UNPKG

jay-code

Version:

Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability

188 lines (161 loc) 4.51 kB
/** * Event bus implementation for Jay-Code */ import { SystemEvents } from '../utils/types.js'; import type { EventMap } from '../utils/types.js'; import { TypedEventEmitter } from '../utils/helpers.js'; export interface IEventBus { emit(event: string, data?: unknown): void; on(event: string, handler: (data: unknown) => void): void; off(event: string, handler: (data: unknown) => void): void; once(event: string, handler: (data: unknown) => void): void; } /** * Internal typed event bus */ class TypedEventBus extends TypedEventEmitter<EventMap> { private eventCounts = new Map<keyof EventMap, number>(); private lastEventTimes = new Map<keyof EventMap, number>(); private debug: boolean; constructor(debug = false) { super(); this.debug = debug; } /** * Emits an event with logging */ override emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void { if (this.debug) { console.debug(`[EventBus] Emitting event: ${String(event)}`, data); } // Track event metrics const count = this.eventCounts.get(event) || 0; this.eventCounts.set(event, count + 1); this.lastEventTimes.set(event, Date.now()); super.emit(event, data); } /** * Get event statistics */ getEventStats(): { event: string; count: number; lastEmitted: Date | null }[] { const stats: { event: string; count: number; lastEmitted: Date | null }[] = []; for (const [event, count] of this.eventCounts.entries()) { const lastTime = this.lastEventTimes.get(event); stats.push({ event: String(event), count, lastEmitted: lastTime ? new Date(lastTime) : null, }); } return stats.sort((a, b) => b.count - a.count); } /** * Reset event statistics */ resetStats(): void { this.eventCounts.clear(); this.lastEventTimes.clear(); } } /** * Global event bus for system-wide communication */ export class EventBus implements IEventBus { private static instance: EventBus; private typedBus: TypedEventBus; private constructor(debug = false) { this.typedBus = new TypedEventBus(debug); } /** * Gets the singleton instance of the event bus */ static getInstance(debug = false): EventBus { if (!EventBus.instance) { EventBus.instance = new EventBus(debug); } return EventBus.instance; } /** * Emits an event */ emit(event: string, data?: unknown): void { // Type-safe emission for known events if (event in SystemEvents) { this.typedBus.emit(event as keyof EventMap, data as any); } else { // For custom events, emit as-is this.typedBus.emit(event as any, data as any); } } /** * Registers an event handler */ on(event: string, handler: (data: unknown) => void): void { this.typedBus.on(event as any, handler); } /** * Removes an event handler */ off(event: string, handler: (data: unknown) => void): void { this.typedBus.off(event as any, handler); } /** * Registers a one-time event handler */ once(event: string, handler: (data: unknown) => void): void { this.typedBus.once(event as any, handler); } /** * Waits for an event to occur */ async waitFor(event: string, timeoutMs?: number): Promise<unknown> { return new Promise((resolve, reject) => { const handler = (data: unknown) => { if (timer) clearTimeout(timer); resolve(data); }; let timer: number | undefined; if (timeoutMs) { timer = setTimeout(() => { this.off(event, handler); reject(new Error(`Timeout waiting for event: ${event}`)); }, timeoutMs); } this.once(event, handler); }); } /** * Creates a filtered event listener */ onFiltered( event: string, filter: (data: unknown) => boolean, handler: (data: unknown) => void, ): void { this.on(event, (data) => { if (filter(data)) { handler(data); } }); } /** * Get event statistics */ getEventStats(): { event: string; count: number; lastEmitted: Date | null }[] { return this.typedBus.getEventStats(); } /** * Reset event statistics */ resetStats(): void { this.typedBus.resetStats(); } /** * Remove all listeners for an event */ removeAllListeners(event?: string): void { this.typedBus.removeAllListeners(event as any); } } // Export singleton instance export const eventBus = EventBus.getInstance();