fix: route APNs delivery per-token by registered environment

Issue: after defaulting APNs delivery to production (#2381), development
builds installed from Xcode stopped receiving notifications entirely:
their sandbox device tokens were sent to the production APNs endpoint,
rejected as BadDeviceToken, and dropped as dead.

Fix: the iOS shell reads the aps-environment entitlement from the
embedded provisioning profile and exposes it to the web layer as a
document-start user script (added in capacitorDidLoad, since Capacitor
replaces the userContentController after webViewConfiguration(for:)).
Token registration reports the environment to the server, which stores
it per token and groups delivery by environment for both relay and
direct APNs sends. OPENCHAMBER_APNS_ENVIRONMENT remains as an explicit
override forcing every send to one environment.

TestFlight/App Store builds and older clients without the field default
to production, preserving released behavior; the relay already accepts
env per send request.
This commit is contained in:
Bohdan Triapitsyn
2026-07-25 01:18:41 +03:00
parent fe0ef0d1da
commit 9f1bd0dfa0
9 changed files with 204 additions and 54 deletions
@@ -162,8 +162,11 @@ export const registerNotificationRoutes = (app, dependencies) => {
}
const platform = req.body?.platform === 'android' ? 'android' : 'ios';
// APNs environment the token belongs to: Xcode/dev-signed installs report 'sandbox',
// TestFlight/App Store report 'production'. Absent (older clients, Android) → production.
const environment = req.body?.environment === 'sandbox' ? 'sandbox' : 'production';
if (typeof addOrUpdateApnsToken === 'function') {
await addOrUpdateApnsToken(uiToken, deviceToken, req.headers['user-agent'], platform);
await addOrUpdateApnsToken(uiToken, deviceToken, req.headers['user-agent'], platform, environment);
}
return res.json({ ok: true });
});