From fbc5529fbfbfe17c0d2a41ce63ccc7d5feda5776 Mon Sep 17 00:00:00 2001 From: wahaha1223 <0668001153@xydigit.com> Date: Thu, 16 Jul 2026 13:37:37 +0800 Subject: [PATCH] fix(push): parse APNs relay timeout as strict decimal (#107883) Co-authored-by: Peter Steinberger --- src/infra/push-apns.relay.test.ts | 37 +++++++++++++++++++++++++++++++ src/infra/push-apns.relay.ts | 7 ++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/infra/push-apns.relay.test.ts b/src/infra/push-apns.relay.test.ts index b220e240450b..e29ec7a82127 100644 --- a/src/infra/push-apns.relay.test.ts +++ b/src/infra/push-apns.relay.test.ts @@ -107,6 +107,43 @@ describe("push-apns.relay", () => { }); }); + it.each(["0x1000", "2e4", "2500ms"])( + "falls back for non-decimal env timeout %s", + (timeoutMs) => { + const resolved = resolveApnsRelayConfigFromEnv({ + OPENCLAW_APNS_RELAY_BASE_URL: "https://relay.example.com", + OPENCLAW_APNS_RELAY_TIMEOUT_MS: timeoutMs, + } as NodeJS.ProcessEnv); + + expectRelayConfig(resolved, { + baseUrl: "https://relay.example.com", + timeoutMs: 10_000, + }); + }, + ); + + it("retains numeric timeout config values", () => { + const resolved = resolveApnsRelayConfigFromEnv( + { + OPENCLAW_APNS_RELAY_BASE_URL: "https://relay.example.com", + } as NodeJS.ProcessEnv, + { + push: { + apns: { + relay: { + timeoutMs: 2500, + }, + }, + }, + }, + ); + + expectRelayConfig(resolved, { + baseUrl: "https://relay.example.com", + timeoutMs: 2500, + }); + }); + it("allows loopback http URLs for alternate truthy env values", () => { const resolved = resolveApnsRelayConfigFromEnv({ OPENCLAW_APNS_RELAY_BASE_URL: "http://[::1]:8787", diff --git a/src/infra/push-apns.relay.ts b/src/infra/push-apns.relay.ts index 223b3fe0c810..bdb4e4de2e8c 100644 --- a/src/infra/push-apns.relay.ts +++ b/src/infra/push-apns.relay.ts @@ -1,6 +1,9 @@ // Sends APNs notifications through the configured relay endpoint. import { URL } from "node:url"; -import { resolveTimerTimeoutMs } from "@openclaw/normalization-core/number-coercion"; +import { + parseStrictPositiveInteger, + resolveTimerTimeoutMs, +} from "@openclaw/normalization-core/number-coercion"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -83,7 +86,7 @@ function normalizeTimeoutMs(value: string | number | undefined): number { if (raw === undefined || raw === "") { return DEFAULT_APNS_RELAY_TIMEOUT_MS; } - const parsed = Number(raw); + const parsed = typeof raw === "number" ? raw : parseStrictPositiveInteger(raw); return resolveTimerTimeoutMs(parsed, DEFAULT_APNS_RELAY_TIMEOUT_MS, 1000); }