diff --git a/infra/relay/src/agentActivity/ApnsDeliveries.test.ts b/infra/relay/src/agentActivity/ApnsDeliveries.test.ts index 0d41bfce781a..75b821bcfa7d 100644 --- a/infra/relay/src/agentActivity/ApnsDeliveries.test.ts +++ b/infra/relay/src/agentActivity/ApnsDeliveries.test.ts @@ -486,6 +486,9 @@ describe("ApnsDeliveries", () => { Effect.provide( makeLayer({ attempts, + currentTargets: [ + { ...target, bundle_id: "com.t3tools.t3code.preview", aps_environment: "sandbox" }, + ], config: signingConfig, execute, }), @@ -1972,3 +1975,76 @@ describe("fast completion delivery", () => { }).pipe(Effect.provide(makeLayer({ attempts: [], queuedJobs }))); }); }); + +describe("signed APNs registration metadata", () => { + for (const kind of ["live_activity_update", "push_notification"] as const) { + for (const changed of ["bundle", "environment", "legacy"] as const) { + it.effect(`routes ${kind} using current registration with ${changed} job metadata`, () => { + const attempts: DeliveryAttempts.DeliveryAttemptInput[] = []; + const requests: HttpClientRequest.HttpClientRequest[] = []; + const payload = makeApnsDeliveryJobPayload({ + kind, + userId: target.user_id, + deviceId: target.device_id, + token: "unchanged-token", + ...(changed === "legacy" + ? {} + : { bundleId: "com.t3tools.t3code.dev", apsEnvironment: "sandbox" as const }), + aggregate: kind === "live_activity_update" ? aggregate : null, + ...(kind === "push_notification" + ? { + notification: { + title: "Thread", + body: "Input: Project", + environmentId: "env", + threadId: "thread", + deepLink: "/", + }, + } + : {}), + createdAt: "1970-01-01T00:00:00.000Z", + expiresAt: "1970-01-01T00:10:00.000Z", + jobId: `metadata-${kind}-${changed}`, + }); + const signed = signApnsDeliveryJob({ + secret: config.apnsDeliveryJobSigningSecret, + payload, + }); + return Effect.gen(function* () { + const deliveries = yield* ApnsDeliveries.ApnsDeliveries; + const result = yield* deliveries.processSignedJob(signed); + expect(result.ok).toBe(true); + expect(requests).toHaveLength(1); + expect(requests[0]?.url).toBe( + `${changed === "environment" ? "https://api.push.apple.com" : "https://api.sandbox.push.apple.com"}/3/device/unchanged-token`, + ); + expect(requests[0]?.headers["apns-topic"]).toBe( + `${changed === "bundle" ? "com.t3tools.t3code.preview" : "com.t3tools.t3code.dev"}${kind === "live_activity_update" ? ".push-type.liveactivity" : ""}`, + ); + }).pipe( + Effect.provide( + makeLayer({ + attempts, + config: signingConfig, + currentTargets: [ + { + ...target, + push_token: "unchanged-token", + activity_push_token: "unchanged-token", + bundle_id: + changed === "bundle" ? "com.t3tools.t3code.preview" : "com.t3tools.t3code.dev", + aps_environment: changed === "environment" ? "production" : "sandbox", + }, + ], + execute: (request) => + Effect.sync(() => { + requests.push(request); + return HttpClientResponse.fromWeb(request, new Response("", { status: 200 })); + }), + }), + ), + ); + }); + } + } +}); diff --git a/infra/relay/src/agentActivity/ApnsDeliveries.ts b/infra/relay/src/agentActivity/ApnsDeliveries.ts index 45620ebbfa8b..db01d1e7880c 100644 --- a/infra/relay/src/agentActivity/ApnsDeliveries.ts +++ b/infra/relay/src/agentActivity/ApnsDeliveries.ts @@ -681,6 +681,7 @@ export const make = Effect.gen(function* () { "relay.delivery.kind": input.kind, ...(input.sourceJobId ? { "relay.delivery.job_id": input.sourceJobId } : {}), }); + let deliveryTarget = input.target; const now = yield* DateTime.now; const aggregate = input.aggregate === null ? null : sanitizeAgentActivityAggregateState(input.aggregate); @@ -722,6 +723,7 @@ export const make = Effect.gen(function* () { }); return staleJobResult({ deviceId: input.target.device_id, kind: input.kind }); } + deliveryTarget = currentTarget; if (alert) { const preferences = parsePreferences(currentTarget.preferences_json); const previousAggregate = parseAggregate(currentTarget.last_aggregate_json); @@ -779,7 +781,7 @@ export const make = Effect.gen(function* () { ); const result = yield* apns .sendLiveActivityRequest({ - credentials: credentialsForTarget(config.apns, input.target), + credentials: credentialsForTarget(config.apns, deliveryTarget), request, issuedAtUnixSeconds: epochSeconds, }) @@ -845,6 +847,7 @@ export const make = Effect.gen(function* () { "relay.delivery.kind": "push_notification", ...(input.sourceJobId ? { "relay.delivery.job_id": input.sourceJobId } : {}), }); + let deliveryTarget = input.target; const now = yield* DateTime.now; const epochSeconds = Math.floor(now.epochMilliseconds / 1_000); const notification = sanitizeApnsNotificationPayload(input.notification); @@ -914,6 +917,7 @@ export const make = Effect.gen(function* () { kind: "push_notification", }); } + deliveryTarget = currentTarget; const preferences = parsePreferences(currentTarget.preferences_json); const alertAllowed = notification.phase !== undefined && notification.updatedAt !== undefined @@ -935,7 +939,7 @@ export const make = Effect.gen(function* () { } const result = yield* apns .sendPushNotificationRequest({ - credentials: credentialsForTarget(config.apns, input.target), + credentials: credentialsForTarget(config.apns, deliveryTarget), request, issuedAtUnixSeconds: epochSeconds, })