diff --git a/examples/shared/src/inMemoryEventStore.ts b/examples/shared/src/inMemoryEventStore.ts index 604b84d39c..0bae16a62f 100644 --- a/examples/shared/src/inMemoryEventStore.ts +++ b/examples/shared/src/inMemoryEventStore.ts @@ -19,8 +19,7 @@ export class InMemoryEventStore implements EventStore { * Extracts the stream ID from an event ID */ private getStreamIdFromEventId(eventId: string): string { - const parts = eventId.split('_'); - return parts.length > 0 ? parts[0]! : ''; + return this.events.get(eventId)?.streamId ?? ''; } /** @@ -53,10 +52,8 @@ export class InMemoryEventStore implements EventStore { let foundLastEvent = false; - // Sort events by eventId for chronological ordering - const sortedEvents = [...this.events.entries()].toSorted((a, b) => a[0].localeCompare(b[0])); - - for (const [eventId, { streamId: eventStreamId, message }] of sortedEvents) { + // Map iteration preserves insertion order, which is the event chronology. + for (const [eventId, { streamId: eventStreamId, message }] of this.events) { // Only include events from the same stream if (eventStreamId !== streamId) { continue; diff --git a/examples/shared/test/inMemoryEventStore.test.ts b/examples/shared/test/inMemoryEventStore.test.ts new file mode 100644 index 0000000000..dbf5d140df --- /dev/null +++ b/examples/shared/test/inMemoryEventStore.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from 'vitest'; +import type { JSONRPCMessage } from '@modelcontextprotocol/server'; +import { InMemoryEventStore } from '../src/inMemoryEventStore'; + +describe('InMemoryEventStore', () => { + it('resumes the standalone GET stream in event insertion order', async () => { + const store = new InMemoryEventStore(); + const streamId = '_GET_stream'; + const firstMessage: JSONRPCMessage = { + jsonrpc: '2.0', + method: 'test/event1', + params: {} + }; + const secondMessage: JSONRPCMessage = { + jsonrpc: '2.0', + method: 'test/event2', + params: {} + }; + const thirdMessage: JSONRPCMessage = { + jsonrpc: '2.0', + method: 'test/event3', + params: {} + }; + + const firstEventId = await store.storeEvent(streamId, firstMessage); + const secondEventId = await store.storeEvent(streamId, secondMessage); + const thirdEventId = await store.storeEvent(streamId, thirdMessage); + + const replayedEvents: { eventId: string; message: JSONRPCMessage }[] = []; + const returnedStreamId = await store.replayEventsAfter(firstEventId, { + send: async (eventId, message) => { + replayedEvents.push({ eventId, message }); + } + }); + + expect(returnedStreamId).toBe(streamId); + expect(replayedEvents).toEqual([ + { eventId: secondEventId, message: secondMessage }, + { eventId: thirdEventId, message: thirdMessage } + ]); + }); +});