@warlock.js/queue 5.30.0 → 5.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +4 -2
  3. package/cjs/index.cjs +32 -2
  4. package/cjs/index.cjs.map +1 -1
  5. package/esm/config.d.mts +4 -6
  6. package/esm/config.d.mts.map +1 -1
  7. package/esm/dashboard-boot.d.mts +2 -4
  8. package/esm/dashboard-boot.d.mts.map +1 -1
  9. package/esm/dashboard.d.mts +8 -7
  10. package/esm/dashboard.d.mts.map +1 -1
  11. package/esm/dashboard.mjs +1 -1
  12. package/esm/dashboard.mjs.map +1 -1
  13. package/esm/define-job.d.mts +2 -2
  14. package/esm/define-job.d.mts.map +1 -1
  15. package/esm/define-job.mjs +15 -1
  16. package/esm/define-job.mjs.map +1 -1
  17. package/esm/dispatch-interceptor.d.mts +33 -0
  18. package/esm/dispatch-interceptor.d.mts.map +1 -0
  19. package/esm/dispatch-interceptor.mjs +14 -0
  20. package/esm/dispatch-interceptor.mjs.map +1 -0
  21. package/esm/duration.d.mts +1 -3
  22. package/esm/duration.d.mts.map +1 -1
  23. package/esm/errors.d.mts +6 -7
  24. package/esm/errors.d.mts.map +1 -1
  25. package/esm/failed-jobs.d.mts +8 -7
  26. package/esm/failed-jobs.d.mts.map +1 -1
  27. package/esm/failed-jobs.mjs +2 -1
  28. package/esm/failed-jobs.mjs.map +1 -1
  29. package/esm/index.d.mts +3 -1
  30. package/esm/index.mjs +3 -1
  31. package/esm/job-registry.d.mts +10 -0
  32. package/esm/job-registry.d.mts.map +1 -0
  33. package/esm/process-job.mjs.map +1 -1
  34. package/esm/queue-connector.d.mts +3 -5
  35. package/esm/queue-connector.d.mts.map +1 -1
  36. package/esm/queue-connector.mjs.map +1 -1
  37. package/esm/queue-context.d.mts +8 -7
  38. package/esm/queue-context.d.mts.map +1 -1
  39. package/esm/queue-dashboard-unguarded.error.d.mts +1 -2
  40. package/esm/queue-dashboard-unguarded.error.d.mts.map +1 -1
  41. package/esm/queue-dashboard-unguarded.error.mjs.map +1 -1
  42. package/esm/queue-manager.d.mts +5 -7
  43. package/esm/queue-manager.d.mts.map +1 -1
  44. package/esm/types.d.mts +76 -46
  45. package/esm/types.d.mts.map +1 -1
  46. package/llms-full.txt +36 -7
  47. package/llms.txt +1 -1
  48. package/package.json +3 -3
  49. package/skills/define-jobs/SKILL.md +36 -6
  50. package/skills/index.md +4 -1
  51. package/skills/queue-notifications/SKILL.md +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"define-job.mjs","names":[],"sources":["../../../../../../../packages/queue/src/define-job.ts"],"sourcesContent":["import type { Job, JobsOptions } from \"bullmq\";\nimport { getQueueConfig } from \"./config\";\nimport { toMilliseconds } from \"./duration\";\nimport { InvalidJobDefinitionError } from \"./errors\";\nimport { getQueueContext, unwrapPayload, wrapPayload } from \"./queue-context\";\nimport { queueOf, registerJob, type RegisteredJob } from \"./job-registry\";\nimport { getQueue } from \"./queue-manager\";\nimport type {\n DispatchOptions,\n JobBackoff,\n JobDefinition,\n JobOptions,\n JobSnapshot,\n JobState,\n QueueJob,\n} from \"./types\";\n\n/**\n * Define a background job.\n *\n * The definition is registered by name so any worker in the process can run\n * it; the returned object dispatches it with a typed payload.\n *\n * @example\n * export const sendInvoice = defineJob({\n * name: \"invoices.send\",\n * attempts: 5,\n * backoff: { type: \"exponential\", delay: 2000 },\n * async handle(payload: { invoiceId: string }, ctx) {\n * await ctx.progress(50);\n * },\n * });\n *\n * await sendInvoice.dispatch({ invoiceId: \"42\" }, { delay: \"10m\", priority: 1 });\n */\nexport function defineJob<TPayload, TResult = unknown>(\n definition: JobDefinition<TPayload, TResult>,\n): QueueJob<TPayload, TResult> {\n assertValidDefinition(definition);\n registerJob(definition as RegisteredJob);\n\n return {\n name: definition.name,\n get queue() {\n return queueOf(definition);\n },\n async dispatch(payload, options = {}) {\n const queueName = queueOf(definition);\n // Capture synchronously, in the caller's async context.\n const captured = definition.context === false ? undefined : getQueueContext()?.capture();\n const job = await getQueue(queueName).add(\n definition.name,\n wrapPayload(payload, captured),\n toBullJobOptions(definition, options),\n );\n\n return { id: String(job.id), name: definition.name, queue: queueName };\n },\n async find(id) {\n const queue = getQueue(queueOf(definition));\n const initialJob = await queue.getJob(id);\n\n if (!initialJob || initialJob.name !== definition.name) {\n return undefined;\n }\n\n // Read the state first, then (re)fetch the job. BullMQ writes a job's\n // result/attemptsMade/finishedOn fields *before* it becomes visible\n // under a new state, so re-reading the job after the state is known\n // guarantees those fields are consistent with the reported state\n // (rather than reflecting a moment before the job finished).\n const state = (await initialJob.getState()) as JobState;\n const job = (await queue.getJob(id)) ?? initialJob;\n\n return toSnapshot<TPayload, TResult>(job, state);\n },\n };\n}\n\nfunction assertValidDefinition(definition: JobDefinition<unknown, unknown>): void {\n if (typeof definition.name !== \"string\" || definition.name.trim() === \"\") {\n throw new InvalidJobDefinitionError(\"defineJob() requires a non-empty `name`.\");\n }\n\n if (typeof definition.handle !== \"function\") {\n throw new InvalidJobDefinitionError(\n `defineJob(\"${definition.name}\") requires a \\`handle(payload, ctx)\\` function.`,\n );\n }\n\n if (definition.attempts !== undefined && !(Number.isInteger(definition.attempts) && definition.attempts >= 1)) {\n throw new InvalidJobDefinitionError(\n `defineJob(\"${definition.name}\"): \\`attempts\\` must be an integer >= 1, got ${definition.attempts}.`,\n );\n }\n}\n\n/**\n * Merge app defaults < job definition < dispatch options into BullMQ's shape.\n */\nfunction toBullJobOptions(definition: JobOptions, options: DispatchOptions): JobsOptions {\n const defaults = getQueueConfig().defaultJobOptions ?? {};\n const attempts = options.attempts ?? definition.attempts ?? defaults.attempts;\n const backoff = options.backoff ?? definition.backoff ?? defaults.backoff;\n const removeOnComplete = definition.removeOnComplete ?? defaults.removeOnComplete;\n const removeOnFail = definition.removeOnFail ?? defaults.removeOnFail;\n\n const bullOptions: JobsOptions = {};\n\n if (attempts !== undefined) bullOptions.attempts = attempts;\n if (backoff !== undefined) bullOptions.backoff = toBullBackoff(backoff);\n if (removeOnComplete !== undefined) bullOptions.removeOnComplete = removeOnComplete;\n if (removeOnFail !== undefined) bullOptions.removeOnFail = removeOnFail;\n if (options.delay !== undefined) bullOptions.delay = toMilliseconds(options.delay);\n if (options.priority !== undefined) bullOptions.priority = options.priority;\n if (options.jobId !== undefined) bullOptions.jobId = options.jobId;\n\n return bullOptions;\n}\n\nfunction toBullBackoff(backoff: JobBackoff): JobsOptions[\"backoff\"] {\n return typeof backoff === \"number\" ? { type: \"fixed\", delay: backoff } : backoff;\n}\n\n/**\n * A plain view of a BullMQ job.\n *\n * @param job The job to read fields from.\n * @param state The job's state; pass a state read *before* `job` was\n * fetched (or re-fetched) so the returned snapshot's fields are consistent\n * with it. If omitted, the state is read from `job` directly.\n */\nexport async function toSnapshot<TPayload, TResult>(\n job: Job,\n state?: JobState,\n): Promise<JobSnapshot<TPayload, TResult>> {\n const resolvedState = state ?? ((await job.getState()) as JobState);\n\n return {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n state: resolvedState,\n payload: unwrapPayload(job.data).payload as TPayload,\n progress: job.progress as JobSnapshot[\"progress\"],\n attemptsMade: job.attemptsMade,\n result: job.returnvalue as TResult | undefined,\n failedReason: job.failedReason || undefined,\n createdAt: new Date(job.timestamp),\n finishedAt: job.finishedOn ? new Date(job.finishedOn) : undefined,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,UACd,YAC6B;CAC7B,sBAAsB,UAAU;CAChC,YAAY,UAA2B;CAEvC,OAAO;EACL,MAAM,WAAW;EACjB,IAAI,QAAQ;GACV,OAAO,QAAQ,UAAU;EAC3B;EACA,MAAM,SAAS,SAAS,UAAU,CAAC,GAAG;GACpC,MAAM,YAAY,QAAQ,UAAU;GAEpC,MAAM,WAAW,WAAW,YAAY,QAAQ,SAAY,gBAAgB,CAAC,EAAE,QAAQ;GACvF,MAAM,MAAM,MAAM,SAAS,SAAS,CAAC,CAAC,IACpC,WAAW,MACX,YAAY,SAAS,QAAQ,GAC7B,iBAAiB,YAAY,OAAO,CACtC;GAEA,OAAO;IAAE,IAAI,OAAO,IAAI,EAAE;IAAG,MAAM,WAAW;IAAM,OAAO;GAAU;EACvE;EACA,MAAM,KAAK,IAAI;GACb,MAAM,QAAQ,SAAS,QAAQ,UAAU,CAAC;GAC1C,MAAM,aAAa,MAAM,MAAM,OAAO,EAAE;GAExC,IAAI,CAAC,cAAc,WAAW,SAAS,WAAW,MAChD;GAQF,MAAM,QAAS,MAAM,WAAW,SAAS;GAGzC,OAAO,WAFM,MAAM,MAAM,OAAO,EAAE,KAAM,YAEE,KAAK;EACjD;CACF;AACF;AAEA,SAAS,sBAAsB,YAAmD;CAChF,IAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,KAAK,MAAM,IACpE,MAAM,IAAI,0BAA0B,0CAA0C;CAGhF,IAAI,OAAO,WAAW,WAAW,YAC/B,MAAM,IAAI,0BACR,cAAc,WAAW,KAAK,iDAChC;CAGF,IAAI,WAAW,aAAa,UAAa,EAAE,OAAO,UAAU,WAAW,QAAQ,KAAK,WAAW,YAAY,IACzG,MAAM,IAAI,0BACR,cAAc,WAAW,KAAK,gDAAgD,WAAW,SAAS,EACpG;AAEJ;;;;AAKA,SAAS,iBAAiB,YAAwB,SAAuC;CACvF,MAAM,WAAW,eAAe,CAAC,CAAC,qBAAqB,CAAC;CACxD,MAAM,WAAW,QAAQ,YAAY,WAAW,YAAY,SAAS;CACrE,MAAM,UAAU,QAAQ,WAAW,WAAW,WAAW,SAAS;CAClE,MAAM,mBAAmB,WAAW,oBAAoB,SAAS;CACjE,MAAM,eAAe,WAAW,gBAAgB,SAAS;CAEzD,MAAM,cAA2B,CAAC;CAElC,IAAI,aAAa,QAAW,YAAY,WAAW;CACnD,IAAI,YAAY,QAAW,YAAY,UAAU,cAAc,OAAO;CACtE,IAAI,qBAAqB,QAAW,YAAY,mBAAmB;CACnE,IAAI,iBAAiB,QAAW,YAAY,eAAe;CAC3D,IAAI,QAAQ,UAAU,QAAW,YAAY,QAAQ,eAAe,QAAQ,KAAK;CACjF,IAAI,QAAQ,aAAa,QAAW,YAAY,WAAW,QAAQ;CACnE,IAAI,QAAQ,UAAU,QAAW,YAAY,QAAQ,QAAQ;CAE7D,OAAO;AACT;AAEA,SAAS,cAAc,SAA6C;CAClE,OAAO,OAAO,YAAY,WAAW;EAAE,MAAM;EAAS,OAAO;CAAQ,IAAI;AAC3E;;;;;;;;;AAUA,eAAsB,WACpB,KACA,OACyC;CACzC,MAAM,gBAAgB,SAAW,MAAM,IAAI,SAAS;CAEpD,OAAO;EACL,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,OAAO;EACP,SAAS,cAAc,IAAI,IAAI,CAAC,CAAC;EACjC,UAAU,IAAI;EACd,cAAc,IAAI;EAClB,QAAQ,IAAI;EACZ,cAAc,IAAI,gBAAgB;EAClC,WAAW,IAAI,KAAK,IAAI,SAAS;EACjC,YAAY,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;CAC1D;AACF"}
1
+ {"version":3,"file":"define-job.mjs","names":[],"sources":["../../../../../../../packages/queue/src/define-job.ts"],"sourcesContent":["import type { Job, JobsOptions } from \"bullmq\";\nimport { getQueueConfig } from \"./config\";\nimport { getDispatchInterceptor } from \"./dispatch-interceptor\";\nimport { toMilliseconds } from \"./duration\";\nimport { InvalidJobDefinitionError } from \"./errors\";\nimport { getQueueContext, unwrapPayload, wrapPayload } from \"./queue-context\";\nimport { queueOf, registerJob, type RegisteredJob } from \"./job-registry\";\nimport { getQueue } from \"./queue-manager\";\nimport type {\n DispatchOptions,\n JobBackoff,\n JobDefinition,\n JobOptions,\n JobSnapshot,\n JobState,\n QueueJob,\n} from \"./types\";\n\n/**\n * Define a background job.\n *\n * The definition is registered by name so any worker in the process can run\n * it; the returned object dispatches it with a typed payload.\n *\n * @example\n * export const sendInvoice = defineJob({\n * name: \"invoices.send\",\n * attempts: 5,\n * backoff: { type: \"exponential\", delay: 2000 },\n * async handle(payload: { invoiceId: string }, ctx) {\n * await ctx.progress(50);\n * },\n * });\n *\n * await sendInvoice.dispatch({ invoiceId: \"42\" }, { delay: \"10m\", priority: 1 });\n */\nexport function defineJob<TPayload, TResult = unknown>(\n definition: JobDefinition<TPayload, TResult>,\n): QueueJob<TPayload, TResult> {\n assertValidDefinition(definition);\n registerJob(definition as RegisteredJob);\n\n return {\n name: definition.name,\n get queue() {\n return queueOf(definition);\n },\n async dispatch(payload, options = {}) {\n const queueName = queueOf(definition);\n const interceptor = getDispatchInterceptor();\n\n // A test fake stands in for the broker: record, never touch Redis.\n if (interceptor) {\n return interceptor.dispatch({ name: definition.name, queue: queueName, payload, options });\n }\n\n // Capture synchronously, in the caller's async context.\n const captured = definition.context === false ? undefined : getQueueContext()?.capture();\n const job = await getQueue(queueName).add(\n definition.name,\n wrapPayload(payload, captured),\n toBullJobOptions(definition, options),\n );\n\n return { id: String(job.id), name: definition.name, queue: queueName };\n },\n async find(id) {\n const interceptor = getDispatchInterceptor();\n\n if (interceptor) {\n const found = await interceptor.find?.({\n name: definition.name,\n queue: queueOf(definition),\n id,\n });\n\n return found as JobSnapshot<TPayload, TResult> | undefined;\n }\n\n const queue = getQueue(queueOf(definition));\n const initialJob = await queue.getJob(id);\n\n if (!initialJob || initialJob.name !== definition.name) {\n return undefined;\n }\n\n // Read the state first, then (re)fetch the job. BullMQ writes a job's\n // result/attemptsMade/finishedOn fields *before* it becomes visible\n // under a new state, so re-reading the job after the state is known\n // guarantees those fields are consistent with the reported state\n // (rather than reflecting a moment before the job finished).\n const state = (await initialJob.getState()) as JobState;\n const job = (await queue.getJob(id)) ?? initialJob;\n\n return toSnapshot<TPayload, TResult>(job, state);\n },\n };\n}\n\nfunction assertValidDefinition(definition: JobDefinition<unknown, unknown>): void {\n if (typeof definition.name !== \"string\" || definition.name.trim() === \"\") {\n throw new InvalidJobDefinitionError(\"defineJob() requires a non-empty `name`.\");\n }\n\n if (typeof definition.handle !== \"function\") {\n throw new InvalidJobDefinitionError(\n `defineJob(\"${definition.name}\") requires a \\`handle(payload, ctx)\\` function.`,\n );\n }\n\n if (\n definition.attempts !== undefined &&\n !(Number.isInteger(definition.attempts) && definition.attempts >= 1)\n ) {\n throw new InvalidJobDefinitionError(\n `defineJob(\"${definition.name}\"): \\`attempts\\` must be an integer >= 1, got ${definition.attempts}.`,\n );\n }\n}\n\n/**\n * Merge app defaults < job definition < dispatch options into BullMQ's shape.\n */\nfunction toBullJobOptions(definition: JobOptions, options: DispatchOptions): JobsOptions {\n const defaults = getQueueConfig().defaultJobOptions ?? {};\n const attempts = options.attempts ?? definition.attempts ?? defaults.attempts;\n const backoff = options.backoff ?? definition.backoff ?? defaults.backoff;\n const removeOnComplete = definition.removeOnComplete ?? defaults.removeOnComplete;\n const removeOnFail = definition.removeOnFail ?? defaults.removeOnFail;\n\n const bullOptions: JobsOptions = {};\n\n if (attempts !== undefined) bullOptions.attempts = attempts;\n if (backoff !== undefined) bullOptions.backoff = toBullBackoff(backoff);\n if (removeOnComplete !== undefined) bullOptions.removeOnComplete = removeOnComplete;\n if (removeOnFail !== undefined) bullOptions.removeOnFail = removeOnFail;\n if (options.delay !== undefined) bullOptions.delay = toMilliseconds(options.delay);\n if (options.priority !== undefined) bullOptions.priority = options.priority;\n if (options.jobId !== undefined) bullOptions.jobId = options.jobId;\n\n return bullOptions;\n}\n\nfunction toBullBackoff(backoff: JobBackoff): JobsOptions[\"backoff\"] {\n return typeof backoff === \"number\" ? { type: \"fixed\", delay: backoff } : backoff;\n}\n\n/**\n * A plain view of a BullMQ job.\n *\n * @param job The job to read fields from.\n * @param state The job's state; pass a state read *before* `job` was\n * fetched (or re-fetched) so the returned snapshot's fields are consistent\n * with it. If omitted, the state is read from `job` directly.\n */\nexport async function toSnapshot<TPayload, TResult>(\n job: Job,\n state?: JobState,\n): Promise<JobSnapshot<TPayload, TResult>> {\n const resolvedState = state ?? ((await job.getState()) as JobState);\n\n return {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n state: resolvedState,\n payload: unwrapPayload(job.data).payload as TPayload,\n progress: job.progress as JobSnapshot[\"progress\"],\n attemptsMade: job.attemptsMade,\n result: job.returnvalue as TResult | undefined,\n failedReason: job.failedReason || undefined,\n createdAt: new Date(job.timestamp),\n finishedAt: job.finishedOn ? new Date(job.finishedOn) : undefined,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,UACd,YAC6B;CAC7B,sBAAsB,UAAU;CAChC,YAAY,UAA2B;CAEvC,OAAO;EACL,MAAM,WAAW;EACjB,IAAI,QAAQ;GACV,OAAO,QAAQ,UAAU;EAC3B;EACA,MAAM,SAAS,SAAS,UAAU,CAAC,GAAG;GACpC,MAAM,YAAY,QAAQ,UAAU;GACpC,MAAM,cAAc,uBAAuB;GAG3C,IAAI,aACF,OAAO,YAAY,SAAS;IAAE,MAAM,WAAW;IAAM,OAAO;IAAW;IAAS;GAAQ,CAAC;GAI3F,MAAM,WAAW,WAAW,YAAY,QAAQ,SAAY,gBAAgB,CAAC,EAAE,QAAQ;GACvF,MAAM,MAAM,MAAM,SAAS,SAAS,CAAC,CAAC,IACpC,WAAW,MACX,YAAY,SAAS,QAAQ,GAC7B,iBAAiB,YAAY,OAAO,CACtC;GAEA,OAAO;IAAE,IAAI,OAAO,IAAI,EAAE;IAAG,MAAM,WAAW;IAAM,OAAO;GAAU;EACvE;EACA,MAAM,KAAK,IAAI;GACb,MAAM,cAAc,uBAAuB;GAE3C,IAAI,aAOF,OAAO,MANa,YAAY,OAAO;IACrC,MAAM,WAAW;IACjB,OAAO,QAAQ,UAAU;IACzB;GACF,CAAC;GAKH,MAAM,QAAQ,SAAS,QAAQ,UAAU,CAAC;GAC1C,MAAM,aAAa,MAAM,MAAM,OAAO,EAAE;GAExC,IAAI,CAAC,cAAc,WAAW,SAAS,WAAW,MAChD;GAQF,MAAM,QAAS,MAAM,WAAW,SAAS;GAGzC,OAAO,WAFM,MAAM,MAAM,OAAO,EAAE,KAAM,YAEE,KAAK;EACjD;CACF;AACF;AAEA,SAAS,sBAAsB,YAAmD;CAChF,IAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,KAAK,MAAM,IACpE,MAAM,IAAI,0BAA0B,0CAA0C;CAGhF,IAAI,OAAO,WAAW,WAAW,YAC/B,MAAM,IAAI,0BACR,cAAc,WAAW,KAAK,iDAChC;CAGF,IACE,WAAW,aAAa,UACxB,EAAE,OAAO,UAAU,WAAW,QAAQ,KAAK,WAAW,YAAY,IAElE,MAAM,IAAI,0BACR,cAAc,WAAW,KAAK,gDAAgD,WAAW,SAAS,EACpG;AAEJ;;;;AAKA,SAAS,iBAAiB,YAAwB,SAAuC;CACvF,MAAM,WAAW,eAAe,CAAC,CAAC,qBAAqB,CAAC;CACxD,MAAM,WAAW,QAAQ,YAAY,WAAW,YAAY,SAAS;CACrE,MAAM,UAAU,QAAQ,WAAW,WAAW,WAAW,SAAS;CAClE,MAAM,mBAAmB,WAAW,oBAAoB,SAAS;CACjE,MAAM,eAAe,WAAW,gBAAgB,SAAS;CAEzD,MAAM,cAA2B,CAAC;CAElC,IAAI,aAAa,QAAW,YAAY,WAAW;CACnD,IAAI,YAAY,QAAW,YAAY,UAAU,cAAc,OAAO;CACtE,IAAI,qBAAqB,QAAW,YAAY,mBAAmB;CACnE,IAAI,iBAAiB,QAAW,YAAY,eAAe;CAC3D,IAAI,QAAQ,UAAU,QAAW,YAAY,QAAQ,eAAe,QAAQ,KAAK;CACjF,IAAI,QAAQ,aAAa,QAAW,YAAY,WAAW,QAAQ;CACnE,IAAI,QAAQ,UAAU,QAAW,YAAY,QAAQ,QAAQ;CAE7D,OAAO;AACT;AAEA,SAAS,cAAc,SAA6C;CAClE,OAAO,OAAO,YAAY,WAAW;EAAE,MAAM;EAAS,OAAO;CAAQ,IAAI;AAC3E;;;;;;;;;AAUA,eAAsB,WACpB,KACA,OACyC;CACzC,MAAM,gBAAgB,SAAW,MAAM,IAAI,SAAS;CAEpD,OAAO;EACL,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,OAAO;EACP,SAAS,cAAc,IAAI,IAAI,CAAC,CAAC;EACjC,UAAU,IAAI;EACd,cAAc,IAAI;EAClB,QAAQ,IAAI;EACZ,cAAc,IAAI,gBAAgB;EAClC,WAAW,IAAI,KAAK,IAAI,SAAS;EACjC,YAAY,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;CAC1D;AACF"}
@@ -0,0 +1,33 @@
1
+ import { DispatchOptions, DispatchedJob, JobSnapshot } from "./types.mjs";
2
+ //#region ../../packages/queue/src/dispatch-interceptor.d.ts
3
+ /**
4
+ * A stand-in for the broker, used by test fakes.
5
+ *
6
+ * When one is installed, `job.dispatch()` hands the job to it instead of
7
+ * adding it to BullMQ, and `job.find()` asks it instead of Redis. Nothing
8
+ * connects to Redis while it is installed.
9
+ *
10
+ * `@warlock.js/core/tests` installs one as `queueFake` in the test
11
+ * environment; this package exposes the seam so core needs no dependency on
12
+ * it. The slot lives on `globalThis` so every copy of this package in a
13
+ * process (a Vitest worker can load two) sees the same one.
14
+ */
15
+ export type DispatchInterceptor = {
16
+ dispatch(job: {
17
+ name: string;
18
+ queue: string;
19
+ payload: unknown;
20
+ options: DispatchOptions;
21
+ }): DispatchedJob | Promise<DispatchedJob>;
22
+ find?(job: {
23
+ name: string;
24
+ queue: string;
25
+ id: string;
26
+ }): JobSnapshot | undefined | Promise<JobSnapshot | undefined>;
27
+ };
28
+ /** Install an interceptor, or remove it with `undefined`. */
29
+ export declare function setDispatchInterceptor(interceptor: DispatchInterceptor | undefined): void;
30
+ /** The installed interceptor, if any. */
31
+ export declare function getDispatchInterceptor(): DispatchInterceptor | undefined;
32
+ //#endregion
33
+ //# sourceMappingURL=dispatch-interceptor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-interceptor.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/dispatch-interceptor.ts"],"mappings":";;;;;;;;;;;;;;YAcY;EACV,SAAS;IACP;IACA;IACA;IACA,SAAS;MACP,gBAAgB,QAAQ;EAC5B,MAAM;IACJ;IACA;IACA;MACE,0BAA0B,QAAQ;;;wBAQxB,uBAAuB,aAAa;;wBAKpC,0BAA0B"}
@@ -0,0 +1,14 @@
1
+ //#region ../../packages/queue/src/dispatch-interceptor.ts
2
+ const INTERCEPTOR_KEY = Symbol.for("warlock.queue.dispatchInterceptor");
3
+ /** Install an interceptor, or remove it with `undefined`. */
4
+ function setDispatchInterceptor(interceptor) {
5
+ globalThis[INTERCEPTOR_KEY] = interceptor;
6
+ }
7
+ /** The installed interceptor, if any. */
8
+ function getDispatchInterceptor() {
9
+ return globalThis[INTERCEPTOR_KEY];
10
+ }
11
+
12
+ //#endregion
13
+ export { getDispatchInterceptor, setDispatchInterceptor };
14
+ //# sourceMappingURL=dispatch-interceptor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-interceptor.mjs","names":[],"sources":["../../../../../../../packages/queue/src/dispatch-interceptor.ts"],"sourcesContent":["import type { DispatchOptions, DispatchedJob, JobSnapshot } from \"./types\";\n\n/**\n * A stand-in for the broker, used by test fakes.\n *\n * When one is installed, `job.dispatch()` hands the job to it instead of\n * adding it to BullMQ, and `job.find()` asks it instead of Redis. Nothing\n * connects to Redis while it is installed.\n *\n * `@warlock.js/core/tests` installs one as `queueFake` in the test\n * environment; this package exposes the seam so core needs no dependency on\n * it. The slot lives on `globalThis` so every copy of this package in a\n * process (a Vitest worker can load two) sees the same one.\n */\nexport type DispatchInterceptor = {\n dispatch(job: {\n name: string;\n queue: string;\n payload: unknown;\n options: DispatchOptions;\n }): DispatchedJob | Promise<DispatchedJob>;\n find?(job: {\n name: string;\n queue: string;\n id: string;\n }): JobSnapshot | undefined | Promise<JobSnapshot | undefined>;\n};\n\nconst INTERCEPTOR_KEY = Symbol.for(\"warlock.queue.dispatchInterceptor\");\n\ntype InterceptorHolder = { [INTERCEPTOR_KEY]?: DispatchInterceptor };\n\n/** Install an interceptor, or remove it with `undefined`. */\nexport function setDispatchInterceptor(interceptor: DispatchInterceptor | undefined): void {\n (globalThis as InterceptorHolder)[INTERCEPTOR_KEY] = interceptor;\n}\n\n/** The installed interceptor, if any. */\nexport function getDispatchInterceptor(): DispatchInterceptor | undefined {\n return (globalThis as InterceptorHolder)[INTERCEPTOR_KEY];\n}\n"],"mappings":";AA4BA,MAAM,kBAAkB,OAAO,IAAI,mCAAmC;;AAKtE,SAAgB,uBAAuB,aAAoD;CACzF,AAAC,WAAiC,mBAAmB;AACvD;;AAGA,SAAgB,yBAA0D;CACxE,OAAQ,WAAiC;AAC3C"}
@@ -1,11 +1,9 @@
1
1
  import { Duration } from "./types.mjs";
2
-
3
2
  //#region ../../packages/queue/src/duration.d.ts
4
3
  /**
5
4
  * Convert a {@link Duration} to milliseconds. Numbers are already
6
5
  * milliseconds. Anything else is rejected loudly rather than guessed at.
7
6
  */
8
- declare function toMilliseconds(value: Duration | string): number;
7
+ export declare function toMilliseconds(value: Duration | string): number;
9
8
  //#endregion
10
- export { toMilliseconds };
11
9
  //# sourceMappingURL=duration.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"duration.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/duration.ts"],"mappings":";;;;;AAiBA;;iBAAgB,cAAA,CAAe,KAAwB,EAAjB,QAAQ"}
1
+ {"version":3,"file":"duration.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/duration.ts"],"mappings":";;;;;;wBAiBgB,eAAe,OAAO"}
package/esm/errors.d.mts CHANGED
@@ -3,43 +3,42 @@
3
3
  * Thrown when the queue is used before `setQueueConfig` (or the queue
4
4
  * connector) supplied a configuration.
5
5
  */
6
- declare class QueueNotConfiguredError extends Error {
6
+ export declare class QueueNotConfiguredError extends Error {
7
7
  constructor();
8
8
  }
9
9
  /**
10
10
  * Thrown for a malformed duration such as `"10 minutes"`.
11
11
  */
12
- declare class InvalidDurationError extends Error {
12
+ export declare class InvalidDurationError extends Error {
13
13
  constructor(value: unknown);
14
14
  }
15
15
  /**
16
16
  * Thrown by `defineJob` for an invalid definition.
17
17
  */
18
- declare class InvalidJobDefinitionError extends Error {
18
+ export declare class InvalidJobDefinitionError extends Error {
19
19
  constructor(message: string);
20
20
  }
21
21
  /**
22
22
  * Thrown by `retryFailedJob` when no failed job has the given id.
23
23
  */
24
- declare class FailedJobNotFoundError extends Error {
24
+ export declare class FailedJobNotFoundError extends Error {
25
25
  constructor(id: string, queue: string);
26
26
  }
27
27
  /**
28
28
  * Thrown by `queueDashboard` when an optional bull-board package is not
29
29
  * installed.
30
30
  */
31
- declare class QueueDashboardDependencyError extends Error {
31
+ export declare class QueueDashboardDependencyError extends Error {
32
32
  constructor(missing: string);
33
33
  }
34
34
  /**
35
35
  * Throw from a job handler (or a queue context's `restore`) to fail the job
36
36
  * permanently — it is not retried, whatever `attempts` allows.
37
37
  */
38
- declare class UnrecoverableJobError extends Error {
38
+ export declare class UnrecoverableJobError extends Error {
39
39
  constructor(message: string, options?: {
40
40
  cause?: unknown;
41
41
  });
42
42
  }
43
43
  //#endregion
44
- export { FailedJobNotFoundError, InvalidDurationError, InvalidJobDefinitionError, QueueDashboardDependencyError, QueueNotConfiguredError, UnrecoverableJobError };
45
44
  //# sourceMappingURL=errors.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/errors.ts"],"mappings":";;AAIA;;;cAAa,uBAAA,SAAgC,KAAK;EAAL,WAAA;AAAA;;;;cAchC,oBAAA,SAA6B,KAAK;cAC1B,KAAA;AAAA;;AAAc;AAYnC;cAAa,yBAAA,SAAkC,KAAK;cAC/B,OAAA;AAAA;;;;cASR,sBAAA,SAA+B,KAAK;cAC5B,EAAA,UAAY,KAAA;AAAA;;;;;cAUpB,6BAAA,SAAsC,KAAK;cACnC,OAAA;AAAA;;AAXyB;AAU9C;;cAea,qBAAA,SAA8B,KAAK;cAC3B,OAAA,UAAiB,OAAA;IAAY,KAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"errors.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/errors.ts"],"mappings":";;;;;qBAIa,gCAAgC;EAC3C;;;;;qBAaW,6BAA6B;EACxC,YAAmB;;;;;qBAYR,kCAAkC;EAC7C,YAAmB;;;;;qBASR,+BAA+B;EAC1C,YAAmB,YAAY;;;;;;qBAUpB,sCAAsC;EACjD,YAAmB;;;;;;qBAcR,8BAA8B;EACzC,YAAmB,iBAAiB;IAAY"}
@@ -1,23 +1,24 @@
1
1
  import { FailedJob } from "./types.mjs";
2
-
3
2
  //#region ../../packages/queue/src/failed-jobs.d.ts
4
- type FailedJobsOptions = {
5
- /** Queue to read. Default: the default queue. */queue?: string; /** First index (newest first). Default `0`. */
6
- start?: number; /** Last index, inclusive. Default `99`. */
3
+ export type FailedJobsOptions = {
4
+ /** Queue to read. Default: the default queue. */
5
+ queue?: string;
6
+ /** First index (newest first). Default `0`. */
7
+ start?: number;
8
+ /** Last index, inclusive. Default `99`. */
7
9
  end?: number;
8
10
  };
9
11
  /**
10
12
  * List failed jobs, newest first — jobs that used up every attempt, or
11
13
  * failed unrecoverably. Each entry can be retried.
12
14
  */
13
- declare function failedJobs(options?: FailedJobsOptions): Promise<FailedJob[]>;
15
+ export declare function failedJobs(options?: FailedJobsOptions): Promise<FailedJob[]>;
14
16
  /**
15
17
  * Retry one failed job by id: it goes back to waiting with its attempts reset.
16
18
  * Throws {@link FailedJobNotFoundError} when no FAILED job has that id.
17
19
  */
18
- declare function retryFailedJob(id: string, options?: {
20
+ export declare function retryFailedJob(id: string, options?: {
19
21
  queue?: string;
20
22
  }): Promise<void>;
21
23
  //#endregion
22
- export { FailedJobsOptions, failedJobs, retryFailedJob };
23
24
  //# sourceMappingURL=failed-jobs.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"failed-jobs.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/failed-jobs.ts"],"mappings":";;;KAOY,iBAAA;mDAEV,KAAA,WAF2B;EAI3B,KAAA,WAJ2B;EAM3B,GAAA;AAAA;;;AAAG;AAOL;iBAAsB,UAAA,CAAW,OAAA,GAAS,iBAAA,GAAyB,OAAA,CAAQ,SAAA;;;;;iBAWrD,cAAA,CAAe,EAAA,UAAY,OAAA;EAAW,KAAA;AAAA,IAAwB,OAAO"}
1
+ {"version":3,"file":"failed-jobs.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/failed-jobs.ts"],"mappings":";;YAOY;;EAEV;;EAEA;;EAEA;;;;;;wBAOoB,WAAW,UAAS,oBAAyB,QAAQ;;;;;wBAWrD,eAAe,YAAY;EAAW;IAAwB"}
@@ -9,7 +9,8 @@ import { getQueue } from "./queue-manager.mjs";
9
9
  * failed unrecoverably. Each entry can be retried.
10
10
  */
11
11
  async function failedJobs(options = {}) {
12
- return (await getQueue(options.queue ?? defaultQueueName()).getFailed(options.start ?? 0, options.end ?? 99)).map((job) => toFailedJob(job));
12
+ const queueName = options.queue ?? defaultQueueName();
13
+ return (await getQueue(queueName).getFailed(options.start ?? 0, options.end ?? 99)).map((job) => toFailedJob(job));
13
14
  }
14
15
  /**
15
16
  * Retry one failed job by id: it goes back to waiting with its attempts reset.
@@ -1 +1 @@
1
- {"version":3,"file":"failed-jobs.mjs","names":[],"sources":["../../../../../../../packages/queue/src/failed-jobs.ts"],"sourcesContent":["import { unwrapPayload } from \"./queue-context\";\nimport type { Job } from \"bullmq\";\nimport { defaultQueueName } from \"./config\";\nimport { FailedJobNotFoundError } from \"./errors\";\nimport { getQueue } from \"./queue-manager\";\nimport type { FailedJob } from \"./types\";\n\nexport type FailedJobsOptions = {\n /** Queue to read. Default: the default queue. */\n queue?: string;\n /** First index (newest first). Default `0`. */\n start?: number;\n /** Last index, inclusive. Default `99`. */\n end?: number;\n};\n\n/**\n * List failed jobs, newest first — jobs that used up every attempt, or\n * failed unrecoverably. Each entry can be retried.\n */\nexport async function failedJobs(options: FailedJobsOptions = {}): Promise<FailedJob[]> {\n const queueName = options.queue ?? defaultQueueName();\n const jobs = await getQueue(queueName).getFailed(options.start ?? 0, options.end ?? 99);\n\n return jobs.map((job) => toFailedJob(job));\n}\n\n/**\n * Retry one failed job by id: it goes back to waiting with its attempts reset.\n * Throws {@link FailedJobNotFoundError} when no FAILED job has that id.\n */\nexport async function retryFailedJob(id: string, options: { queue?: string } = {}): Promise<void> {\n const queueName = options.queue ?? defaultQueueName();\n const job = await getQueue(queueName).getJob(id);\n\n if (!job || !(await job.isFailed())) {\n throw new FailedJobNotFoundError(id, queueName);\n }\n\n await job.retry(\"failed\");\n}\n\nfunction toFailedJob(job: Job): FailedJob {\n return {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n payload: unwrapPayload(job.data).payload,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n stacktrace: job.stacktrace ?? [],\n failedAt: job.finishedOn ? new Date(job.finishedOn) : undefined,\n retry: () => job.retry(\"failed\"),\n };\n}\n"],"mappings":";;;;;;;;;;AAoBA,eAAsB,WAAW,UAA6B,CAAC,GAAyB;CAItF,QAAO,MAFY,SADD,QAAQ,SAAS,iBAAiB,CACf,CAAC,CAAC,UAAU,QAAQ,SAAS,GAAG,QAAQ,OAAO,EAAE,EAE3E,CAAC,KAAK,QAAQ,YAAY,GAAG,CAAC;AAC3C;;;;;AAMA,eAAsB,eAAe,IAAY,UAA8B,CAAC,GAAkB;CAChG,MAAM,YAAY,QAAQ,SAAS,iBAAiB;CACpD,MAAM,MAAM,MAAM,SAAS,SAAS,CAAC,CAAC,OAAO,EAAE;CAE/C,IAAI,CAAC,OAAO,CAAE,MAAM,IAAI,SAAS,GAC/B,MAAM,IAAI,uBAAuB,IAAI,SAAS;CAGhD,MAAM,IAAI,MAAM,QAAQ;AAC1B;AAEA,SAAS,YAAY,KAAqB;CACxC,OAAO;EACL,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,SAAS,cAAc,IAAI,IAAI,CAAC,CAAC;EACjC,cAAc,IAAI;EAClB,cAAc,IAAI;EAClB,YAAY,IAAI,cAAc,CAAC;EAC/B,UAAU,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;EACtD,aAAa,IAAI,MAAM,QAAQ;CACjC;AACF"}
1
+ {"version":3,"file":"failed-jobs.mjs","names":[],"sources":["../../../../../../../packages/queue/src/failed-jobs.ts"],"sourcesContent":["import { unwrapPayload } from \"./queue-context\";\nimport type { Job } from \"bullmq\";\nimport { defaultQueueName } from \"./config\";\nimport { FailedJobNotFoundError } from \"./errors\";\nimport { getQueue } from \"./queue-manager\";\nimport type { FailedJob } from \"./types\";\n\nexport type FailedJobsOptions = {\n /** Queue to read. Default: the default queue. */\n queue?: string;\n /** First index (newest first). Default `0`. */\n start?: number;\n /** Last index, inclusive. Default `99`. */\n end?: number;\n};\n\n/**\n * List failed jobs, newest first — jobs that used up every attempt, or\n * failed unrecoverably. Each entry can be retried.\n */\nexport async function failedJobs(options: FailedJobsOptions = {}): Promise<FailedJob[]> {\n const queueName = options.queue ?? defaultQueueName();\n const jobs = await getQueue(queueName).getFailed(options.start ?? 0, options.end ?? 99);\n\n return jobs.map((job) => toFailedJob(job));\n}\n\n/**\n * Retry one failed job by id: it goes back to waiting with its attempts reset.\n * Throws {@link FailedJobNotFoundError} when no FAILED job has that id.\n */\nexport async function retryFailedJob(id: string, options: { queue?: string } = {}): Promise<void> {\n const queueName = options.queue ?? defaultQueueName();\n const job = await getQueue(queueName).getJob(id);\n\n if (!job || !(await job.isFailed())) {\n throw new FailedJobNotFoundError(id, queueName);\n }\n\n await job.retry(\"failed\");\n}\n\nfunction toFailedJob(job: Job): FailedJob {\n return {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n payload: unwrapPayload(job.data).payload,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n stacktrace: job.stacktrace ?? [],\n failedAt: job.finishedOn ? new Date(job.finishedOn) : undefined,\n retry: () => job.retry(\"failed\"),\n };\n}\n"],"mappings":";;;;;;;;;;AAoBA,eAAsB,WAAW,UAA6B,CAAC,GAAyB;CACtF,MAAM,YAAY,QAAQ,SAAS,iBAAiB;CAGpD,QAAO,MAFY,SAAS,SAAS,CAAC,CAAC,UAAU,QAAQ,SAAS,GAAG,QAAQ,OAAO,EAAE,EAE3E,CAAC,KAAK,QAAQ,YAAY,GAAG,CAAC;AAC3C;;;;;AAMA,eAAsB,eAAe,IAAY,UAA8B,CAAC,GAAkB;CAChG,MAAM,YAAY,QAAQ,SAAS,iBAAiB;CACpD,MAAM,MAAM,MAAM,SAAS,SAAS,CAAC,CAAC,OAAO,EAAE;CAE/C,IAAI,CAAC,OAAO,CAAE,MAAM,IAAI,SAAS,GAC/B,MAAM,IAAI,uBAAuB,IAAI,SAAS;CAGhD,MAAM,IAAI,MAAM,QAAQ;AAC1B;AAEA,SAAS,YAAY,KAAqB;CACxC,OAAO;EACL,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,SAAS,cAAc,IAAI,IAAI,CAAC,CAAC;EACjC,cAAc,IAAI;EAClB,cAAc,IAAI;EAClB,YAAY,IAAI,cAAc,CAAC;EAC/B,UAAU,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;EACtD,aAAa,IAAI,MAAM,QAAQ;CACjC;AACF"}
package/esm/index.d.mts CHANGED
@@ -3,11 +3,13 @@ import { defaultQueueName, getQueueConfig, resetQueueConfig, setQueueConfig } fr
3
3
  import { DashboardServer, QueueDashboardOptions, loadBullBoard, queueDashboard } from "./dashboard.mjs";
4
4
  import { DEFAULT_DASHBOARD_PATH, mountQueueDashboard } from "./dashboard-boot.mjs";
5
5
  import { defineJob } from "./define-job.mjs";
6
+ import { DispatchInterceptor, getDispatchInterceptor, setDispatchInterceptor } from "./dispatch-interceptor.mjs";
6
7
  import { toMilliseconds } from "./duration.mjs";
7
8
  import { FailedJobNotFoundError, InvalidDurationError, InvalidJobDefinitionError, QueueDashboardDependencyError, QueueNotConfiguredError, UnrecoverableJobError } from "./errors.mjs";
8
9
  import { FailedJobsOptions, failedJobs, retryFailedJob } from "./failed-jobs.mjs";
10
+ import { RegisteredJob, queueOf, registeredJobs } from "./job-registry.mjs";
9
11
  import { QUEUE_CONNECTOR_PRIORITY, QueueConnectorOptions, queueConnector } from "./queue-connector.mjs";
10
12
  import { QueueContext, defineQueueContext, getQueueContext, resetQueueContext, setQueueContext } from "./queue-context.mjs";
11
13
  import { QueueDashboardUnguardedError } from "./queue-dashboard-unguarded.error.mjs";
12
14
  import { CloseQueueOptions, closeQueue, getQueue, runningWorkers, startWorkers } from "./queue-manager.mjs";
13
- export { type CloseQueueOptions, DEFAULT_DASHBOARD_PATH, DashboardServer, DispatchOptions, DispatchedJob, Duration, DurationUnit, FailedJob, FailedJobNotFoundError, FailedJobsOptions, InvalidDurationError, InvalidJobDefinitionError, JobBackoff, JobContext, JobDefinition, JobOptions, JobProgress, JobRetention, JobSnapshot, JobState, QUEUE_CONNECTOR_PRIORITY, QueueConfig, QueueConnectorOptions, type QueueContext, QueueDashboardConfig, QueueDashboardDependencyError, QueueDashboardOptions, QueueDashboardUnguardedError, QueueJob, QueueNotConfiguredError, QueueWorkersConfig, UnrecoverableJobError, closeQueue, defaultQueueName, defineJob, defineQueueContext, failedJobs, getQueue, getQueueConfig, getQueueContext, loadBullBoard, mountQueueDashboard, queueConnector, queueDashboard, resetQueueConfig, resetQueueContext, retryFailedJob, runningWorkers, setQueueConfig, setQueueContext, startWorkers, toMilliseconds };
15
+ export { type CloseQueueOptions, DEFAULT_DASHBOARD_PATH, DashboardServer, type DispatchInterceptor, DispatchOptions, DispatchedJob, Duration, DurationUnit, FailedJob, FailedJobNotFoundError, FailedJobsOptions, InvalidDurationError, InvalidJobDefinitionError, JobBackoff, JobContext, JobDefinition, JobOptions, JobProgress, JobRetention, JobSnapshot, JobState, QUEUE_CONNECTOR_PRIORITY, QueueConfig, QueueConnectorOptions, type QueueContext, QueueDashboardConfig, QueueDashboardDependencyError, QueueDashboardOptions, QueueDashboardUnguardedError, QueueJob, QueueNotConfiguredError, QueueWorkersConfig, type RegisteredJob, UnrecoverableJobError, closeQueue, defaultQueueName, defineJob, defineQueueContext, failedJobs, getDispatchInterceptor, getQueue, getQueueConfig, getQueueContext, loadBullBoard, mountQueueDashboard, queueConnector, queueDashboard, queueOf, registeredJobs, resetQueueConfig, resetQueueContext, retryFailedJob, runningWorkers, setDispatchInterceptor, setQueueConfig, setQueueContext, startWorkers, toMilliseconds };
package/esm/index.mjs CHANGED
@@ -1,13 +1,15 @@
1
1
  import { FailedJobNotFoundError, InvalidDurationError, InvalidJobDefinitionError, QueueDashboardDependencyError, QueueNotConfiguredError, UnrecoverableJobError } from "./errors.mjs";
2
2
  import { defaultQueueName, getQueueConfig, resetQueueConfig, setQueueConfig } from "./config.mjs";
3
+ import { queueOf, registeredJobs } from "./job-registry.mjs";
3
4
  import { defineQueueContext, getQueueContext, resetQueueContext, setQueueContext } from "./queue-context.mjs";
4
5
  import { closeQueue, getQueue, runningWorkers, startWorkers } from "./queue-manager.mjs";
5
6
  import { loadBullBoard, queueDashboard } from "./dashboard.mjs";
6
7
  import { QueueDashboardUnguardedError } from "./queue-dashboard-unguarded.error.mjs";
7
8
  import { DEFAULT_DASHBOARD_PATH, mountQueueDashboard } from "./dashboard-boot.mjs";
9
+ import { getDispatchInterceptor, setDispatchInterceptor } from "./dispatch-interceptor.mjs";
8
10
  import { toMilliseconds } from "./duration.mjs";
9
11
  import { defineJob } from "./define-job.mjs";
10
12
  import { failedJobs, retryFailedJob } from "./failed-jobs.mjs";
11
13
  import { QUEUE_CONNECTOR_PRIORITY, queueConnector } from "./queue-connector.mjs";
12
14
 
13
- export { DEFAULT_DASHBOARD_PATH, FailedJobNotFoundError, InvalidDurationError, InvalidJobDefinitionError, QUEUE_CONNECTOR_PRIORITY, QueueDashboardDependencyError, QueueDashboardUnguardedError, QueueNotConfiguredError, UnrecoverableJobError, closeQueue, defaultQueueName, defineJob, defineQueueContext, failedJobs, getQueue, getQueueConfig, getQueueContext, loadBullBoard, mountQueueDashboard, queueConnector, queueDashboard, resetQueueConfig, resetQueueContext, retryFailedJob, runningWorkers, setQueueConfig, setQueueContext, startWorkers, toMilliseconds };
15
+ export { DEFAULT_DASHBOARD_PATH, FailedJobNotFoundError, InvalidDurationError, InvalidJobDefinitionError, QUEUE_CONNECTOR_PRIORITY, QueueDashboardDependencyError, QueueDashboardUnguardedError, QueueNotConfiguredError, UnrecoverableJobError, closeQueue, defaultQueueName, defineJob, defineQueueContext, failedJobs, getDispatchInterceptor, getQueue, getQueueConfig, getQueueContext, loadBullBoard, mountQueueDashboard, queueConnector, queueDashboard, queueOf, registeredJobs, resetQueueConfig, resetQueueContext, retryFailedJob, runningWorkers, setDispatchInterceptor, setQueueConfig, setQueueContext, startWorkers, toMilliseconds };
@@ -0,0 +1,10 @@
1
+ import { JobDefinition } from "./types.mjs";
2
+ //#region ../../packages/queue/src/job-registry.d.ts
3
+ /** A registered definition, payload/result erased for storage. */
4
+ export type RegisteredJob = JobDefinition<unknown, unknown>;
5
+ /** Every registered definition. */
6
+ export declare function registeredJobs(): RegisteredJob[];
7
+ /** The queue a definition runs on, resolved against the active config. */
8
+ export declare function queueOf(job: Pick<RegisteredJob, "queue">): string;
9
+ //#endregion
10
+ //# sourceMappingURL=job-registry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-registry.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/job-registry.ts"],"mappings":";;;YAIY,gBAAgB;;wBA8BZ,kBAAkB;;wBAKlB,QAAQ,KAAK,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"process-job.mjs","names":[],"sources":["../../../../../../../packages/queue/src/process-job.ts"],"sourcesContent":["import { type Job, UnrecoverableError } from \"bullmq\";\nimport { UnrecoverableJobError } from \"./errors\";\nimport { findRegisteredJob } from \"./job-registry\";\nimport { getQueueContext, unwrapPayload } from \"./queue-context\";\nimport type { JobContext } from \"./types\";\n\n/**\n * The single BullMQ processor every worker runs: route the job to the\n * handler registered under its name.\n *\n * A name with no handler in this process fails with `UnrecoverableError` —\n * retrying cannot make a missing definition appear, so it must not burn\n * through its attempts.\n */\nexport async function processJob(job: Job): Promise<unknown> {\n const definition = findRegisteredJob(job.name);\n\n if (!definition) {\n throw new UnrecoverableError(\n `No job named \"${job.name}\" is defined in this process. ` +\n \"Make sure the module that calls defineJob() is imported by the worker process.\",\n );\n }\n\n const { payload, context: captured } = unwrapPayload(job.data);\n\n const context: JobContext = {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n attempt: job.attemptsMade + 1,\n maxAttempts: job.opts.attempts ?? 1,\n progress: (value) => job.updateProgress(value),\n log: async (line) => {\n await job.log(line);\n },\n context: captured,\n };\n\n const run = async () => definition.handle(payload, context);\n const queueContext = getQueueContext();\n\n try {\n return captured !== undefined && queueContext ? await queueContext.restore(captured, run) : await run();\n } catch (error) {\n if (error instanceof UnrecoverableJobError) {\n throw new UnrecoverableError(error.message);\n }\n\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,eAAsB,WAAW,KAA4B;CAC3D,MAAM,aAAa,kBAAkB,IAAI,IAAI;CAE7C,IAAI,CAAC,YACH,MAAM,IAAI,mBACR,iBAAiB,IAAI,KAAK,6GAE5B;CAGF,MAAM,EAAE,SAAS,SAAS,aAAa,cAAc,IAAI,IAAI;CAE7D,MAAM,UAAsB;EAC1B,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,SAAS,IAAI,eAAe;EAC5B,aAAa,IAAI,KAAK,YAAY;EAClC,WAAW,UAAU,IAAI,eAAe,KAAK;EAC7C,KAAK,OAAO,SAAS;GACnB,MAAM,IAAI,IAAI,IAAI;EACpB;EACA,SAAS;CACX;CAEA,MAAM,MAAM,YAAY,WAAW,OAAO,SAAS,OAAO;CAC1D,MAAM,eAAe,gBAAgB;CAErC,IAAI;EACF,OAAO,aAAa,UAAa,eAAe,MAAM,aAAa,QAAQ,UAAU,GAAG,IAAI,MAAM,IAAI;CACxG,SAAS,OAAO;EACd,IAAI,iBAAiB,uBACnB,MAAM,IAAI,mBAAmB,MAAM,OAAO;EAG5C,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"process-job.mjs","names":[],"sources":["../../../../../../../packages/queue/src/process-job.ts"],"sourcesContent":["import { type Job, UnrecoverableError } from \"bullmq\";\nimport { UnrecoverableJobError } from \"./errors\";\nimport { findRegisteredJob } from \"./job-registry\";\nimport { getQueueContext, unwrapPayload } from \"./queue-context\";\nimport type { JobContext } from \"./types\";\n\n/**\n * The single BullMQ processor every worker runs: route the job to the\n * handler registered under its name.\n *\n * A name with no handler in this process fails with `UnrecoverableError` —\n * retrying cannot make a missing definition appear, so it must not burn\n * through its attempts.\n */\nexport async function processJob(job: Job): Promise<unknown> {\n const definition = findRegisteredJob(job.name);\n\n if (!definition) {\n throw new UnrecoverableError(\n `No job named \"${job.name}\" is defined in this process. ` +\n \"Make sure the module that calls defineJob() is imported by the worker process.\",\n );\n }\n\n const { payload, context: captured } = unwrapPayload(job.data);\n\n const context: JobContext = {\n id: String(job.id),\n name: job.name,\n queue: job.queueName,\n attempt: job.attemptsMade + 1,\n maxAttempts: job.opts.attempts ?? 1,\n progress: (value) => job.updateProgress(value),\n log: async (line) => {\n await job.log(line);\n },\n context: captured,\n };\n\n const run = async () => definition.handle(payload, context);\n const queueContext = getQueueContext();\n\n try {\n return captured !== undefined && queueContext\n ? await queueContext.restore(captured, run)\n : await run();\n } catch (error) {\n if (error instanceof UnrecoverableJobError) {\n throw new UnrecoverableError(error.message);\n }\n\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,eAAsB,WAAW,KAA4B;CAC3D,MAAM,aAAa,kBAAkB,IAAI,IAAI;CAE7C,IAAI,CAAC,YACH,MAAM,IAAI,mBACR,iBAAiB,IAAI,KAAK,6GAE5B;CAGF,MAAM,EAAE,SAAS,SAAS,aAAa,cAAc,IAAI,IAAI;CAE7D,MAAM,UAAsB;EAC1B,IAAI,OAAO,IAAI,EAAE;EACjB,MAAM,IAAI;EACV,OAAO,IAAI;EACX,SAAS,IAAI,eAAe;EAC5B,aAAa,IAAI,KAAK,YAAY;EAClC,WAAW,UAAU,IAAI,eAAe,KAAK;EAC7C,KAAK,OAAO,SAAS;GACnB,MAAM,IAAI,IAAI,IAAI;EACpB;EACA,SAAS;CACX;CAEA,MAAM,MAAM,YAAY,WAAW,OAAO,SAAS,OAAO;CAC1D,MAAM,eAAe,gBAAgB;CAErC,IAAI;EACF,OAAO,aAAa,UAAa,eAC7B,MAAM,aAAa,QAAQ,UAAU,GAAG,IACxC,MAAM,IAAI;CAChB,SAAS,OAAO;EACd,IAAI,iBAAiB,uBACnB,MAAM,IAAI,mBAAmB,MAAM,OAAO;EAG5C,MAAM;CACR;AACF"}
@@ -1,14 +1,13 @@
1
1
  import { QueueConfig } from "./types.mjs";
2
2
  import { Connector } from "@warlock.js/core";
3
-
4
3
  //#region ../../packages/queue/src/queue-connector.d.ts
5
4
  /**
6
5
  * Boots after every built-in connector (`ConnectorPriority.AI` is `10`), so
7
6
  * the logger is up and anything a job handler needs is already connected;
8
7
  * shuts down before them for the same reason.
9
8
  */
10
- declare const QUEUE_CONNECTOR_PRIORITY = 11;
11
- type QueueConnectorOptions = {
9
+ export declare const QUEUE_CONNECTOR_PRIORITY = 11;
10
+ export type QueueConnectorOptions = {
12
11
  /**
13
12
  * Supply the configuration directly instead of reading the `queue` config
14
13
  * key (`src/config/queue.ts`).
@@ -30,7 +29,6 @@ type QueueConnectorOptions = {
30
29
  *
31
30
  * export default defineConfig({ connectors: [queueConnector()] });
32
31
  */
33
- declare function queueConnector(options?: QueueConnectorOptions): Connector;
32
+ export declare function queueConnector(options?: QueueConnectorOptions): Connector;
34
33
  //#endregion
35
- export { QUEUE_CONNECTOR_PRIORITY, QueueConnectorOptions, queueConnector };
36
34
  //# sourceMappingURL=queue-connector.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-connector.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-connector.ts"],"mappings":";;;;;;;AA6BsB;AAkBtB;cA3Ba,wBAAA;AAAA,KAID,qBAAA;EAuBkE;;;;EAlB5E,MAAA,GAAS,WAAW;AAAA;;;;;;;;;;;;;;;;iBAkBN,cAAA,CAAe,OAAA,GAAS,qBAAA,GAA6B,SAAS"}
1
+ {"version":3,"file":"queue-connector.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-connector.ts"],"mappings":";;;;;;;;qBAoBa;YAID;;;;;EAKV,SAAS;;;;;;;;;;;;;;;;;wBAkBK,eAAe,UAAS,wBAA6B"}
@@ -1 +1 @@
1
- {"version":3,"file":"queue-connector.mjs","names":[],"sources":["../../../../../../../packages/queue/src/queue-connector.ts"],"sourcesContent":["/**\n * The queue's connector for `warlock.config.ts > connectors`.\n *\n * Deliberately a plain object with TYPE-ONLY imports from core: the config\n * file that constructs it must not drag core's runtime graph (or BullMQ) in\n * at config-load time. Core is imported lazily inside `start()`, where the\n * app has already loaded it.\n */\nimport type { Connector, ConnectorLifecyclePhase } from \"@warlock.js/core\";\nimport { log } from \"@warlock.js/logger\";\nimport { resetQueueConfig, setQueueConfig } from \"./config\";\nimport { mountQueueDashboard } from \"./dashboard-boot\";\nimport { closeQueue, startWorkers } from \"./queue-manager\";\nimport type { QueueConfig } from \"./types\";\n\n/**\n * Boots after every built-in connector (`ConnectorPriority.AI` is `10`), so\n * the logger is up and anything a job handler needs is already connected;\n * shuts down before them for the same reason.\n */\nexport const QUEUE_CONNECTOR_PRIORITY = 11;\n\nconst WATCHED_FILES = [\"src/config/queue.ts\"];\n\nexport type QueueConnectorOptions = {\n /**\n * Supply the configuration directly instead of reading the `queue` config\n * key (`src/config/queue.ts`).\n */\n config?: QueueConfig;\n};\n\n/**\n * Construct the queue connector.\n *\n * Runs in the `late` lifecycle phase — after app code is imported — so every\n * `defineJob` in the app has registered before workers start. At start it\n * reads the `queue` config and starts in-process workers unless\n * `workers.enabled` is `false`; at shutdown it closes workers (waiting for\n * active jobs, bounded by `workers.shutdownTimeout`) and then the queues.\n *\n * @example\n * // warlock.config.ts\n * import { queueConnector } from \"@warlock.js/queue\";\n *\n * export default defineConfig({ connectors: [queueConnector()] });\n */\nexport function queueConnector(options: QueueConnectorOptions = {}): Connector {\n let active = false;\n\n const connector: Connector = {\n name: \"queue\",\n priority: QUEUE_CONNECTOR_PRIORITY,\n // Core's `ConnectorLifecyclePhase.Late`; the value is spelled out so this\n // module stays free of a runtime import of core.\n lifecyclePhase: \"late\" as ConnectorLifecyclePhase,\n isActive: () => active,\n /**\n * Mounts the dashboard, when configured, here rather than in `start()`:\n * `boot()` runs for every late-phase connector, in priority order, before\n * any of them `start()`s — so by the time this runs, the HTTP connector\n * (priority 5, before queue's 11) has already built its Fastify instance\n * and registered its own plugins, but has not yet called `listen()`.\n * Fastify refuses new plugin registrations after `listen()`, so this is\n * the only point in the boot sequence where mounting is possible.\n */\n async boot() {\n const queueConfig = options.config ?? (await readQueueConfig());\n\n if (!queueConfig?.dashboard?.enabled) {\n return;\n }\n\n // The dashboard resolves queues through the active config, so it has to\n // be registered here rather than only in `start()`, which runs after\n // every late connector has booted. `start()` sets it again; the setter\n // is idempotent for the same object.\n setQueueConfig(queueConfig);\n\n const { getHttpServer } = await import(\"@warlock.js/core\");\n\n await mountQueueDashboard(getHttpServer(), queueConfig);\n },\n async start() {\n const queueConfig = options.config ?? (await readQueueConfig());\n\n if (!queueConfig) {\n log.warn(\n \"queue\",\n \"configured\",\n \"queueConnector() is registered but no `queue` config was found (src/config/queue.ts); queue not started\",\n );\n return;\n }\n\n setQueueConfig(queueConfig);\n const started = await startWorkers();\n active = true;\n\n log.info(\n \"queue\",\n \"configured\",\n started.length > 0\n ? `Queue workers running for: ${started.join(\", \")}`\n : \"Queue configured (no in-process workers)\",\n );\n },\n async restart() {\n await connector.shutdown();\n await connector.start();\n },\n async shutdown() {\n if (!active) {\n return;\n }\n\n await closeQueue();\n resetQueueConfig();\n active = false;\n },\n shouldRestart(changedFiles) {\n return changedFiles.some((file) => {\n const normalized = file.replace(/\\\\/g, \"/\");\n\n return WATCHED_FILES.some((watched) => normalized === watched || normalized.endsWith(`/${watched}`));\n });\n },\n };\n\n return connector;\n}\n\nasync function readQueueConfig(): Promise<QueueConfig | undefined> {\n const { config } = await import(\"@warlock.js/core\");\n\n return config.get<QueueConfig | undefined>(\"queue\");\n}\n"],"mappings":";;;;;;;;;;;AAoBA,MAAa,2BAA2B;AAExC,MAAM,gBAAgB,CAAC,qBAAqB;;;;;;;;;;;;;;;;AAyB5C,SAAgB,eAAe,UAAiC,CAAC,GAAc;CAC7E,IAAI,SAAS;CAEb,MAAM,YAAuB;EAC3B,MAAM;EACN;EAGA,gBAAgB;EAChB,gBAAgB;;;;;;;;;;EAUhB,MAAM,OAAO;GACX,MAAM,cAAc,QAAQ,UAAW,MAAM,gBAAgB;GAE7D,IAAI,CAAC,aAAa,WAAW,SAC3B;GAOF,eAAe,WAAW;GAE1B,MAAM,EAAE,kBAAkB,MAAM,OAAO;GAEvC,MAAM,oBAAoB,cAAc,GAAG,WAAW;EACxD;EACA,MAAM,QAAQ;GACZ,MAAM,cAAc,QAAQ,UAAW,MAAM,gBAAgB;GAE7D,IAAI,CAAC,aAAa;IAChB,IAAI,KACF,SACA,cACA,yGACF;IACA;GACF;GAEA,eAAe,WAAW;GAC1B,MAAM,UAAU,MAAM,aAAa;GACnC,SAAS;GAET,IAAI,KACF,SACA,cACA,QAAQ,SAAS,IACb,8BAA8B,QAAQ,KAAK,IAAI,MAC/C,0CACN;EACF;EACA,MAAM,UAAU;GACd,MAAM,UAAU,SAAS;GACzB,MAAM,UAAU,MAAM;EACxB;EACA,MAAM,WAAW;GACf,IAAI,CAAC,QACH;GAGF,MAAM,WAAW;GACjB,iBAAiB;GACjB,SAAS;EACX;EACA,cAAc,cAAc;GAC1B,OAAO,aAAa,MAAM,SAAS;IACjC,MAAM,aAAa,KAAK,QAAQ,OAAO,GAAG;IAE1C,OAAO,cAAc,MAAM,YAAY,eAAe,WAAW,WAAW,SAAS,IAAI,SAAS,CAAC;GACrG,CAAC;EACH;CACF;CAEA,OAAO;AACT;AAEA,eAAe,kBAAoD;CACjE,MAAM,EAAE,WAAW,MAAM,OAAO;CAEhC,OAAO,OAAO,IAA6B,OAAO;AACpD"}
1
+ {"version":3,"file":"queue-connector.mjs","names":[],"sources":["../../../../../../../packages/queue/src/queue-connector.ts"],"sourcesContent":["/**\n * The queue's connector for `warlock.config.ts > connectors`.\n *\n * Deliberately a plain object with TYPE-ONLY imports from core: the config\n * file that constructs it must not drag core's runtime graph (or BullMQ) in\n * at config-load time. Core is imported lazily inside `start()`, where the\n * app has already loaded it.\n */\nimport type { Connector, ConnectorLifecyclePhase } from \"@warlock.js/core\";\nimport { log } from \"@warlock.js/logger\";\nimport { resetQueueConfig, setQueueConfig } from \"./config\";\nimport { mountQueueDashboard } from \"./dashboard-boot\";\nimport { closeQueue, startWorkers } from \"./queue-manager\";\nimport type { QueueConfig } from \"./types\";\n\n/**\n * Boots after every built-in connector (`ConnectorPriority.AI` is `10`), so\n * the logger is up and anything a job handler needs is already connected;\n * shuts down before them for the same reason.\n */\nexport const QUEUE_CONNECTOR_PRIORITY = 11;\n\nconst WATCHED_FILES = [\"src/config/queue.ts\"];\n\nexport type QueueConnectorOptions = {\n /**\n * Supply the configuration directly instead of reading the `queue` config\n * key (`src/config/queue.ts`).\n */\n config?: QueueConfig;\n};\n\n/**\n * Construct the queue connector.\n *\n * Runs in the `late` lifecycle phase — after app code is imported — so every\n * `defineJob` in the app has registered before workers start. At start it\n * reads the `queue` config and starts in-process workers unless\n * `workers.enabled` is `false`; at shutdown it closes workers (waiting for\n * active jobs, bounded by `workers.shutdownTimeout`) and then the queues.\n *\n * @example\n * // warlock.config.ts\n * import { queueConnector } from \"@warlock.js/queue\";\n *\n * export default defineConfig({ connectors: [queueConnector()] });\n */\nexport function queueConnector(options: QueueConnectorOptions = {}): Connector {\n let active = false;\n\n const connector: Connector = {\n name: \"queue\",\n priority: QUEUE_CONNECTOR_PRIORITY,\n // Core's `ConnectorLifecyclePhase.Late`; the value is spelled out so this\n // module stays free of a runtime import of core.\n lifecyclePhase: \"late\" as ConnectorLifecyclePhase,\n isActive: () => active,\n /**\n * Mounts the dashboard, when configured, here rather than in `start()`:\n * `boot()` runs for every late-phase connector, in priority order, before\n * any of them `start()`s — so by the time this runs, the HTTP connector\n * (priority 5, before queue's 11) has already built its Fastify instance\n * and registered its own plugins, but has not yet called `listen()`.\n * Fastify refuses new plugin registrations after `listen()`, so this is\n * the only point in the boot sequence where mounting is possible.\n */\n async boot() {\n const queueConfig = options.config ?? (await readQueueConfig());\n\n if (!queueConfig?.dashboard?.enabled) {\n return;\n }\n\n // The dashboard resolves queues through the active config, so it has to\n // be registered here rather than only in `start()`, which runs after\n // every late connector has booted. `start()` sets it again; the setter\n // is idempotent for the same object.\n setQueueConfig(queueConfig);\n\n const { getHttpServer } = await import(\"@warlock.js/core\");\n\n await mountQueueDashboard(getHttpServer(), queueConfig);\n },\n async start() {\n const queueConfig = options.config ?? (await readQueueConfig());\n\n if (!queueConfig) {\n log.warn(\n \"queue\",\n \"configured\",\n \"queueConnector() is registered but no `queue` config was found (src/config/queue.ts); queue not started\",\n );\n return;\n }\n\n setQueueConfig(queueConfig);\n const started = await startWorkers();\n active = true;\n\n log.info(\n \"queue\",\n \"configured\",\n started.length > 0\n ? `Queue workers running for: ${started.join(\", \")}`\n : \"Queue configured (no in-process workers)\",\n );\n },\n async restart() {\n await connector.shutdown();\n await connector.start();\n },\n async shutdown() {\n if (!active) {\n return;\n }\n\n await closeQueue();\n resetQueueConfig();\n active = false;\n },\n shouldRestart(changedFiles) {\n return changedFiles.some((file) => {\n const normalized = file.replace(/\\\\/g, \"/\");\n\n return WATCHED_FILES.some(\n (watched) => normalized === watched || normalized.endsWith(`/${watched}`),\n );\n });\n },\n };\n\n return connector;\n}\n\nasync function readQueueConfig(): Promise<QueueConfig | undefined> {\n const { config } = await import(\"@warlock.js/core\");\n\n return config.get<QueueConfig | undefined>(\"queue\");\n}\n"],"mappings":";;;;;;;;;;;AAoBA,MAAa,2BAA2B;AAExC,MAAM,gBAAgB,CAAC,qBAAqB;;;;;;;;;;;;;;;;AAyB5C,SAAgB,eAAe,UAAiC,CAAC,GAAc;CAC7E,IAAI,SAAS;CAEb,MAAM,YAAuB;EAC3B,MAAM;EACN;EAGA,gBAAgB;EAChB,gBAAgB;;;;;;;;;;EAUhB,MAAM,OAAO;GACX,MAAM,cAAc,QAAQ,UAAW,MAAM,gBAAgB;GAE7D,IAAI,CAAC,aAAa,WAAW,SAC3B;GAOF,eAAe,WAAW;GAE1B,MAAM,EAAE,kBAAkB,MAAM,OAAO;GAEvC,MAAM,oBAAoB,cAAc,GAAG,WAAW;EACxD;EACA,MAAM,QAAQ;GACZ,MAAM,cAAc,QAAQ,UAAW,MAAM,gBAAgB;GAE7D,IAAI,CAAC,aAAa;IAChB,IAAI,KACF,SACA,cACA,yGACF;IACA;GACF;GAEA,eAAe,WAAW;GAC1B,MAAM,UAAU,MAAM,aAAa;GACnC,SAAS;GAET,IAAI,KACF,SACA,cACA,QAAQ,SAAS,IACb,8BAA8B,QAAQ,KAAK,IAAI,MAC/C,0CACN;EACF;EACA,MAAM,UAAU;GACd,MAAM,UAAU,SAAS;GACzB,MAAM,UAAU,MAAM;EACxB;EACA,MAAM,WAAW;GACf,IAAI,CAAC,QACH;GAGF,MAAM,WAAW;GACjB,iBAAiB;GACjB,SAAS;EACX;EACA,cAAc,cAAc;GAC1B,OAAO,aAAa,MAAM,SAAS;IACjC,MAAM,aAAa,KAAK,QAAQ,OAAO,GAAG;IAE1C,OAAO,cAAc,MAClB,YAAY,eAAe,WAAW,WAAW,SAAS,IAAI,SAAS,CAC1E;GACF,CAAC;EACH;CACF;CAEA,OAAO;AACT;AAEA,eAAe,kBAAoD;CACjE,MAAM,EAAE,WAAW,MAAM,OAAO;CAEhC,OAAO,OAAO,IAA6B,OAAO;AACpD"}
@@ -3,8 +3,10 @@
3
3
  * Carries ambient state (tenant, request id, …) from the code that
4
4
  * dispatches a job into the worker that runs it.
5
5
  */
6
- type QueueContext<T> = {
7
- /** Read the ambient state at dispatch time; `undefined` means nothing to carry. */capture: () => T | undefined; /** Run `run` with the captured state re-established. */
6
+ export type QueueContext<T> = {
7
+ /** Read the ambient state at dispatch time; `undefined` means nothing to carry. */
8
+ capture: () => T | undefined;
9
+ /** Run `run` with the captured state re-established. */
8
10
  restore: (captured: T, run: () => Promise<unknown>) => Promise<unknown>;
9
11
  };
10
12
  /**
@@ -18,13 +20,12 @@ type QueueContext<T> = {
18
20
  * }),
19
21
  * );
20
22
  */
21
- declare function defineQueueContext<T>(context: QueueContext<T>): QueueContext<T>;
23
+ export declare function defineQueueContext<T>(context: QueueContext<T>): QueueContext<T>;
22
24
  /** Register the queue context used by every job dispatch and run. */
23
- declare function setQueueContext(context: QueueContext<any>): void;
25
+ export declare function setQueueContext(context: QueueContext<any>): void;
24
26
  /** The registered queue context, if any. */
25
- declare function getQueueContext(): QueueContext<any> | undefined;
27
+ export declare function getQueueContext(): QueueContext<any> | undefined;
26
28
  /** Forget the registered queue context. */
27
- declare function resetQueueContext(): void;
29
+ export declare function resetQueueContext(): void;
28
30
  //#endregion
29
- export { QueueContext, defineQueueContext, getQueueContext, resetQueueContext, setQueueContext };
30
31
  //# sourceMappingURL=queue-context.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-context.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-context.ts"],"mappings":";;AAIA;;;KAAY,YAAA;EAIU,mFAFpB,OAAA,QAAe,CAAA,cAEwC;EAAvD,OAAA,GAAU,QAAA,EAAU,CAAA,EAAG,GAAA,QAAW,OAAA,cAAqB,OAAA;AAAA;;;;;;;;;;;AAAO;iBAchD,kBAAA,IAAsB,OAAA,EAAS,YAAA,CAAa,CAAA,IAAK,YAAA,CAAa,CAAA;;iBAO9D,eAAA,CAAgB,OAA0B,EAAjB,YAAY;;iBAKrC,eAAA,IAAmB,YAAY;;iBAK/B,iBAAA"}
1
+ {"version":3,"file":"queue-context.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-context.ts"],"mappings":";;;;;YAIY,aAAa;;EAEvB,eAAe;;EAEf,UAAU,UAAU,GAAG,WAAW,qBAAqB;;;;;;;;;;;;;wBAczC,mBAAmB,GAAG,SAAS,aAAa,KAAK,aAAa;;wBAO9D,gBAAgB,SAAS;;wBAKzB,mBAAmB;;wBAKnB"}
@@ -5,9 +5,8 @@
5
5
  * on the open internet without a guard is a production incident waiting to
6
6
  * happen, so this fails the boot instead of shipping the hole.
7
7
  */
8
- declare class QueueDashboardUnguardedError extends Error {
8
+ export declare class QueueDashboardUnguardedError extends Error {
9
9
  constructor();
10
10
  }
11
11
  //#endregion
12
- export { QueueDashboardUnguardedError };
13
12
  //# sourceMappingURL=queue-dashboard-unguarded.error.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-dashboard-unguarded.error.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-dashboard-unguarded.error.ts"],"mappings":";;AAMA;;;;;cAAa,4BAAA,SAAqC,KAAK;EAAL,WAAA;AAAA"}
1
+ {"version":3,"file":"queue-dashboard-unguarded.error.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-dashboard-unguarded.error.ts"],"mappings":";;;;;;;qBAMa,qCAAqC;EAChD"}
@@ -1 +1 @@
1
- {"version":3,"file":"queue-dashboard-unguarded.error.mjs","names":[],"sources":["../../../../../../../packages/queue/src/queue-dashboard-unguarded.error.ts"],"sourcesContent":["/**\n * Thrown at boot when `queue.dashboard.enabled` is `true` in production with\n * no guard middleware. The dashboard can retry and delete jobs; mounting it\n * on the open internet without a guard is a production incident waiting to\n * happen, so this fails the boot instead of shipping the hole.\n */\nexport class QueueDashboardUnguardedError extends Error {\n public constructor() {\n super(\n \"queue.dashboard.enabled is true in production with no middleware. The dashboard can \" +\n \"retry and delete jobs, so it must be guarded before it is exposed.\\n\\n\" +\n \"Add a guard middleware:\\n\\n\" +\n \" import { middleware } from \\\"@warlock.js/core\\\";\\n\" +\n \" import { authMiddleware } from \\\"@warlock.js/auth\\\";\\n\\n\" +\n \" const queueConfig: QueueConfig = {\\n\" +\n \" // ...\\n\" +\n \" dashboard: {\\n\" +\n \" enabled: true,\\n\" +\n \" middleware: [authMiddleware(\\\"admin\\\")],\\n\" +\n \" },\\n\" +\n \" };\\n\",\n );\n this.name = \"QueueDashboardUnguardedError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,+BAAb,cAAkD,MAAM;CACtD,AAAO,cAAc;EACnB,MACE,6bAYF;EACA,KAAK,OAAO;CACd;AACF"}
1
+ {"version":3,"file":"queue-dashboard-unguarded.error.mjs","names":[],"sources":["../../../../../../../packages/queue/src/queue-dashboard-unguarded.error.ts"],"sourcesContent":["/**\n * Thrown at boot when `queue.dashboard.enabled` is `true` in production with\n * no guard middleware. The dashboard can retry and delete jobs; mounting it\n * on the open internet without a guard is a production incident waiting to\n * happen, so this fails the boot instead of shipping the hole.\n */\nexport class QueueDashboardUnguardedError extends Error {\n public constructor() {\n super(\n \"queue.dashboard.enabled is true in production with no middleware. The dashboard can \" +\n \"retry and delete jobs, so it must be guarded before it is exposed.\\n\\n\" +\n \"Add a guard middleware:\\n\\n\" +\n ' import { middleware } from \"@warlock.js/core\";\\n' +\n ' import { authMiddleware } from \"@warlock.js/auth\";\\n\\n' +\n \" const queueConfig: QueueConfig = {\\n\" +\n \" // ...\\n\" +\n \" dashboard: {\\n\" +\n \" enabled: true,\\n\" +\n ' middleware: [authMiddleware(\"admin\")],\\n' +\n \" },\\n\" +\n \" };\\n\",\n );\n this.name = \"QueueDashboardUnguardedError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,+BAAb,cAAkD,MAAM;CACtD,AAAO,cAAc;EACnB,MACE,6bAYF;EACA,KAAK,OAAO;CACd;AACF"}
@@ -1,11 +1,10 @@
1
1
  import { Queue } from "bullmq";
2
-
3
2
  //#region ../../packages/queue/src/queue-manager.d.ts
4
3
  /**
5
4
  * The BullMQ queue for `name`, created on first use with the configured
6
5
  * connection and prefix.
7
6
  */
8
- declare function getQueue(name: string): Queue;
7
+ export declare function getQueue(name: string): Queue;
9
8
  /**
10
9
  * Start one worker per queue that has a registered job, and keep starting
11
10
  * workers for queues whose first job is defined later.
@@ -18,10 +17,10 @@ declare function getQueue(name: string): Queue;
18
17
  *
19
18
  * @returns the queue names that now have a worker in this process.
20
19
  */
21
- declare function startWorkers(): Promise<string[]>;
20
+ export declare function startWorkers(): Promise<string[]>;
22
21
  /** The queue names with a running worker in this process. */
23
- declare function runningWorkers(): string[];
24
- type CloseQueueOptions = {
22
+ export declare function runningWorkers(): string[];
23
+ export type CloseQueueOptions = {
25
24
  /**
26
25
  * How long to wait for active jobs before force-closing workers, in
27
26
  * milliseconds. Default: `workers.shutdownTimeout`, else `30000`.
@@ -33,7 +32,6 @@ type CloseQueueOptions = {
33
32
  * (bounded by `timeout`, then force-close), then close every queue
34
33
  * connection. Safe to call when nothing was started, and more than once.
35
34
  */
36
- declare function closeQueue(options?: CloseQueueOptions): Promise<void>;
35
+ export declare function closeQueue(options?: CloseQueueOptions): Promise<void>;
37
36
  //#endregion
38
- export { CloseQueueOptions, closeQueue, getQueue, runningWorkers, startWorkers };
39
37
  //# sourceMappingURL=queue-manager.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-manager.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-manager.ts"],"mappings":";;;;;AAgBA;;iBAAgB,QAAA,CAAS,IAAA,WAAe,KAAK;;AAAA;AAiC7C;;;;AAA6C;AAgC7C;;;;AAA8B;iBAhCR,YAAA,IAAgB,OAAO;;iBAgC7B,cAAA;AAAA,KAgCJ,iBAAA;EAKH;AAQT;;;EARE,OAAO;AAAA;;;;AAQiE;;iBAApD,UAAA,CAAW,OAAA,GAAS,iBAAA,GAAyB,OAAO"}
1
+ {"version":3,"file":"queue-manager.d.mts","names":[],"sources":["../../../../../../../packages/queue/src/queue-manager.ts"],"mappings":";;;;;;wBAgBgB,SAAS,eAAe;;;;;;;;;;;;;wBAiClB,gBAAgB;;wBAgCtB;YAgCJ;;;;;EAKV;;;;;;;wBAQoB,WAAW,UAAS,oBAAyB"}