import { composeEndpoints, defineApiEndpoints, type ExtractApiEndpoints, type UnionToIntersection, } from "../factory"; import type { HeadscaleApiInterface } from "../index"; import apiKeyEndpoints from "./api-keys"; import nodeEndpoints from "./nodes"; import policyEndpoints from "./policy"; import preAuthKeyEndpoints from "./pre-auth-keys"; import userEndpoints from "./users"; interface HealthcheckEndpoint { /** * Checks if the Headscale instance is healthy. * * @returns A boolean indicating if the instance is healthy. */ isHealthy(): Promise; } const healthcheckEndpoint = defineApiEndpoints((client, apiKey) => ({ isHealthy: async () => { try { const res = await client.rawFetch("/health", { method: "GET", headers: { // This doesn't really matter Authorization: `Bearer ${apiKey}`, }, }); return res.statusCode === 200; } catch { return false; } }, })); /** * A constant list of all endpoint groups. * Add new endpoint groups here. */ export const endpointSets = [ apiKeyEndpoints, healthcheckEndpoint, nodeEndpoints, policyEndpoints, preAuthKeyEndpoints, userEndpoints, ] as const; /** * All of the available API methods when interacting with Headscale's API. * We have wrapped each operation with nice methods and parameters to make it * easier to do integration testing by spinning up an actual Headscale instance * and calling these methods against it. * * We also have the benefit of supporting multiple Headscale versions by * passing in different internal implementations based on the OpenAPI spec. */ export type RuntimeApiClient = UnionToIntersection< ExtractApiEndpoints<(typeof endpointSets)[number]> >; /** * Composes all endpoint groups into a single runtime API client. * * @param client - The client helpers for making API requests. * @param apiKey - The API key for authentication. * @returns A fully composed runtime API client. */ export default (client: HeadscaleApiInterface["clientHelpers"], apiKey: string) => composeEndpoints(endpointSets, client, apiKey);