diff --git a/src/lib/events/bus.ts b/src/lib/events/bus.ts index a3e90de..0cdf108 100644 --- a/src/lib/events/bus.ts +++ b/src/lib/events/bus.ts @@ -6,16 +6,21 @@ export type TicketEvent = | { type: "ticket.updated"; ticket: TicketDTO } | { type: "message.created"; ticketId: string; customerId: string; assigneeId: string | null; message: MessageDTO }; -// Next.js dev mode reloads this module on every edit — stash the emitter on -// globalThis so hot reload doesn't spawn a second, disconnected bus. +// Stashed on globalThis rather than relying on Node's module cache to give +// us a singleton: Next.js dev mode reloads this module on every edit (hot +// reload would otherwise spawn a second, disconnected bus), and — the +// production-breaking case — Turbopack's route-level bundling can inline +// this small module separately into each route's own chunk instead of +// sharing one instance, so /api/events (the SSE subscriber) and whatever +// publishes an event (ticket creation, mail ingestion, ...) can each end up +// holding their own private EventEmitter that never sees the other's +// events. globalThis is the one thing guaranteed to be the same object +// across every chunk in the process, in both dev and production. const globalForBus = globalThis as unknown as { ticketEventBus?: EventEmitter }; const emitter = globalForBus.ticketEventBus ?? new EventEmitter(); emitter.setMaxListeners(200); // one per open SSE connection - -if (process.env.NODE_ENV !== "production") { - globalForBus.ticketEventBus = emitter; -} +globalForBus.ticketEventBus = emitter; const CHANNEL = "ticket-event";