diff --git a/src/gateway/probe.test.ts b/src/gateway/probe.test.ts index 4a2374e17cb..01c69be5199 100644 --- a/src/gateway/probe.test.ts +++ b/src/gateway/probe.test.ts @@ -40,9 +40,15 @@ vi.mock("./client.js", () => ({ GatewayClient: MockGatewayClient, })); -const { probeGateway } = await import("./probe.js"); +const { clampProbeTimeoutMs, probeGateway } = await import("./probe.js"); describe("probeGateway", () => { + it("clamps probe timeout to timer-safe bounds", () => { + expect(clampProbeTimeoutMs(1)).toBe(250); + expect(clampProbeTimeoutMs(2_000)).toBe(2_000); + expect(clampProbeTimeoutMs(3_000_000_000)).toBe(2_147_483_647); + }); + it("connects with operator.read scope", async () => { const result = await probeGateway({ url: "ws://127.0.0.1:18789", diff --git a/src/gateway/probe.ts b/src/gateway/probe.ts index bbd36639b78..b285c395c3d 100644 --- a/src/gateway/probe.ts +++ b/src/gateway/probe.ts @@ -29,6 +29,13 @@ export type GatewayProbeResult = { configSnapshot: unknown; }; +export const MIN_PROBE_TIMEOUT_MS = 250; +export const MAX_TIMER_DELAY_MS = 2_147_483_647; + +export function clampProbeTimeoutMs(timeoutMs: number): number { + return Math.min(MAX_TIMER_DELAY_MS, Math.max(MIN_PROBE_TIMEOUT_MS, timeoutMs)); +} + export async function probeGateway(opts: { url: string; auth?: GatewayProbeAuth; @@ -144,21 +151,18 @@ export async function probeGateway(opts: { }, }); - 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), - ); + const timer = setTimeout(() => { + settle({ + ok: false, + connectLatencyMs, + error: connectError ? `connect failed: ${connectError}` : "timeout", + close, + health: null, + status: null, + presence: null, + configSnapshot: null, + }); + }, clampProbeTimeoutMs(opts.timeoutMs)); client.start(); });