{"version":3,"file":"notifications-event-bus.mjs","names":[],"sources":["../../../../../../../notifications/src/dispatch/notifications-event-bus.ts"],"sourcesContent":["/**\n * Typed event bus for notifications observability. Emits `sent`, `failed`,\n * and `skipped` events per (channel, recipient) — fan-out emits N events.\n *\n * Intentionally minimal — a `Map<event, Set<handler>>` keeps tests trivial\n * and avoids pulling event-emitter machinery for what is fundamentally\n * pub/sub. Handler exceptions are logged-and-swallowed so one bad listener\n * cannot break the dispatcher.\n *\n * @example\n *   notifications.on(\"sent\",    ({ channel }) => metrics.inc(`notif.${channel}.sent`));\n *   notifications.on(\"skipped\", ({ reason })  => metrics.inc(`notif.skipped.${reason}`));\n *   const off = notifications.on(\"failed\", logErr);\n *   off(); // unsubscribe\n */\nimport { log } from \"@warlock.js/logger\";\nimport type { NotificationEvents } from \"../types\";\n\ntype EventName = keyof NotificationEvents;\ntype Handler<E extends EventName> = (data: NotificationEvents[E]) => void | Promise<void>;\n\nconst handlers: { [E in EventName]: Set<Handler<E>> } = {\n  sending: new Set(),\n  sent: new Set(),\n  failed: new Set(),\n  skipped: new Set(),\n};\n\n/**\n * Public observability surface.\n *\n * `on(event, handler)` returns an unsubscribe function. `off` exists for\n * symmetry with libraries that hold handler references for later removal.\n */\nexport const notifications = {\n  on<E extends EventName>(event: E, handler: Handler<E>): () => void {\n    handlers[event].add(handler as Handler<EventName>);\n    return () => {\n      handlers[event].delete(handler as Handler<EventName>);\n    };\n  },\n  off<E extends EventName>(event: E, handler: Handler<E>): void {\n    handlers[event].delete(handler as Handler<EventName>);\n  },\n};\n\n/**\n * Internal emit — used by the dispatcher. Not exported from the package.\n * Handlers run in registration order; an awaited Promise.allSettled isolates\n * each listener so one throw cannot block the others.\n */\nexport async function emit<E extends EventName>(\n  event: E,\n  data: NotificationEvents[E],\n): Promise<void> {\n  const set = handlers[event];\n  if (set.size === 0) return;\n\n  // The `async` wrapper turns SYNC handler throws into promise rejections so\n  // `Promise.allSettled` can isolate them. Without it, a `throw` inside the\n  // handler escapes the array map before allSettled gets a chance to catch.\n  const results = await Promise.allSettled(\n    Array.from(set).map(async (handler) => {\n      await (handler as Handler<E>)(data);\n    }),\n  );\n\n  for (const result of results) {\n    if (result.status === \"rejected\") {\n      log.error(\"notifications\", \"event-handler\", result.reason);\n    }\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,WAAkD;CACtD,yBAAS,IAAI,IAAI;CACjB,sBAAM,IAAI,IAAI;CACd,wBAAQ,IAAI,IAAI;CAChB,yBAAS,IAAI,IAAI;AACnB;;;;;;;AAQA,MAAa,gBAAgB;CAC3B,GAAwB,OAAU,SAAiC;EACjE,SAAS,MAAM,CAAC,IAAI,OAA6B;EACjD,aAAa;GACX,SAAS,MAAM,CAAC,OAAO,OAA6B;EACtD;CACF;CACA,IAAyB,OAAU,SAA2B;EAC5D,SAAS,MAAM,CAAC,OAAO,OAA6B;CACtD;AACF;;;;;;AAOA,eAAsB,KACpB,OACA,MACe;CACf,MAAM,MAAM,SAAS;CACrB,IAAI,IAAI,SAAS,GAAG;CAKpB,MAAM,UAAU,MAAM,QAAQ,WAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,OAAO,YAAY;EACrC,MAAO,QAAuB,IAAI;CACpC,CAAC,CACH;CAEA,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,WAAW,YACpB,IAAI,MAAM,iBAAiB,iBAAiB,OAAO,MAAM;AAG/D"}