fix: default APNs delivery to production (#2381)
Issue: TestFlight iOS clients register production APNs device tokens, but notifications from a default OpenChamber server are not delivered. Expected behavior: the released iOS app receives notifications without requiring users to configure an APNs environment, while development builds can explicitly select sandbox delivery. Root cause: both relay and direct APNs delivery defaulted to the sandbox environment, so production TestFlight tokens were sent to the wrong APNs endpoint. Fix: default both delivery modes to production, preserve OPENCHAMBER_APNS_ENVIRONMENT=sandbox as an explicit development override, and update tests and documentation.
This commit is contained in:
@@ -69,6 +69,7 @@ afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
delete process.env.OPENCHAMBER_PUSH_RELAY_URL;
|
||||
delete process.env.OPENCHAMBER_PUSH_RELAY_DISABLED;
|
||||
delete process.env.OPENCHAMBER_APNS_ENVIRONMENT;
|
||||
});
|
||||
|
||||
describe('apns runtime relay mode (default)', () => {
|
||||
@@ -116,6 +117,7 @@ describe('apns runtime relay mode (default)', () => {
|
||||
expect(sent.title).toBe('Agent response is ready');
|
||||
expect(sent.body).toBe('My session');
|
||||
expect(sent.badge).toBe(3);
|
||||
expect(sent.env).toBe('production');
|
||||
expect(sent.data).toEqual({ sessionId: 'sess1' });
|
||||
expect(sent.publicKeyJwk).toMatchObject({ kty: 'EC', crv: 'P-256' });
|
||||
const sendMessage = `${sent.ts}.${[...sent.tokens].sort().join(',')}.${sent.title}`;
|
||||
@@ -144,6 +146,20 @@ describe('apns runtime relay mode (default)', () => {
|
||||
expect(deps.writeSettingsToDisk).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('honors an explicit sandbox environment', async () => {
|
||||
const fetchMock = vi.fn(async () => jsonResponse({ ok: true, results: [] }));
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
process.env.OPENCHAMBER_PUSH_RELAY_URL = 'https://relay.test/v1/push/send';
|
||||
process.env.OPENCHAMBER_APNS_ENVIRONMENT = 'sandbox';
|
||||
|
||||
const runtime = createApnsRuntime(makeDeps());
|
||||
await runtime.addOrUpdateApnsToken('s1', 'tokenA');
|
||||
await runtime.sendApnsToAllUiSessions({ title: 't', body: 'b' });
|
||||
|
||||
const sent = JSON.parse(fetchMock.mock.calls.find(isSend)[1].body);
|
||||
expect(sent.env).toBe('sandbox');
|
||||
});
|
||||
|
||||
it('no-ops (no relay call) when no tokens are registered', async () => {
|
||||
const fetchMock = vi.fn();
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
@@ -154,6 +170,15 @@ describe('apns runtime relay mode (default)', () => {
|
||||
});
|
||||
|
||||
describe('apns runtime direct fallback (relay disabled)', () => {
|
||||
it('defaults direct APNs configuration to production', async () => {
|
||||
const { environment: _environment, ...configWithoutEnvironment } = APNS_CONFIG;
|
||||
const runtime = createApnsRuntime(
|
||||
makeDeps({ readSettingsFromDiskMigrated: vi.fn(async () => ({ apnsConfig: configWithoutEnvironment })) }),
|
||||
);
|
||||
|
||||
await expect(runtime.resolveApnsConfig()).resolves.toMatchObject({ environment: 'production' });
|
||||
});
|
||||
|
||||
it('signs an ES256 JWT and sends over http2 when relay is disabled', async () => {
|
||||
process.env.OPENCHAMBER_PUSH_RELAY_DISABLED = 'true';
|
||||
const targeted = [];
|
||||
|
||||
Reference in New Issue
Block a user