diff --git a/packages/session-persistence/session-persistence/src/coordinator.ts b/packages/session-persistence/session-persistence/src/coordinator.ts index beb5fca483..7dc0c9a0ba 100644 --- a/packages/session-persistence/session-persistence/src/coordinator.ts +++ b/packages/session-persistence/session-persistence/src/coordinator.ts @@ -125,6 +125,11 @@ function assertSupportedEvents(events: readonly SessionEvent[], id: SessionId): if (legacy !== undefined) { throw new Error(`session "${id}" contains unsupported legacy request/header-delta event at seq ${legacy.seq}`) } + const legacyModeType: string = 'mode/set' + const legacyMode = events.find(event => event.type === legacyModeType) + if (legacyMode !== undefined) { + throw new Error(`session "${id}" contains unsupported legacy mode/set event at seq ${legacyMode.seq}`) + } const fallback = events.find(event => event.type === 'request/header' && (event.data as { reason?: string }).reason === 'fallback') if (fallback !== undefined) { diff --git a/packages/session-persistence/session-persistence/tests/persistence.spec.ts b/packages/session-persistence/session-persistence/tests/persistence.spec.ts index e083ac3543..510ae38136 100644 --- a/packages/session-persistence/session-persistence/tests/persistence.spec.ts +++ b/packages/session-persistence/session-persistence/tests/persistence.spec.ts @@ -22,6 +22,16 @@ function legacyHeaderDelta(seq = 0): SessionEvent { } as unknown as SessionEvent } +/** An unsupported named-mode fixture emulating an untyped producer. */ +function legacyModeSet(seq = 0): SessionEvent { + return { + type: 'mode/set', + seq, + time: 1, + data: { mode: 'plan' }, + } as unknown as SessionEvent +} + /** An obsolete full-header reason fixture from the removed delta codec. */ function legacyFallbackHeader(seq = 0): SessionEvent { return { @@ -510,6 +520,19 @@ describe('SessionPersistence service registration', () => { await fiber.dispose() }) + it('rejects a stored legacy named-mode event during load', async () => { + const id = SessionId('legacy-mode-load') + const m = meta(id, '/legacy') + const store: MemoryStore = new Map([[id, { meta: m, events: [legacyModeSet()] }]]) + const ctx = new Context() + await ctx.plugin(SessionStore) + const fiber = await ctx.plugin(MemoryPersistence, { store }) + + await expect(ctx.sessionPersistence.load(id)) + .rejects.toThrow('unsupported legacy mode/set event at seq 0') + await fiber.dispose() + }) + it('retires all coordinator bookkeeping for disposed sessions', async () => { const ctx = new Context() await ctx.plugin(SessionStore)