/** * In-process outbox drain signal (D-01 / D-03 / D-04). * * Module-level singleton EventEmitter — one emitter shared across all callers * in this Node.js process. Carries a zero-payload 'drain' event: signal is * fire-and-forget; no data crosses this boundary (D-04). * * Single-subscriber design: * - signalOutboxDrain() is called only after a successful enqueue DB commit (D-01/D-03). * - The sole listener is registered by initOutboxTrigger() in outboxWorker.ts. * - With exactly one subscriber the default EventEmitter limit of 10 is correct. * - Do NOT call setMaxListeners — unlike listEmitter.ts (T-04-04, 200 SSE fan-out), * this emitter never fans out to multiple listeners. * * Exports: signalOutboxDrain, onOutboxDrain */ import { EventEmitter } from 'node:events'; // Module-level singleton — one emitter shared across all route handlers // in this Node.js process. const emitter = new EventEmitter(); /** * Fire a drain signal after a successful outbox enqueue commit. * Synchronous and fire-and-forget — never awaited (D-04). */ export function signalOutboxDrain(): void { emitter.emit('drain'); } /** * Register a handler to be invoked on each drain signal. * Returns an unsubscribe function; call it to stop delivery to this handler. */ export function onOutboxDrain(handler: () => void): () => void { emitter.on('drain', handler); return () => emitter.off('drain', handler); }