| import { loadConfig } from "../../config/config.js"; |
| import { |
| clearApnsRegistrationIfCurrent, |
| loadApnsRegistration, |
| normalizeApnsEnvironment, |
| resolveApnsAuthConfigFromEnv, |
| resolveApnsRelayConfigFromEnv, |
| sendApnsAlert, |
| shouldClearStoredApnsRegistration, |
| } from "../../infra/push-apns.js"; |
| import { ErrorCodes, errorShape, validatePushTestParams } from "../protocol/index.js"; |
| import { respondInvalidParams, respondUnavailableOnThrow } from "./nodes.helpers.js"; |
| import type { GatewayRequestHandlers } from "./types.js"; |
|
|
| function normalizeOptionalString(value: unknown): string | undefined { |
| if (typeof value !== "string") { |
| return undefined; |
| } |
| const trimmed = value.trim(); |
| return trimmed.length > 0 ? trimmed : undefined; |
| } |
|
|
| export const pushHandlers: GatewayRequestHandlers = { |
| "push.test": async ({ params, respond }) => { |
| if (!validatePushTestParams(params)) { |
| respondInvalidParams({ |
| respond, |
| method: "push.test", |
| validator: validatePushTestParams, |
| }); |
| return; |
| } |
|
|
| const nodeId = String(params.nodeId ?? "").trim(); |
| if (!nodeId) { |
| respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId required")); |
| return; |
| } |
|
|
| const title = normalizeOptionalString(params.title) ?? "OpenClaw"; |
| const body = normalizeOptionalString(params.body) ?? `Push test for node ${nodeId}`; |
|
|
| await respondUnavailableOnThrow(respond, async () => { |
| const registration = await loadApnsRegistration(nodeId); |
| if (!registration) { |
| respond( |
| false, |
| undefined, |
| errorShape( |
| ErrorCodes.INVALID_REQUEST, |
| `node ${nodeId} has no APNs registration (connect iOS node first)`, |
| ), |
| ); |
| return; |
| } |
|
|
| const overrideEnvironment = normalizeApnsEnvironment(params.environment); |
| const result = |
| registration.transport === "direct" |
| ? await (async () => { |
| const auth = await resolveApnsAuthConfigFromEnv(process.env); |
| if (!auth.ok) { |
| respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, auth.error)); |
| return null; |
| } |
| return await sendApnsAlert({ |
| registration: { |
| ...registration, |
| environment: overrideEnvironment ?? registration.environment, |
| }, |
| nodeId, |
| title, |
| body, |
| auth: auth.value, |
| }); |
| })() |
| : await (async () => { |
| const relay = resolveApnsRelayConfigFromEnv(process.env, loadConfig().gateway); |
| if (!relay.ok) { |
| respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, relay.error)); |
| return null; |
| } |
| return await sendApnsAlert({ |
| registration, |
| nodeId, |
| title, |
| body, |
| relayConfig: relay.value, |
| }); |
| })(); |
| if (!result) { |
| return; |
| } |
| if ( |
| shouldClearStoredApnsRegistration({ |
| registration, |
| result, |
| overrideEnvironment, |
| }) |
| ) { |
| await clearApnsRegistrationIfCurrent({ |
| nodeId, |
| registration, |
| }); |
| } |
| respond(true, result, undefined); |
| }); |
| }, |
| }; |
|
|