diff --git a/packages/gateway-client/src/timeouts.test.ts b/packages/gateway-client/src/timeouts.test.ts index 20166596a97..74c198f4466 100644 --- a/packages/gateway-client/src/timeouts.test.ts +++ b/packages/gateway-client/src/timeouts.test.ts @@ -55,6 +55,19 @@ describe("gateway client handshake timeouts", () => { ).toBe(MAX_SAFE_TIMEOUT_DELAY_MS); }); + it("accepts existing strict timeout env integer forms", () => { + expect( + getPreauthHandshakeTimeoutMsFromEnv({ + OPENCLAW_HANDSHAKE_TIMEOUT_MS: " +75000 ", + }), + ).toBe(75_000); + expect( + getConnectChallengeTimeoutMsFromEnv({ + OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS: " 015000 ", + }), + ).toBe(15_000); + }); + it("caps connect challenge timeout env and explicit values to the safe timer range", () => { expect( getConnectChallengeTimeoutMsFromEnv({ diff --git a/packages/gateway-client/src/timeouts.ts b/packages/gateway-client/src/timeouts.ts index 72d1f9d904e..81fdf685901 100644 --- a/packages/gateway-client/src/timeouts.ts +++ b/packages/gateway-client/src/timeouts.ts @@ -1,9 +1,10 @@ function parseStrictPositiveInteger(value: string): number | undefined { - if (!/^[1-9]\d*$/u.test(value)) { + const trimmed = value.trim(); + if (!/^\+?\d+$/u.test(trimmed)) { return undefined; } - const parsed = Number(value); - return Number.isSafeInteger(parsed) ? parsed : undefined; + const parsed = Number(trimmed); + return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined; } export const MAX_SAFE_TIMEOUT_DELAY_MS = 2_147_483_647; diff --git a/src/gateway/handshake-timeouts.test.ts b/src/gateway/handshake-timeouts.test.ts index a95843c6de2..0257b0c96ae 100644 --- a/src/gateway/handshake-timeouts.test.ts +++ b/src/gateway/handshake-timeouts.test.ts @@ -37,6 +37,13 @@ describe("gateway handshake timeouts", () => { VITEST: "1", }), ).toBe(20); + expect( + getPreauthHandshakeTimeoutMsFromEnv({ + OPENCLAW_HANDSHAKE_TIMEOUT_MS: " +75 ", + OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS: "20", + VITEST: "1", + }), + ).toBe(75); }); test("resolves preauth handshake timeout with env over config over default", () => { @@ -126,6 +133,9 @@ describe("gateway handshake timeouts", () => { expect( getConnectChallengeTimeoutMsFromEnv({ OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS: "15000" }), ).toBe(15_000); + expect( + getConnectChallengeTimeoutMsFromEnv({ OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS: " 015000 " }), + ).toBe(15_000); expect( getConnectChallengeTimeoutMsFromEnv({ OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS: "garbage" }), ).toBeUndefined(); diff --git a/src/gateway/handshake-timeouts.ts b/src/gateway/handshake-timeouts.ts index b7e46fd42f8..1bdd53f3ff7 100644 --- a/src/gateway/handshake-timeouts.ts +++ b/src/gateway/handshake-timeouts.ts @@ -1,89 +1,10 @@ -import { parseStrictPositiveInteger } from "../infra/parse-finite-number.js"; -import { resolveSafeTimeoutDelayMs } from "../utils/timer-delay.js"; - -export const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS = 15_000; -export const MIN_CONNECT_CHALLENGE_TIMEOUT_MS = 250; -export const MAX_CONNECT_CHALLENGE_TIMEOUT_MS = DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS; - -export function clampConnectChallengeTimeoutMs( - timeoutMs: number, - maxTimeoutMs = MAX_CONNECT_CHALLENGE_TIMEOUT_MS, -): number { - return Math.max( - MIN_CONNECT_CHALLENGE_TIMEOUT_MS, - Math.min(Math.max(MIN_CONNECT_CHALLENGE_TIMEOUT_MS, maxTimeoutMs), timeoutMs), - ); -} - -export function getConnectChallengeTimeoutMsFromEnv( - env: NodeJS.ProcessEnv = process.env, -): number | undefined { - const raw = env.OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS; - if (raw) { - const parsed = parseStrictPositiveInteger(raw); - if (parsed !== undefined) { - return resolveSafeTimeoutDelayMs(parsed); - } - } - return undefined; -} - -function normalizePositiveTimeoutMs(timeoutMs: unknown): number | undefined { - return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 - ? resolveSafeTimeoutDelayMs(timeoutMs) - : undefined; -} - -export function resolveConnectChallengeTimeoutMs( - timeoutMs?: number | null, - params?: { - env?: NodeJS.ProcessEnv; - configuredTimeoutMs?: number | null; - }, -): number { - const configuredPreauthTimeoutMs = resolvePreauthHandshakeTimeoutMs({ - env: params?.env, - configuredTimeoutMs: params?.configuredTimeoutMs, - }); - const maxTimeoutMs = Math.max(DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, configuredPreauthTimeoutMs); - if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) { - return clampConnectChallengeTimeoutMs(timeoutMs, maxTimeoutMs); - } - const envOverride = getConnectChallengeTimeoutMsFromEnv(params?.env); - if (envOverride !== undefined) { - return clampConnectChallengeTimeoutMs(envOverride, Math.max(maxTimeoutMs, envOverride)); - } - return clampConnectChallengeTimeoutMs(configuredPreauthTimeoutMs, maxTimeoutMs); -} - -export function getPreauthHandshakeTimeoutMsFromEnv(env: NodeJS.ProcessEnv = process.env): number { - const configuredTimeout = - env.OPENCLAW_HANDSHAKE_TIMEOUT_MS || (env.VITEST && env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS); - if (configuredTimeout) { - const parsed = parseStrictPositiveInteger(configuredTimeout); - if (parsed !== undefined) { - return resolveSafeTimeoutDelayMs(parsed); - } - } - return DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS; -} - -export function resolvePreauthHandshakeTimeoutMs(params?: { - env?: NodeJS.ProcessEnv; - configuredTimeoutMs?: number | null; -}): number { - const env = params?.env ?? process.env; - const configuredTimeout = - env.OPENCLAW_HANDSHAKE_TIMEOUT_MS || (env.VITEST && env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS); - if (configuredTimeout) { - const parsed = parseStrictPositiveInteger(configuredTimeout); - if (parsed !== undefined) { - return resolveSafeTimeoutDelayMs(parsed); - } - } - const configured = normalizePositiveTimeoutMs(params?.configuredTimeoutMs); - if (configured !== undefined) { - return configured; - } - return DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS; -} +export { + clampConnectChallengeTimeoutMs, + DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, + getConnectChallengeTimeoutMsFromEnv, + getPreauthHandshakeTimeoutMsFromEnv, + MAX_CONNECT_CHALLENGE_TIMEOUT_MS, + MIN_CONNECT_CHALLENGE_TIMEOUT_MS, + resolveConnectChallengeTimeoutMs, + resolvePreauthHandshakeTimeoutMs, +} from "../../packages/gateway-client/src/timeouts.js";