/** * Token acquisition for the Homebridge UI log client. * * {@link acquireToken} turns a {@link LogClientCredentials} discriminated union into a raw bearer token by talking to the homebridge-config-ui-x authentication API. Each * credential arm maps to one of the server's authentication paths: a pre-acquired `token` is returned verbatim with no network call, a `password` arm posts to `POST * /api/auth/login` (carrying an optional one-time passcode), and `noauth` posts to `POST /api/auth/noauth`, which the server honors only when its UI is configured with * `auth: "none"`. * * The module's central concern beyond "get a token" is failure classification. The socket's reconnect loop re-authenticates on every reconnect, so it must be able * to tell a transient fault (the server is briefly down or returned a 5xx) from a permanent one (the credentials are wrong, an OTP is required, or noauth is disabled). * A transient fault should be retried with backoff; a permanent one must fail the reconnect fast so the user gets an actionable error rather than an endless retry loop * against credentials that will never work. {@link acquireToken} therefore rejects with a {@link LogAuthError} whose `kind` distinguishes `"permanent"` from * `"transient"`, and the reconnect's `shouldRetry` predicate vetoes a retry on the permanent kind via {@link isPermanentAuthError}. * * The `fetch` implementation is injected (defaulting to the global `fetch`) so the whole module is exercised in tests without a live server. * * @module */ import type { EndpointTarget } from "./endpoints.ts"; import type { LogClientCredentials } from "./types.ts"; /** * The classification of an authentication failure, used by the reconnect loop to decide whether to retry. * * - `"permanent"` - the credentials are wrong, an OTP is required, or noauth is disabled. Retrying with the same credentials will keep failing, so the reconnect loop * vetoes a retry and surfaces the error to the user. * - `"transient"` - a network fault or a server-side 5xx/429. The condition may clear on its own, so the reconnect loop retries with backoff. * * @category Log Client */ export type LogAuthErrorKind = "permanent" | "transient"; /** * Options accepted by {@link LogAuthError}'s constructor. * * @property cause - The underlying cause (a network error, or the HTTP response context), attached for diagnostics. * @property kind - The failure classification. See {@link LogAuthErrorKind}. * * @category Log Client */ export interface LogAuthErrorOptions { readonly cause?: unknown; readonly kind: LogAuthErrorKind; } /** * The error thrown by {@link acquireToken} when authentication fails. * * Carries a {@link LogAuthErrorKind} tag so a consumer (specifically the socket's reconnect `shouldRetry` predicate) can distinguish a permanent credential * problem from a transient network/server fault without parsing the message text. The message itself is already actionable - it names the failing path and the reason - * so it can be surfaced to the user directly. * * @category Log Client */ export declare class LogAuthError extends Error { /** * The failure classification. `"permanent"` failures must not be retried; `"transient"` failures may be. */ readonly kind: LogAuthErrorKind; /** * Construct a new authentication error. * * @param message - A human-readable, actionable description of the failure. * @param options - The classification and optional underlying cause. See {@link LogAuthErrorOptions}. */ constructor(message: string, options: LogAuthErrorOptions); } /** * Type guard: returns `true` when `error` is a {@link LogAuthError} classified `"permanent"`. * * The reconnect loop's `shouldRetry` predicate consults this to veto a retry the instant a permanent credential failure surfaces, so a wrong password or a missing OTP * fails the reconnect fast rather than looping forever against credentials that cannot succeed. * * @param error - The value to test. * * @returns `true` when `error` is a permanent authentication failure. * * @category Log Client */ export declare function isPermanentAuthError(error: unknown): boolean; /** * Options accepted by {@link acquireToken}: the connection target plus an injectable `fetch` seam. * * @property fetch - The fetch implementation to use. Defaults to the global `fetch`. Injected so the auth flow is testable without a live server. * @property host - The hostname or IP of the homebridge-config-ui-x server. * @property port - The TCP port the server listens on. * @property tls - When `true`, use the secure (`https`) scheme; when `false` or omitted, plaintext (`http`). * * @category Log Client */ export interface AcquireTokenOptions extends EndpointTarget { readonly fetch?: typeof fetch; } /** * Acquire a raw bearer token for the homebridge-config-ui-x API from the supplied credentials. * * Dispatches on the credential discriminated union: * * - `token` - returns the pre-acquired token verbatim, with no network call. A static token that has since expired is not detected here; the failure surfaces later when * the socket handshake is rejected. * - `password` - posts `{ username, password, otp? }` to `POST /api/auth/login`. * - `noauth` - posts to `POST /api/auth/noauth`, which the server honors only when its UI is configured with `auth: "none"`. * * On failure it rejects with a {@link LogAuthError} whose `kind` classifies the failure as permanent (wrong credentials, OTP required, noauth disabled, broken success * body) or transient (network fault, 5xx, 429), so the reconnect loop can fail fast on permanent failures and retry transient ones. * * @param credentials - The credentials to authenticate with. See {@link LogClientCredentials}. * @param options - The connection target and the injectable `fetch` seam. See {@link AcquireTokenOptions}. * * @returns A promise resolving to the raw bearer token (the bare JWT, with no `Bearer` prefix). * * @throws {@link LogAuthError} on any authentication failure, classified permanent or transient. * * @category Log Client */ export declare function acquireToken(credentials: LogClientCredentials, options: AcquireTokenOptions): Promise; //# sourceMappingURL=auth.d.ts.map