| 13 | * see more details: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#resumability-and-redelivery. |
| 14 | */ |
| 15 | export class InMemoryEventStore implements EventStore { |
| 16 | private events: Map<string, { streamId: string; message: JSONRPCMessage }> = |
| 17 | new Map(); |
| 18 | |
| 19 | /** |
| 20 | * Generates a unique event ID for a given stream ID |
| 21 | */ |
| 22 | private generateEventId(streamId: string): string { |
| 23 | return `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`; |
| 24 | } |
| 25 | |
| 26 | /** |
| 27 | * Extracts the stream ID from an event ID |
| 28 | */ |
| 29 | private getStreamIdFromEventId(eventId: string): string { |
| 30 | const parts = eventId.split('_'); |
| 31 | return parts.length > 0 ? parts[0] : ''; |
| 32 | } |
| 33 | |
| 34 | /** |
| 35 | * Stores an event with a generated event ID |
| 36 | * Implements EventStore.storeEvent |
| 37 | */ |
| 38 | async storeEvent(streamId: string, message: JSONRPCMessage): Promise<string> { |
| 39 | const eventId = this.generateEventId(streamId); |
| 40 | this.events.set(eventId, { streamId, message }); |
| 41 | return eventId; |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Replays events that occurred after a specific event ID |
| 46 | * Implements EventStore.replayEventsAfter |
| 47 | */ |
| 48 | async replayEventsAfter( |
| 49 | lastEventId: string, |
| 50 | { |
| 51 | send, |
| 52 | }: { send: (eventId: string, message: JSONRPCMessage) => Promise<void> } |
| 53 | ): Promise<string> { |
| 54 | if (!lastEventId || !this.events.has(lastEventId)) { |
| 55 | return ''; |
| 56 | } |
| 57 | |
| 58 | // Extract the stream ID from the event ID |
| 59 | const streamId = this.getStreamIdFromEventId(lastEventId); |
| 60 | if (!streamId) { |
| 61 | return ''; |
| 62 | } |
| 63 | |
| 64 | let foundLastEvent = false; |
| 65 | |
| 66 | // Sort events by eventId for chronological ordering |
| 67 | const sortedEvents = [...this.events.entries()].sort((a, b) => |
| 68 | a[0].localeCompare(b[0]) |
| 69 | ); |
| 70 | |
| 71 | for (const [ |
| 72 | eventId, |
nothing calls this directly
no outgoing calls
no test coverage detected