

















@@ -15,6 +15,7 @@ import { formatErrorMessage } from "./errors.js";
1515import { normalizeHostname } from "./net/hostname.js";
16161717type ApnsRelayPushType = "alert" | "background";
18+type ApnsRelayEnvironment = "production" | "sandbox";
18191920/** Resolved APNs relay endpoint and client timeout for gateway-originated sends. */
2021export type ApnsRelayConfig = {
@@ -36,7 +37,7 @@ export type ApnsRelayPushResponse = {
3637status: number;
3738apnsId?: string;
3839reason?: string;
39-environment: "production";
40+environment?: ApnsRelayEnvironment;
4041tokenSuffix?: string;
4142};
4243@@ -56,6 +57,7 @@ export type ApnsRelayRequestSender = (params: {
56575758/** Hosted APNs relay origin used only when registrations prove they were minted there. */
5859export const DEFAULT_APNS_RELAY_BASE_URL = "https://ios-push-relay.openclaw.ai";
60+export const DEFAULT_APNS_SANDBOX_RELAY_BASE_URL = "https://ios-push-relay-sandbox.openclaw.ai";
5961const DEFAULT_APNS_RELAY_TIMEOUT_MS = 10_000;
6062const GATEWAY_DEVICE_ID_HEADER = "x-openclaw-gateway-device-id";
6163const GATEWAY_SIGNATURE_HEADER = "x-openclaw-gateway-signature";
@@ -101,6 +103,14 @@ function parseReason(value: unknown): string | undefined {
101103return typeof value === "string" ? normalizeOptionalString(value) : undefined;
102104}
103105106+function parseRelayEnvironment(value: unknown): ApnsRelayEnvironment | undefined {
107+const normalized = typeof value === "string" ? normalizeLowercaseStringOrEmpty(value) : "";
108+if (normalized === "sandbox" || normalized === "production") {
109+return normalized;
110+}
111+return undefined;
112+}
113+104114/** Validate and canonicalize an APNs relay base URL for config and registration origins. */
105115export function normalizeApnsRelayBaseUrl(
106116baseUrl: string,
@@ -169,11 +179,13 @@ export function resolveApnsRelayConfigFromEnv(
169179};
170180}
171181172-const baseUrl =
173-explicitBaseUrl ??
174-(normalizedRegistrationOrigin?.value === DEFAULT_APNS_RELAY_BASE_URL
182+const hostedRelayBaseUrl =
183+normalizedRegistrationOrigin?.value === DEFAULT_APNS_RELAY_BASE_URL
175184 ? DEFAULT_APNS_RELAY_BASE_URL
176- : undefined);
185+ : normalizedRegistrationOrigin?.value === DEFAULT_APNS_SANDBOX_RELAY_BASE_URL
186+ ? DEFAULT_APNS_SANDBOX_RELAY_BASE_URL
187+ : undefined;
188+const baseUrl = explicitBaseUrl ?? hostedRelayBaseUrl;
177189const baseUrlSource = envBaseUrl
178190 ? "OPENCLAW_APNS_RELAY_BASE_URL"
179191 : configBaseUrl
@@ -245,7 +257,6 @@ async function sendApnsRelayRequest(params: {
245257ok: false,
246258status: response.status,
247259reason: "RelayRedirectNotAllowed",
248-environment: "production",
249260};
250261}
251262@@ -264,12 +275,13 @@ async function sendApnsRelayRequest(params: {
264275typeof body.status === "number" && Number.isFinite(body.status)
265276 ? Math.trunc(body.status)
266277 : response.status;
278+const environment = parseRelayEnvironment(body.environment);
267279return {
268280ok: typeof body.ok === "boolean" ? body.ok : response.ok && status >= 200 && status < 300,
269281 status,
270282apnsId: parseReason(body.apnsId),
271283reason: parseReason(body.reason),
272-environment: "production",
284+...(environment ? { environment } : {}),
273285tokenSuffix: parseReason(body.tokenSuffix),
274286};
275287}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。