crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit 01c28e63d95e239e252fe775e8ce014ebe0f1c72
parent 6a72792b91d0e846a93ffb4ec88336d89ebc36b2
Author: Michael Camilleri <[email protected]>
Date:   Fri, 12 Jun 2026 10:46:17 +0900

Add store-and-forward window for meaningful events

Diffstat:
MWorkers/push-worker.js | 25+++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/Workers/push-worker.js b/Workers/push-worker.js @@ -454,13 +454,20 @@ export class PushRegistry { ? "api.sandbox.push.apple.com" : "api.push.apple.com"; const jwt = await this.providerJWT(); + // "play" presence is the noisiest, least-actionable alert kind: deliver + // it without a sound and at power-considerate priority so a backgrounded + // peer isn't pinged every time someone opens the puzzle. Other alert + // kinds (win/resign/pause) keep the sound and immediate priority. + const presence = !message.background && message.kind === "play"; const alert = {}; if (message.title) alert.title = message.title; if (message.body) alert.body = message.body; + const aps = message.background + ? { "content-available": 1 } + : { alert, "mutable-content": 1 }; + if (!message.background && !presence) aps.sound = "default"; const apnsPayload = { - aps: message.background - ? { "content-available": 1 } - : { alert, sound: "default", "mutable-content": 1 }, + aps, kind: message.kind }; if (message.gameID) apnsPayload.gameID = message.gameID; @@ -471,6 +478,16 @@ export class PushRegistry { // app builds, which the extension handles by falling back to `kind`. if (message.payload) apnsPayload.payload = message.payload; + // "play" presence is ephemeral: deliver now or discard. Other alert kinds + // (win/resign/pause) are one-time meaningful events — give APNs a + // store-and-forward window so a recipient who is offline at send time + // still gets the banner. Background pushes stay at 0; the state they + // nudge converges through CloudKit anyway. + const ephemeral = message.background || message.kind === "play"; + const expiration = ephemeral + ? "0" + : String(Math.floor(Date.now() / 1000) + 4 * 60 * 60); + const response = await fetch(`https://${host}/3/device/${target.token}`, { method: "POST", headers: { @@ -478,7 +495,7 @@ export class PushRegistry { "apns-topic": topic, "apns-push-type": message.background ? "background" : "alert", "apns-priority": message.background ? "5" : "10", - "apns-expiration": "0", + "apns-expiration": expiration, "content-type": "application/json" }, body: JSON.stringify(apnsPayload)