import { EventEmitter } from "node:events"; import type { Transaction } from "@shared/lib/types"; /** * Global system event bus for cross-module communication. * Used for real-time dashboard updates and domain event decoupling. */ class SystemEventEmitter extends EventEmitter { /** * Emit an event and await all listeners sequentially. * Used for domain events that must preserve transaction atomicity * (e.g., quest progress tracking within the caller's DB transaction). */ async emitAsync(event: string, ...args: any[]): Promise { const listeners = this.listeners(event); for (const listener of listeners) { await (listener as Function)(...args); } return listeners.length > 0; } } export const systemEvents = new SystemEventEmitter(); export const EVENTS = { DASHBOARD: { STATS_UPDATE: "dashboard:stats_update", NEW_EVENT: "dashboard:new_event", }, ACTIONS: { RELOAD_COMMANDS: "actions:reload_commands", CLEAR_CACHE: "actions:clear_cache", MAINTENANCE_MODE: "actions:maintenance_mode", }, QUEST: { COMPLETED: "quest:completed", }, DOMAIN: { BALANCE_CHANGED: "domain:balance_changed", XP_GAINED: "domain:xp_gained", ITEM_COLLECTED: "domain:item_collected", ITEM_USED: "domain:item_used", TRANSFER_COMPLETED: "domain:transfer_completed", DAILY_CLAIMED: "domain:daily_claimed", TRIVIA_STARTED: "domain:trivia_started", TRIVIA_WON: "domain:trivia_won", EXAM_PASSED: "domain:exam_passed", }, } as const; export interface DomainEventPayloads { [EVENTS.DOMAIN.BALANCE_CHANGED]: { userId: string; type: string; tx: Transaction }; [EVENTS.DOMAIN.XP_GAINED]: { userId: string; amount: number; tx: Transaction }; [EVENTS.DOMAIN.ITEM_COLLECTED]: { userId: string; itemId: number; quantity: number; tx: Transaction }; [EVENTS.DOMAIN.ITEM_USED]: { userId: string; itemId: number; tx: Transaction }; [EVENTS.DOMAIN.TRANSFER_COMPLETED]: { userId: string; username: string; amount: bigint; toUserId: string; tx: Transaction }; [EVENTS.DOMAIN.DAILY_CLAIMED]: { userId: string; username: string; amount: bigint; tx: Transaction }; [EVENTS.DOMAIN.TRIVIA_STARTED]: { username: string; difficulty: string }; [EVENTS.DOMAIN.TRIVIA_WON]: { userId: string; username: string | undefined; reward: bigint; tx: Transaction }; [EVENTS.DOMAIN.EXAM_PASSED]: { userId: string; username: string; reward: bigint; tx: Transaction }; }