import { EventEmitter } from 'stream'; import { applyPatch } from 'rfc6902'; import { Block } from './types'; const sessions = (global as any)._sessionManagerSessions || new Map(); if (process.env.NODE_ENV !== 'production') { (global as any)._sessionManagerSessions = sessions; } class SessionManager { private static sessions: Map = sessions; readonly id: string; private blocks = new Map(); private events: { event: string; data: any }[] = []; private emitter = new EventEmitter(); private TTL_MS = 30 * 60 * 1000; constructor(id?: string) { this.id = id ?? crypto.randomUUID(); setTimeout(() => { SessionManager.sessions.delete(this.id); }, this.TTL_MS); } static getSession(id: string): SessionManager | undefined { return this.sessions.get(id); } static getAllSessions(): SessionManager[] { return Array.from(this.sessions.values()); } static createSession(): SessionManager { const session = new SessionManager(); this.sessions.set(session.id, session); return session; } removeAllListeners() { this.emitter.removeAllListeners(); } emit(event: string, data: any) { this.emitter.emit(event, data); this.events.push({ event, data }); } emitBlock(block: Block) { this.blocks.set(block.id, block); this.emit('data', { type: 'block', block: block, }); } getBlock(blockId: string): Block | undefined { return this.blocks.get(blockId); } updateBlock(blockId: string, patch: any[]) { const block = this.blocks.get(blockId); if (block) { applyPatch(block, patch); this.blocks.set(blockId, block); this.emit('data', { type: 'updateBlock', blockId: blockId, patch: patch, }); } } getAllBlocks() { return Array.from(this.blocks.values()); } subscribe(listener: (event: string, data: any) => void): () => void { const currentEventsLength = this.events.length; const handler = (event: string) => (data: any) => listener(event, data); const dataHandler = handler('data'); const endHandler = handler('end'); const errorHandler = handler('error'); this.emitter.on('data', dataHandler); this.emitter.on('end', endHandler); this.emitter.on('error', errorHandler); for (let i = 0; i < currentEventsLength; i++) { const { event, data } = this.events[i]; listener(event, data); } return () => { this.emitter.off('data', dataHandler); this.emitter.off('end', endHandler); this.emitter.off('error', errorHandler); }; } } export default SessionManager;