/** * Durable delivery: `alarmStatus` can answer 409 `ERR_ALARM_TRIGGERED_OFFLINE` * with the alarm frame in the body. That is an alarm signal, not a failure — * the client must ring the same takeover and must not render an error. */ import { configureApi, ApiError, OfflineAlarmError, post } from '../src/services/apiClient'; import { alarmStatus } from '../src/services/alarmApi'; const g = globalThis as unknown as { fetch: typeof fetch }; const realFetch = g.fetch; function stub(status: number, body: unknown): void { g.fetch = (async () => ({ ok: status >= 200 && status < 300, status, text: async () => JSON.stringify(body), json: async () => body, })) as unknown as typeof fetch; } beforeEach(() => { configureApi({ baseUrl: 'http://instance.test', token: null, refreshToken: null, onUnauthorized: () => {}, onSessionUpdate: () => {}, }); }); afterEach(() => { g.fetch = realFetch; }); describe('ERR_ALARM_TRIGGERED_OFFLINE', () => { it('is returned as a success-shaped status carrying the frame', async () => { stub(409, { error: { code: 'ERR_ALARM_TRIGGERED_OFFLINE', message: 'alarm fired while offline' }, alarm: { type: 'alarm', alertId: 'alr_1', eventId: 'evt_7', action: 'trigger', message: 'Fire drill', serverTime: '2026-10-19T00:00:00Z', }, }); await expect(alarmStatus('alr_1')).resolves.toEqual({ active: true, action: 'trigger', eventId: 'evt_7', message: 'Fire drill', serverTime: '2026-10-19T00:00:00Z', offlineTrigger: true, }); }); it('accepts the frame at the top level too', async () => { stub(409, { error: { code: 'ERR_ALARM_TRIGGERED_OFFLINE', message: 'late' }, alertId: 'alr_1', eventId: 'evt_8', action: 'trigger', }); await expect(alarmStatus('alr_1')).resolves.toMatchObject({ active: true, eventId: 'evt_8', offlineTrigger: true, }); }); it('does not let the generic HTTP path swallow it', async () => { stub(409, { error: { code: 'ERR_ALARM_TRIGGERED_OFFLINE', message: 'late' }, alarm: { alertId: 'alr_1', eventId: 'evt_9' }, }); await expect(post('alarmStatus', {})).rejects.toBeInstanceOf(OfflineAlarmError); }); it('refuses to ring a 409 that claims the code but carries no frame', async () => { stub(409, { error: { code: 'ERR_ALARM_TRIGGERED_OFFLINE', message: 'late' } }); await expect(alarmStatus('alr_1')).rejects.toBeInstanceOf(OfflineAlarmError); }); it('keeps any other 409 a plain error', async () => { stub(409, { error: { code: 'ERR_ALERT_ALREADY_JOINED', message: 'already joined' } }); const err = await alarmStatus('alr_1').catch(e => e); expect(err).toBeInstanceOf(ApiError); expect(err).not.toBeInstanceOf(OfflineAlarmError); expect(err.code).toBe('ERR_ALERT_ALREADY_JOINED'); }); });