import { randomUUID } from "node:crypto"; import type { SystemPresence } from "../infra/system-presence.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; import { GatewayClient } from "./client.js"; export type GatewayProbeAuth = { token?: string; password?: string; }; export type GatewayProbeClose = { code: number; reason: string; hint?: string; }; export type GatewayProbeResult = { ok: boolean; url: string; connectLatencyMs: number | null; error: string | null; close: GatewayProbeClose | null; health: unknown; status: unknown; presence: SystemPresence[] | null; configSnapshot: unknown; }; function formatError(err: unknown): string { if (err instanceof Error) return err.message; return String(err); } export async function probeGateway(opts: { url: string; auth?: GatewayProbeAuth; timeoutMs: number; }): Promise { const startedAt = Date.now(); const instanceId = randomUUID(); let connectLatencyMs: number | null = null; let connectError: string | null = null; let close: GatewayProbeClose | null = null; return await new Promise((resolve) => { let settled = false; const settle = (result: Omit) => { if (settled) return; settled = true; clearTimeout(timer); client.stop(); resolve({ url: opts.url, ...result }); }; const client = new GatewayClient({ url: opts.url, token: opts.auth?.token, password: opts.auth?.password, clientName: GATEWAY_CLIENT_NAMES.CLI, clientVersion: "dev", mode: GATEWAY_CLIENT_MODES.PROBE, instanceId, onConnectError: (err) => { connectError = formatError(err); }, onClose: (code, reason) => { close = { code, reason }; }, onHelloOk: async () => { connectLatencyMs = Date.now() - startedAt; try { const [health, status, presence, configSnapshot] = await Promise.all([ client.request("health"), client.request("status"), client.request("system-presence"), client.request("config.get", {}), ]); settle({ ok: true, connectLatencyMs, error: null, close, health, status, presence: Array.isArray(presence) ? (presence as SystemPresence[]) : null, configSnapshot, }); } catch (err) { settle({ ok: false, connectLatencyMs, error: formatError(err), close, health: null, status: null, presence: null, configSnapshot: null, }); } }, }); const timer = setTimeout( () => { settle({ ok: false, connectLatencyMs, error: connectError ? `connect failed: ${connectError}` : "timeout", close, health: null, status: null, presence: null, configSnapshot: null, }); }, Math.max(250, opts.timeoutMs), ); client.start(); }); }