import { randomUUID } from "node:crypto"; import { loadConfig } from "../config/config.js"; import { GatewayClient } from "./client.js"; import { PROTOCOL_VERSION } from "./protocol/index.js"; export type CallGatewayOptions = { url?: string; token?: string; password?: string; method: string; params?: unknown; expectFinal?: boolean; timeoutMs?: number; clientName?: string; clientVersion?: string; platform?: string; mode?: string; instanceId?: string; minProtocol?: number; maxProtocol?: number; }; export async function callGateway( opts: CallGatewayOptions, ): Promise { const timeoutMs = opts.timeoutMs ?? 10_000; const config = loadConfig(); const isRemoteMode = config.gateway?.mode === "remote"; const remote = isRemoteMode ? config.gateway.remote : undefined; const url = (typeof opts.url === "string" && opts.url.trim().length > 0 ? opts.url.trim() : undefined) || (typeof remote?.url === "string" && remote.url.trim().length > 0 ? remote.url.trim() : undefined) || "ws://127.0.0.1:18789"; const token = (typeof opts.token === "string" && opts.token.trim().length > 0 ? opts.token.trim() : undefined) || (isRemoteMode ? typeof remote?.token === "string" && remote.token.trim().length > 0 ? remote.token.trim() : undefined : process.env.CLAWDIS_GATEWAY_TOKEN?.trim() || (typeof config.gateway?.auth?.token === "string" && config.gateway.auth.token.trim().length > 0 ? config.gateway.auth.token.trim() : undefined)); const password = (typeof opts.password === "string" && opts.password.trim().length > 0 ? opts.password.trim() : undefined) || process.env.CLAWDIS_GATEWAY_PASSWORD || (typeof remote?.password === "string" && remote.password.trim().length > 0 ? remote.password.trim() : undefined); return await new Promise((resolve, reject) => { let settled = false; let ignoreClose = false; const stop = (err?: Error, value?: T) => { if (settled) return; settled = true; clearTimeout(timer); if (err) reject(err); else resolve(value as T); }; const client = new GatewayClient({ url, token, password, instanceId: opts.instanceId ?? randomUUID(), clientName: opts.clientName ?? "cli", clientVersion: opts.clientVersion ?? "dev", platform: opts.platform, mode: opts.mode ?? "cli", minProtocol: opts.minProtocol ?? PROTOCOL_VERSION, maxProtocol: opts.maxProtocol ?? PROTOCOL_VERSION, onHelloOk: async () => { try { const result = await client.request(opts.method, opts.params, { expectFinal: opts.expectFinal, }); ignoreClose = true; stop(undefined, result); client.stop(); } catch (err) { ignoreClose = true; client.stop(); stop(err as Error); } }, onClose: (code, reason) => { if (settled || ignoreClose) return; stop(new Error(`gateway closed (${code}): ${reason}`)); }, }); const timer = setTimeout(() => { ignoreClose = true; client.stop(); stop(new Error("gateway timeout")); }, timeoutMs); client.start(); }); } export function randomIdempotencyKey() { return randomUUID(); }