{"version":3,"file":"notifications-worker.mjs","names":[],"sources":["../../../../../../../notifications/src/queue/notifications-worker.ts"],"sourcesContent":["/**\n * Notification queue worker — consumes the jobs `heraldQueue` publishes and\n * runs the actual `channel.send`. Call this once in a worker process (or the\n * web process) after the notifications config + herald broker are up.\n *\n * The job carries an ALREADY-RENDERED payload + resolved route, so the worker\n * only looks the channel up by name and dispatches — no notifiable needed.\n *\n * @example\n *   // in a worker entrypoint, after the notifications config + broker are up\n *   import { startNotificationsWorker } from \"@warlock.js/notifications\";\n *   await startNotificationsWorker();\n */\nimport { log } from \"@warlock.js/logger\";\nimport { getNotificationConfig } from \"../config\";\nimport type { ChannelName, SendOptions } from \"../types\";\nimport { DEFAULT_QUEUE_CHANNEL, loadHerald } from \"./load-herald\";\n\ntype NotificationJob = {\n  channel: string;\n  route: unknown;\n  payload: unknown;\n  options: SendOptions;\n};\n\nexport type WorkerOptions = {\n  /** Herald channel to consume from. Must match the dispatcher. Default `\"notifications.dispatch\"`. */\n  channel?: string;\n  /** Herald broker name. Default broker if omitted. */\n  broker?: string;\n};\n\nexport async function startNotificationsWorker(options: WorkerOptions = {}): Promise<void> {\n  const channelName = options.channel ?? DEFAULT_QUEUE_CHANNEL;\n  const { herald } = await loadHerald();\n\n  await herald(options.broker)\n    .channel(channelName)\n    .subscribe(async (message: { payload: unknown }, ctx: { ack(): Promise<void> }) => {\n      const job = message.payload as NotificationJob;\n\n      try {\n        const channel = getNotificationConfig().channels[job.channel as ChannelName];\n\n        if (!channel) {\n          // Unknown channel — log and ack to avoid a poison-message loop.\n          log.error(\"notifications\", \"queue.worker\", `Unknown channel \"${job.channel}\" — dropping job`);\n          await ctx.ack();\n          return;\n        }\n\n        await channel.send({\n          payload: job.payload as never,\n          route: job.route as never,\n          options: job.options,\n        });\n\n        await ctx.ack();\n      } catch (error) {\n        // Phase 2: log + ack (no retry/DLQ yet — that lands with the\n        // delay-aware worker). A dead-letter strategy is a follow-up.\n        log.error(\"notifications\", \"queue.worker\", error as Error);\n        await ctx.ack();\n      }\n    });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgCA,eAAsB,yBAAyB,UAAyB,CAAC,GAAkB;CACzF,MAAM,cAAc,QAAQ;CAC5B,MAAM,EAAE,WAAW,MAAM,WAAW;CAEpC,MAAM,OAAO,QAAQ,MAAM,CAAC,CACzB,QAAQ,WAAW,CAAC,CACpB,UAAU,OAAO,SAA+B,QAAkC;EACjF,MAAM,MAAM,QAAQ;EAEpB,IAAI;GACF,MAAM,UAAU,sBAAsB,CAAC,CAAC,SAAS,IAAI;GAErD,IAAI,CAAC,SAAS;IAEZ,IAAI,MAAM,iBAAiB,gBAAgB,oBAAoB,IAAI,QAAQ,iBAAiB;IAC5F,MAAM,IAAI,IAAI;IACd;GACF;GAEA,MAAM,QAAQ,KAAK;IACjB,SAAS,IAAI;IACb,OAAO,IAAI;IACX,SAAS,IAAI;GACf,CAAC;GAED,MAAM,IAAI,IAAI;EAChB,SAAS,OAAO;GAGd,IAAI,MAAM,iBAAiB,gBAAgB,KAAc;GACzD,MAAM,IAAI,IAAI;EAChB;CACF,CAAC;AACL"}