UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

144 lines 4.3 kB
import { uuidv7 } from "../utils/uuid"; function deepCloneAndFreeze(obj) { if (obj === null || typeof obj !== "object") { return obj; } if (Array.isArray(obj)) { const cloned = obj.map((item) => deepCloneAndFreeze(item)); return Object.freeze(cloned); } const cloned = {}; for (const key of Object.keys(obj)) { cloned[key] = deepCloneAndFreeze(obj[key]); } return Object.freeze(cloned); } export class EventDispatcher { handlers = []; streamId; _context; highPerformance; batchSize; batchFlushMs; eventBatch = []; batchTimeout = null; constructor(contextOrConfig = {}) { this.streamId = uuidv7(); const isConfig = "highPerformance" in contextOrConfig || "batchSize" in contextOrConfig || "batchFlushMs" in contextOrConfig || "context" in contextOrConfig; if (isConfig) { const config = contextOrConfig; this.highPerformance = config.highPerformance ?? false; this.batchSize = config.batchSize ?? 10; this.batchFlushMs = config.batchFlushMs ?? 5; this._context = this.highPerformance ? Object.freeze(config.context ?? {}) : deepCloneAndFreeze(config.context ?? {}); } else { this.highPerformance = false; this.batchSize = 10; this.batchFlushMs = 5; this._context = deepCloneAndFreeze(contextOrConfig); } } onEvent(handler) { this.handlers.push(handler); } offEvent(handler) { const index = this.handlers.indexOf(handler); if (index !== -1) { this.handlers.splice(index, 1); } } flush() { if (this.batchTimeout) { clearTimeout(this.batchTimeout); this.batchTimeout = null; } if (this.eventBatch.length === 0) return; const batch = this.eventBatch; this.eventBatch = []; for (const event of batch) { this.dispatchToHandlers(event); } } dispatchToHandlers(event) { for (const handler of [...this.handlers]) { queueMicrotask(() => { try { const result = handler(event); if (result && typeof result === "object" && "catch" in result) { result.catch(() => { }); } } catch { } }); } } emit(type, payload) { if (this.handlers.length === 0) return; const event = { type, ts: Date.now(), streamId: this.streamId, context: this._context, ...payload, }; if (this.highPerformance && this.batchSize > 1) { this.eventBatch.push(event); if (this.eventBatch.length >= this.batchSize) { this.flush(); } else if (!this.batchTimeout) { this.batchTimeout = setTimeout(() => { this.batchTimeout = null; this.flush(); }, this.batchFlushMs); } return; } this.dispatchToHandlers(event); } emitSync(type, payload) { if (this.handlers.length === 0) return; const event = { type, ts: Date.now(), streamId: this.streamId, context: this._context, ...payload, }; for (const handler of [...this.handlers]) { try { const result = handler(event); if (result && typeof result === "object" && "catch" in result) { result.catch(() => { }); } } catch { } } } getStreamId() { return this.streamId; } getContext() { return this._context; } getHandlerCount() { return this.handlers.length; } } export function createEventDispatcher(context = {}) { return new EventDispatcher(context); } //# sourceMappingURL=event-dispatcher.js.map