import { EventEmitter } from "node:events"; import type { CanonicalQuote, ConnectorHealth, MarketEvent, Observation, RawObservation } from "@market-atlas/market-model"; /** * Internal market bus. In-process today (modular monolith); the topic names mirror the * spec so that a NATS/Redpanda transport can replace this class without touching producers. */ export interface BusTopics { "raw.observation": RawObservation; "normalized.observation": Observation; "canonical.quote": CanonicalQuote; "market.event": MarketEvent; "connector.health": ConnectorHealth; "market.state": { exchangeId: string; state: string; at: number }; } type Handler = (msg: T) => void; export class MarketBus { private emitter = new EventEmitter({ captureRejections: false }); readonly counters: Record = {}; constructor() { this.emitter.setMaxListeners(200); } publish(topic: K, msg: BusTopics[K]): void { this.counters[topic] = (this.counters[topic] ?? 0) + 1; this.emitter.emit(topic, msg); } subscribe(topic: K, handler: Handler): () => void { this.emitter.on(topic, handler); return () => this.emitter.off(topic, handler); } } export const bus = new MarketBus();