@babelqueue/bullmq 1.0.0 → 1.1.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.
- package/README.md +18 -0
- package/dist/index.cjs +46 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -4
- package/dist/index.d.ts +47 -4
- package/dist/index.js +43 -2
- package/dist/index.js.map +1 -1
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -48,6 +48,24 @@ unmapped URN throws unless you pass `onUnknownUrn`.
|
|
|
48
48
|
> services. For raw cross-language queues, other SDKs read/write plain broker
|
|
49
49
|
> queues directly.
|
|
50
50
|
|
|
51
|
+
## OpenTelemetry tracing (ADR-0028)
|
|
52
|
+
|
|
53
|
+
Cross-hop **span** linkage rides on the out-of-band `HeaderCarrier` from
|
|
54
|
+
[`@babelqueue/core@^1.4.0`](https://www.npmjs.com/package/@babelqueue/core). Pass the carrier produced by
|
|
55
|
+
`@babelqueue/core/otel`'s `publish` to this adapter's `publish({ headers })`; it is carried on
|
|
56
|
+
BullMQ's native `telemetry.metadata` job-options slot (so the envelope — `job.data` — is never touched). On consume, the `processor` surfaces a delivered job's headers to the handler's third argument (and `headersOf(job)` reads them back),
|
|
57
|
+
so the core's `otel` `wrapHandler` starts the consumer span as a true **child** of the producer span.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { trace } from "@opentelemetry/api";
|
|
61
|
+
import { publish as tracedPublish } from "@babelqueue/core/otel";
|
|
62
|
+
import type { HeaderCarrier } from "@babelqueue/core";
|
|
63
|
+
|
|
64
|
+
const headers: HeaderCarrier = {};
|
|
65
|
+
await tracedPublish(trace.getTracer("orders"), urn, data,
|
|
66
|
+
() => adapterPublish(urn, data, { headers }), { headers });
|
|
67
|
+
```
|
|
68
|
+
|
|
51
69
|
## License
|
|
52
70
|
|
|
53
71
|
[MIT](../../LICENSE) © Muhammet Şafak · [babelqueue.com](https://babelqueue.com)
|
package/dist/index.cjs
CHANGED
|
@@ -20,19 +20,60 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
decodeMetadata: () => decodeMetadata,
|
|
24
|
+
encodeMetadata: () => encodeMetadata,
|
|
25
|
+
headersOf: () => headersOf,
|
|
23
26
|
processor: () => processor,
|
|
24
27
|
publish: () => publish
|
|
25
28
|
});
|
|
26
29
|
module.exports = __toCommonJS(index_exports);
|
|
27
30
|
var import_core = require("@babelqueue/core");
|
|
31
|
+
|
|
32
|
+
// src/headers.ts
|
|
33
|
+
function sanitizeHeaders(headers) {
|
|
34
|
+
const out = {};
|
|
35
|
+
if (!headers) return out;
|
|
36
|
+
for (const key of Object.keys(headers)) {
|
|
37
|
+
const value = headers[key];
|
|
38
|
+
if (key === "" || value == null || value === "") continue;
|
|
39
|
+
out[key] = value;
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function encodeMetadata(headers) {
|
|
44
|
+
const clean = sanitizeHeaders(headers);
|
|
45
|
+
return Object.keys(clean).length === 0 ? void 0 : JSON.stringify(clean);
|
|
46
|
+
}
|
|
47
|
+
function decodeMetadata(metadata) {
|
|
48
|
+
if (!metadata) return {};
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(metadata);
|
|
51
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
52
|
+
return sanitizeHeaders(parsed);
|
|
53
|
+
} catch {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/index.ts
|
|
59
|
+
function headersOf(job) {
|
|
60
|
+
return decodeMetadata(job.opts?.telemetry?.metadata);
|
|
61
|
+
}
|
|
28
62
|
async function publish(queue, urn, data, options = {}) {
|
|
29
63
|
const envelope = import_core.EnvelopeCodec.make(urn, data, {
|
|
30
64
|
queue: queue.name,
|
|
31
65
|
traceId: options.traceId
|
|
32
66
|
});
|
|
33
|
-
await queue.add(urn, envelope, options.jobsOptions);
|
|
67
|
+
await queue.add(urn, envelope, withHeaders(options.jobsOptions, options.headers));
|
|
34
68
|
return envelope.meta.id;
|
|
35
69
|
}
|
|
70
|
+
function withHeaders(jobsOptions, headers) {
|
|
71
|
+
const metadata = encodeMetadata(headers);
|
|
72
|
+
if (metadata === void 0) return jobsOptions;
|
|
73
|
+
const telemetry = jobsOptions?.telemetry;
|
|
74
|
+
if (telemetry?.metadata != null) return jobsOptions;
|
|
75
|
+
return { ...jobsOptions, telemetry: { ...telemetry, metadata } };
|
|
76
|
+
}
|
|
36
77
|
function processor(handlers, options = {}) {
|
|
37
78
|
return async (job) => {
|
|
38
79
|
const envelope = job.data;
|
|
@@ -49,11 +90,14 @@ function processor(handlers, options = {}) {
|
|
|
49
90
|
}
|
|
50
91
|
throw new import_core.UnknownUrnError(urn);
|
|
51
92
|
}
|
|
52
|
-
return handler(envelope, job);
|
|
93
|
+
return handler(envelope, job, headersOf(job));
|
|
53
94
|
};
|
|
54
95
|
}
|
|
55
96
|
// Annotate the CommonJS export names for ESM import in node:
|
|
56
97
|
0 && (module.exports = {
|
|
98
|
+
decodeMetadata,
|
|
99
|
+
encodeMetadata,
|
|
100
|
+
headersOf,
|
|
57
101
|
processor,
|
|
58
102
|
publish
|
|
59
103
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * BullMQ adapter for BabelQueue.\n *\n * It makes your BullMQ jobs carry the canonical BabelQueue envelope and routes\n * them by URN, so a BullMQ-based Node service speaks the same contract (envelope\n * shape, URN identity, trace propagation) as the PHP/Laravel, Python, Go, Java and\n * .NET SDKs.\n *\n * import { Queue, Worker } from \"bullmq\";\n * import { publish, processor } from \"@babelqueue/bullmq\";\n *\n * const queue = new Queue(\"orders\", { connection });\n * await publish(queue, \"urn:babel:orders:created\", { order_id: 1042 });\n *\n * new Worker(\"orders\", processor({\n * \"urn:babel:orders:created\": async (env) => { ... },\n * }), { connection });\n */\n\nimport {\n BabelQueueError,\n EnvelopeCodec,\n UnknownUrnError,\n type Envelope,\n type IncomingEnvelope,\n} from \"@babelqueue/core\";\nimport type { Job, JobsOptions, Queue } from \"bullmq\";\n\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/headers.ts"],"sourcesContent":["/**\n * BullMQ adapter for BabelQueue.\n *\n * It makes your BullMQ jobs carry the canonical BabelQueue envelope and routes\n * them by URN, so a BullMQ-based Node service speaks the same contract (envelope\n * shape, URN identity, trace propagation) as the PHP/Laravel, Python, Go, Java and\n * .NET SDKs.\n *\n * import { Queue, Worker } from \"bullmq\";\n * import { publish, processor } from \"@babelqueue/bullmq\";\n *\n * const queue = new Queue(\"orders\", { connection });\n * await publish(queue, \"urn:babel:orders:created\", { order_id: 1042 });\n *\n * new Worker(\"orders\", processor({\n * \"urn:babel:orders:created\": async (env) => { ... },\n * }), { connection });\n */\n\nimport {\n BabelQueueError,\n EnvelopeCodec,\n UnknownUrnError,\n type Envelope,\n type HeaderCarrier,\n type IncomingEnvelope,\n} from \"@babelqueue/core\";\nimport type { Job, JobsOptions, Queue } from \"bullmq\";\n\nimport { decodeMetadata, encodeMetadata } from \"./headers.js\";\n\nexport { decodeMetadata, encodeMetadata } from \"./headers.js\";\n\n/**\n * The out-of-band {@link HeaderCarrier} carried by a job, read from BullMQ's native\n * `telemetry.metadata` slot (`job.opts.telemetry.metadata`). Empty for a job published without\n * headers. Pass it to `@babelqueue/core/otel`'s `wrapHandler` to link the consumer span as a child\n * of the producer span (ADR-0028).\n */\nexport function headersOf(job: Job): HeaderCarrier {\n return decodeMetadata(job.opts?.telemetry?.metadata);\n}\n\n/**\n * A URN handler. Receives the validated envelope, the raw BullMQ job, and the out-of-band\n * {@link HeaderCarrier} carried in the job's `telemetry.metadata` (empty when there are none).\n */\nexport type BabelHandler = (envelope: Envelope, job: Job, headers: HeaderCarrier) => unknown | Promise<unknown>;\n\n/** A map of URN → handler. */\nexport type BabelHandlers = Record<string, BabelHandler>;\n\n/** Options for {@link publish}. */\nexport interface PublishOptions {\n /** Reuse an existing trace id (trace continuation). */\n traceId?: string;\n /** BullMQ job options (delay, attempts, backoff, …). */\n jobsOptions?: JobsOptions;\n /**\n * Out-of-band transport headers carried in BullMQ's native `telemetry.metadata` slot (ADR-0028) —\n * e.g. a W3C `traceparent` written by `@babelqueue/core/otel`'s `publish`. The canonical envelope\n * (`job.data`) stays byte-identical (GR-1); an empty/omitted carrier leaves the job options\n * unchanged. An explicit `jobsOptions.telemetry.metadata` wins (it is not clobbered).\n */\n headers?: HeaderCarrier;\n}\n\n/**\n * Build the canonical envelope for `(urn, data)` and add it as a BullMQ job (the\n * job name is the URN, the job data is the envelope). Returns the message id\n * (`meta.id`).\n *\n * When `options.headers` carries any out-of-band header (e.g. a `traceparent`) it is serialized\n * into the job's `telemetry.metadata` so a consumer can read it back via {@link headersOf} — the\n * envelope itself is never touched.\n */\nexport async function publish(\n queue: Queue,\n urn: string,\n data: Record<string, unknown>,\n options: PublishOptions = {},\n): Promise<string> {\n const envelope = EnvelopeCodec.make(urn, data, {\n queue: queue.name,\n traceId: options.traceId,\n });\n await queue.add(urn, envelope, withHeaders(options.jobsOptions, options.headers));\n return envelope.meta.id;\n}\n\n/**\n * Merge an out-of-band header carrier into a job's `telemetry.metadata` without clobbering an\n * explicit one the caller already set. Returns the original options unchanged when there is nothing\n * to carry, so a header-less publish stays byte-identical.\n */\nfunction withHeaders(jobsOptions: JobsOptions | undefined, headers: HeaderCarrier | undefined): JobsOptions | undefined {\n const metadata = encodeMetadata(headers);\n if (metadata === undefined) return jobsOptions;\n const telemetry = jobsOptions?.telemetry;\n if (telemetry?.metadata != null) return jobsOptions; // an explicit metadata wins (merge-not-clobber)\n return { ...jobsOptions, telemetry: { ...telemetry, metadata } };\n}\n\n/** Options for {@link processor}. */\nexport interface ProcessorOptions {\n /** Called instead of throwing when a job's URN has no handler. */\n onUnknownUrn?: (envelope: IncomingEnvelope, job: Job) => unknown | Promise<unknown>;\n}\n\n/**\n * Build a BullMQ processor that decodes each job's envelope, validates it, and\n * routes it to the handler registered for its URN. A non-conformant envelope\n * throws (so BullMQ retries / fails the job per its options); an unmapped URN\n * throws unless `onUnknownUrn` is given.\n *\n * new Worker(\"orders\", processor(handlers), { connection });\n */\nexport function processor(\n handlers: BabelHandlers,\n options: ProcessorOptions = {},\n): (job: Job) => Promise<unknown> {\n return async (job: Job): Promise<unknown> => {\n const envelope = job.data as IncomingEnvelope;\n\n if (!EnvelopeCodec.accepts(envelope)) {\n throw new BabelQueueError(\n `Rejected a non-conformant BabelQueue envelope on job ${job.id ?? \"?\"}.`,\n );\n }\n\n const urn = EnvelopeCodec.urn(envelope);\n const handler = handlers[urn];\n if (!handler) {\n if (options.onUnknownUrn) {\n return options.onUnknownUrn(envelope, job);\n }\n throw new UnknownUrnError(urn);\n }\n\n return handler(envelope, job, headersOf(job));\n };\n}\n","/**\n * Pure, dependency-free helpers for the out-of-band transport-header seam (ADR-0028) — the Node\n * adapter mirror of Go's `sanitizeHeaders` and PHP's `Support\\Headers`. They carry an injected\n * {@link HeaderCarrier} (e.g. a W3C `traceparent`) beside the frozen envelope (GR-1), never inside it.\n *\n * BullMQ has no AMQP-style header table; its native context-propagation slot is\n * `JobsOptions.telemetry.metadata` (a string, stored compactly as `tm` in Redis), so the carrier is\n * serialized to JSON there — leaving `job.data` (the canonical envelope) byte-identical.\n */\n\nimport type { HeaderCarrier } from \"@babelqueue/core\";\n\n/**\n * Copy `headers`, dropping blank keys and blank values. Returns an empty object when nothing\n * survives. A nullish input yields an empty object.\n */\nexport function sanitizeHeaders(headers: HeaderCarrier | null | undefined): HeaderCarrier {\n const out: HeaderCarrier = {};\n if (!headers) return out;\n for (const key of Object.keys(headers)) {\n const value = headers[key];\n if (key === \"\" || value == null || value === \"\") continue;\n out[key] = value;\n }\n return out;\n}\n\n/**\n * Serialize a header carrier for BullMQ's `telemetry.metadata` slot, or `undefined` when there is\n * nothing to carry (so a header-less publish leaves `telemetry` unset and the job byte-identical).\n */\nexport function encodeMetadata(headers: HeaderCarrier | null | undefined): string | undefined {\n const clean = sanitizeHeaders(headers);\n return Object.keys(clean).length === 0 ? undefined : JSON.stringify(clean);\n}\n\n/**\n * Read a header carrier back from a BullMQ `telemetry.metadata` string. Returns an empty object for\n * a missing or unparseable value, so a job produced without headers (or by a non-babelqueue\n * producer) consumes with no headers and no error.\n */\nexport function decodeMetadata(metadata: string | undefined | null): HeaderCarrier {\n if (!metadata) return {};\n try {\n const parsed = JSON.parse(metadata) as unknown;\n if (parsed == null || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n return sanitizeHeaders(parsed as HeaderCarrier);\n } catch {\n return {};\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA,kBAOO;;;ACVA,SAAS,gBAAgB,SAA0D;AACxF,QAAM,MAAqB,CAAC;AAC5B,MAAI,CAAC,QAAS,QAAO;AACrB,aAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,QAAQ,MAAM,SAAS,QAAQ,UAAU,GAAI;AACjD,QAAI,GAAG,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAMO,SAAS,eAAe,SAA+D;AAC5F,QAAM,QAAQ,gBAAgB,OAAO;AACrC,SAAO,OAAO,KAAK,KAAK,EAAE,WAAW,IAAI,SAAY,KAAK,UAAU,KAAK;AAC3E;AAOO,SAAS,eAAe,UAAoD;AACjF,MAAI,CAAC,SAAU,QAAO,CAAC;AACvB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,QAAI,UAAU,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AACnF,WAAO,gBAAgB,MAAuB;AAAA,EAChD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;;;ADXO,SAAS,UAAU,KAAyB;AACjD,SAAO,eAAe,IAAI,MAAM,WAAW,QAAQ;AACrD;AAmCA,eAAsB,QACpB,OACA,KACA,MACA,UAA0B,CAAC,GACV;AACjB,QAAM,WAAW,0BAAc,KAAK,KAAK,MAAM;AAAA,IAC7C,OAAO,MAAM;AAAA,IACb,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,MAAM,IAAI,KAAK,UAAU,YAAY,QAAQ,aAAa,QAAQ,OAAO,CAAC;AAChF,SAAO,SAAS,KAAK;AACvB;AAOA,SAAS,YAAY,aAAsC,SAA6D;AACtH,QAAM,WAAW,eAAe,OAAO;AACvC,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,YAAY,aAAa;AAC/B,MAAI,WAAW,YAAY,KAAM,QAAO;AACxC,SAAO,EAAE,GAAG,aAAa,WAAW,EAAE,GAAG,WAAW,SAAS,EAAE;AACjE;AAgBO,SAAS,UACd,UACA,UAA4B,CAAC,GACG;AAChC,SAAO,OAAO,QAA+B;AAC3C,UAAM,WAAW,IAAI;AAErB,QAAI,CAAC,0BAAc,QAAQ,QAAQ,GAAG;AACpC,YAAM,IAAI;AAAA,QACR,wDAAwD,IAAI,MAAM,GAAG;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,MAAM,0BAAc,IAAI,QAAQ;AACtC,UAAM,UAAU,SAAS,GAAG;AAC5B,QAAI,CAAC,SAAS;AACZ,UAAI,QAAQ,cAAc;AACxB,eAAO,QAAQ,aAAa,UAAU,GAAG;AAAA,MAC3C;AACA,YAAM,IAAI,4BAAgB,GAAG;AAAA,IAC/B;AAEA,WAAO,QAAQ,UAAU,KAAK,UAAU,GAAG,CAAC;AAAA,EAC9C;AACF;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
|
-
import { Envelope, IncomingEnvelope } from '@babelqueue/core';
|
|
1
|
+
import { HeaderCarrier, Envelope, IncomingEnvelope } from '@babelqueue/core';
|
|
2
2
|
import { Job, JobsOptions, Queue } from 'bullmq';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Pure, dependency-free helpers for the out-of-band transport-header seam (ADR-0028) — the Node
|
|
6
|
+
* adapter mirror of Go's `sanitizeHeaders` and PHP's `Support\Headers`. They carry an injected
|
|
7
|
+
* {@link HeaderCarrier} (e.g. a W3C `traceparent`) beside the frozen envelope (GR-1), never inside it.
|
|
8
|
+
*
|
|
9
|
+
* BullMQ has no AMQP-style header table; its native context-propagation slot is
|
|
10
|
+
* `JobsOptions.telemetry.metadata` (a string, stored compactly as `tm` in Redis), so the carrier is
|
|
11
|
+
* serialized to JSON there — leaving `job.data` (the canonical envelope) byte-identical.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Serialize a header carrier for BullMQ's `telemetry.metadata` slot, or `undefined` when there is
|
|
16
|
+
* nothing to carry (so a header-less publish leaves `telemetry` unset and the job byte-identical).
|
|
17
|
+
*/
|
|
18
|
+
declare function encodeMetadata(headers: HeaderCarrier | null | undefined): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Read a header carrier back from a BullMQ `telemetry.metadata` string. Returns an empty object for
|
|
21
|
+
* a missing or unparseable value, so a job produced without headers (or by a non-babelqueue
|
|
22
|
+
* producer) consumes with no headers and no error.
|
|
23
|
+
*/
|
|
24
|
+
declare function decodeMetadata(metadata: string | undefined | null): HeaderCarrier;
|
|
25
|
+
|
|
4
26
|
/**
|
|
5
27
|
* BullMQ adapter for BabelQueue.
|
|
6
28
|
*
|
|
@@ -20,8 +42,18 @@ import { Job, JobsOptions, Queue } from 'bullmq';
|
|
|
20
42
|
* }), { connection });
|
|
21
43
|
*/
|
|
22
44
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The out-of-band {@link HeaderCarrier} carried by a job, read from BullMQ's native
|
|
47
|
+
* `telemetry.metadata` slot (`job.opts.telemetry.metadata`). Empty for a job published without
|
|
48
|
+
* headers. Pass it to `@babelqueue/core/otel`'s `wrapHandler` to link the consumer span as a child
|
|
49
|
+
* of the producer span (ADR-0028).
|
|
50
|
+
*/
|
|
51
|
+
declare function headersOf(job: Job): HeaderCarrier;
|
|
52
|
+
/**
|
|
53
|
+
* A URN handler. Receives the validated envelope, the raw BullMQ job, and the out-of-band
|
|
54
|
+
* {@link HeaderCarrier} carried in the job's `telemetry.metadata` (empty when there are none).
|
|
55
|
+
*/
|
|
56
|
+
type BabelHandler = (envelope: Envelope, job: Job, headers: HeaderCarrier) => unknown | Promise<unknown>;
|
|
25
57
|
/** A map of URN → handler. */
|
|
26
58
|
type BabelHandlers = Record<string, BabelHandler>;
|
|
27
59
|
/** Options for {@link publish}. */
|
|
@@ -30,11 +62,22 @@ interface PublishOptions {
|
|
|
30
62
|
traceId?: string;
|
|
31
63
|
/** BullMQ job options (delay, attempts, backoff, …). */
|
|
32
64
|
jobsOptions?: JobsOptions;
|
|
65
|
+
/**
|
|
66
|
+
* Out-of-band transport headers carried in BullMQ's native `telemetry.metadata` slot (ADR-0028) —
|
|
67
|
+
* e.g. a W3C `traceparent` written by `@babelqueue/core/otel`'s `publish`. The canonical envelope
|
|
68
|
+
* (`job.data`) stays byte-identical (GR-1); an empty/omitted carrier leaves the job options
|
|
69
|
+
* unchanged. An explicit `jobsOptions.telemetry.metadata` wins (it is not clobbered).
|
|
70
|
+
*/
|
|
71
|
+
headers?: HeaderCarrier;
|
|
33
72
|
}
|
|
34
73
|
/**
|
|
35
74
|
* Build the canonical envelope for `(urn, data)` and add it as a BullMQ job (the
|
|
36
75
|
* job name is the URN, the job data is the envelope). Returns the message id
|
|
37
76
|
* (`meta.id`).
|
|
77
|
+
*
|
|
78
|
+
* When `options.headers` carries any out-of-band header (e.g. a `traceparent`) it is serialized
|
|
79
|
+
* into the job's `telemetry.metadata` so a consumer can read it back via {@link headersOf} — the
|
|
80
|
+
* envelope itself is never touched.
|
|
38
81
|
*/
|
|
39
82
|
declare function publish(queue: Queue, urn: string, data: Record<string, unknown>, options?: PublishOptions): Promise<string>;
|
|
40
83
|
/** Options for {@link processor}. */
|
|
@@ -52,4 +95,4 @@ interface ProcessorOptions {
|
|
|
52
95
|
*/
|
|
53
96
|
declare function processor(handlers: BabelHandlers, options?: ProcessorOptions): (job: Job) => Promise<unknown>;
|
|
54
97
|
|
|
55
|
-
export { type BabelHandler, type BabelHandlers, type ProcessorOptions, type PublishOptions, processor, publish };
|
|
98
|
+
export { type BabelHandler, type BabelHandlers, type ProcessorOptions, type PublishOptions, decodeMetadata, encodeMetadata, headersOf, processor, publish };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
|
-
import { Envelope, IncomingEnvelope } from '@babelqueue/core';
|
|
1
|
+
import { HeaderCarrier, Envelope, IncomingEnvelope } from '@babelqueue/core';
|
|
2
2
|
import { Job, JobsOptions, Queue } from 'bullmq';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Pure, dependency-free helpers for the out-of-band transport-header seam (ADR-0028) — the Node
|
|
6
|
+
* adapter mirror of Go's `sanitizeHeaders` and PHP's `Support\Headers`. They carry an injected
|
|
7
|
+
* {@link HeaderCarrier} (e.g. a W3C `traceparent`) beside the frozen envelope (GR-1), never inside it.
|
|
8
|
+
*
|
|
9
|
+
* BullMQ has no AMQP-style header table; its native context-propagation slot is
|
|
10
|
+
* `JobsOptions.telemetry.metadata` (a string, stored compactly as `tm` in Redis), so the carrier is
|
|
11
|
+
* serialized to JSON there — leaving `job.data` (the canonical envelope) byte-identical.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Serialize a header carrier for BullMQ's `telemetry.metadata` slot, or `undefined` when there is
|
|
16
|
+
* nothing to carry (so a header-less publish leaves `telemetry` unset and the job byte-identical).
|
|
17
|
+
*/
|
|
18
|
+
declare function encodeMetadata(headers: HeaderCarrier | null | undefined): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Read a header carrier back from a BullMQ `telemetry.metadata` string. Returns an empty object for
|
|
21
|
+
* a missing or unparseable value, so a job produced without headers (or by a non-babelqueue
|
|
22
|
+
* producer) consumes with no headers and no error.
|
|
23
|
+
*/
|
|
24
|
+
declare function decodeMetadata(metadata: string | undefined | null): HeaderCarrier;
|
|
25
|
+
|
|
4
26
|
/**
|
|
5
27
|
* BullMQ adapter for BabelQueue.
|
|
6
28
|
*
|
|
@@ -20,8 +42,18 @@ import { Job, JobsOptions, Queue } from 'bullmq';
|
|
|
20
42
|
* }), { connection });
|
|
21
43
|
*/
|
|
22
44
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The out-of-band {@link HeaderCarrier} carried by a job, read from BullMQ's native
|
|
47
|
+
* `telemetry.metadata` slot (`job.opts.telemetry.metadata`). Empty for a job published without
|
|
48
|
+
* headers. Pass it to `@babelqueue/core/otel`'s `wrapHandler` to link the consumer span as a child
|
|
49
|
+
* of the producer span (ADR-0028).
|
|
50
|
+
*/
|
|
51
|
+
declare function headersOf(job: Job): HeaderCarrier;
|
|
52
|
+
/**
|
|
53
|
+
* A URN handler. Receives the validated envelope, the raw BullMQ job, and the out-of-band
|
|
54
|
+
* {@link HeaderCarrier} carried in the job's `telemetry.metadata` (empty when there are none).
|
|
55
|
+
*/
|
|
56
|
+
type BabelHandler = (envelope: Envelope, job: Job, headers: HeaderCarrier) => unknown | Promise<unknown>;
|
|
25
57
|
/** A map of URN → handler. */
|
|
26
58
|
type BabelHandlers = Record<string, BabelHandler>;
|
|
27
59
|
/** Options for {@link publish}. */
|
|
@@ -30,11 +62,22 @@ interface PublishOptions {
|
|
|
30
62
|
traceId?: string;
|
|
31
63
|
/** BullMQ job options (delay, attempts, backoff, …). */
|
|
32
64
|
jobsOptions?: JobsOptions;
|
|
65
|
+
/**
|
|
66
|
+
* Out-of-band transport headers carried in BullMQ's native `telemetry.metadata` slot (ADR-0028) —
|
|
67
|
+
* e.g. a W3C `traceparent` written by `@babelqueue/core/otel`'s `publish`. The canonical envelope
|
|
68
|
+
* (`job.data`) stays byte-identical (GR-1); an empty/omitted carrier leaves the job options
|
|
69
|
+
* unchanged. An explicit `jobsOptions.telemetry.metadata` wins (it is not clobbered).
|
|
70
|
+
*/
|
|
71
|
+
headers?: HeaderCarrier;
|
|
33
72
|
}
|
|
34
73
|
/**
|
|
35
74
|
* Build the canonical envelope for `(urn, data)` and add it as a BullMQ job (the
|
|
36
75
|
* job name is the URN, the job data is the envelope). Returns the message id
|
|
37
76
|
* (`meta.id`).
|
|
77
|
+
*
|
|
78
|
+
* When `options.headers` carries any out-of-band header (e.g. a `traceparent`) it is serialized
|
|
79
|
+
* into the job's `telemetry.metadata` so a consumer can read it back via {@link headersOf} — the
|
|
80
|
+
* envelope itself is never touched.
|
|
38
81
|
*/
|
|
39
82
|
declare function publish(queue: Queue, urn: string, data: Record<string, unknown>, options?: PublishOptions): Promise<string>;
|
|
40
83
|
/** Options for {@link processor}. */
|
|
@@ -52,4 +95,4 @@ interface ProcessorOptions {
|
|
|
52
95
|
*/
|
|
53
96
|
declare function processor(handlers: BabelHandlers, options?: ProcessorOptions): (job: Job) => Promise<unknown>;
|
|
54
97
|
|
|
55
|
-
export { type BabelHandler, type BabelHandlers, type ProcessorOptions, type PublishOptions, processor, publish };
|
|
98
|
+
export { type BabelHandler, type BabelHandlers, type ProcessorOptions, type PublishOptions, decodeMetadata, encodeMetadata, headersOf, processor, publish };
|
package/dist/index.js
CHANGED
|
@@ -4,14 +4,52 @@ import {
|
|
|
4
4
|
EnvelopeCodec,
|
|
5
5
|
UnknownUrnError
|
|
6
6
|
} from "@babelqueue/core";
|
|
7
|
+
|
|
8
|
+
// src/headers.ts
|
|
9
|
+
function sanitizeHeaders(headers) {
|
|
10
|
+
const out = {};
|
|
11
|
+
if (!headers) return out;
|
|
12
|
+
for (const key of Object.keys(headers)) {
|
|
13
|
+
const value = headers[key];
|
|
14
|
+
if (key === "" || value == null || value === "") continue;
|
|
15
|
+
out[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
function encodeMetadata(headers) {
|
|
20
|
+
const clean = sanitizeHeaders(headers);
|
|
21
|
+
return Object.keys(clean).length === 0 ? void 0 : JSON.stringify(clean);
|
|
22
|
+
}
|
|
23
|
+
function decodeMetadata(metadata) {
|
|
24
|
+
if (!metadata) return {};
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(metadata);
|
|
27
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
28
|
+
return sanitizeHeaders(parsed);
|
|
29
|
+
} catch {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/index.ts
|
|
35
|
+
function headersOf(job) {
|
|
36
|
+
return decodeMetadata(job.opts?.telemetry?.metadata);
|
|
37
|
+
}
|
|
7
38
|
async function publish(queue, urn, data, options = {}) {
|
|
8
39
|
const envelope = EnvelopeCodec.make(urn, data, {
|
|
9
40
|
queue: queue.name,
|
|
10
41
|
traceId: options.traceId
|
|
11
42
|
});
|
|
12
|
-
await queue.add(urn, envelope, options.jobsOptions);
|
|
43
|
+
await queue.add(urn, envelope, withHeaders(options.jobsOptions, options.headers));
|
|
13
44
|
return envelope.meta.id;
|
|
14
45
|
}
|
|
46
|
+
function withHeaders(jobsOptions, headers) {
|
|
47
|
+
const metadata = encodeMetadata(headers);
|
|
48
|
+
if (metadata === void 0) return jobsOptions;
|
|
49
|
+
const telemetry = jobsOptions?.telemetry;
|
|
50
|
+
if (telemetry?.metadata != null) return jobsOptions;
|
|
51
|
+
return { ...jobsOptions, telemetry: { ...telemetry, metadata } };
|
|
52
|
+
}
|
|
15
53
|
function processor(handlers, options = {}) {
|
|
16
54
|
return async (job) => {
|
|
17
55
|
const envelope = job.data;
|
|
@@ -28,10 +66,13 @@ function processor(handlers, options = {}) {
|
|
|
28
66
|
}
|
|
29
67
|
throw new UnknownUrnError(urn);
|
|
30
68
|
}
|
|
31
|
-
return handler(envelope, job);
|
|
69
|
+
return handler(envelope, job, headersOf(job));
|
|
32
70
|
};
|
|
33
71
|
}
|
|
34
72
|
export {
|
|
73
|
+
decodeMetadata,
|
|
74
|
+
encodeMetadata,
|
|
75
|
+
headersOf,
|
|
35
76
|
processor,
|
|
36
77
|
publish
|
|
37
78
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * BullMQ adapter for BabelQueue.\n *\n * It makes your BullMQ jobs carry the canonical BabelQueue envelope and routes\n * them by URN, so a BullMQ-based Node service speaks the same contract (envelope\n * shape, URN identity, trace propagation) as the PHP/Laravel, Python, Go, Java and\n * .NET SDKs.\n *\n * import { Queue, Worker } from \"bullmq\";\n * import { publish, processor } from \"@babelqueue/bullmq\";\n *\n * const queue = new Queue(\"orders\", { connection });\n * await publish(queue, \"urn:babel:orders:created\", { order_id: 1042 });\n *\n * new Worker(\"orders\", processor({\n * \"urn:babel:orders:created\": async (env) => { ... },\n * }), { connection });\n */\n\nimport {\n BabelQueueError,\n EnvelopeCodec,\n UnknownUrnError,\n type Envelope,\n type IncomingEnvelope,\n} from \"@babelqueue/core\";\nimport type { Job, JobsOptions, Queue } from \"bullmq\";\n\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/headers.ts"],"sourcesContent":["/**\n * BullMQ adapter for BabelQueue.\n *\n * It makes your BullMQ jobs carry the canonical BabelQueue envelope and routes\n * them by URN, so a BullMQ-based Node service speaks the same contract (envelope\n * shape, URN identity, trace propagation) as the PHP/Laravel, Python, Go, Java and\n * .NET SDKs.\n *\n * import { Queue, Worker } from \"bullmq\";\n * import { publish, processor } from \"@babelqueue/bullmq\";\n *\n * const queue = new Queue(\"orders\", { connection });\n * await publish(queue, \"urn:babel:orders:created\", { order_id: 1042 });\n *\n * new Worker(\"orders\", processor({\n * \"urn:babel:orders:created\": async (env) => { ... },\n * }), { connection });\n */\n\nimport {\n BabelQueueError,\n EnvelopeCodec,\n UnknownUrnError,\n type Envelope,\n type HeaderCarrier,\n type IncomingEnvelope,\n} from \"@babelqueue/core\";\nimport type { Job, JobsOptions, Queue } from \"bullmq\";\n\nimport { decodeMetadata, encodeMetadata } from \"./headers.js\";\n\nexport { decodeMetadata, encodeMetadata } from \"./headers.js\";\n\n/**\n * The out-of-band {@link HeaderCarrier} carried by a job, read from BullMQ's native\n * `telemetry.metadata` slot (`job.opts.telemetry.metadata`). Empty for a job published without\n * headers. Pass it to `@babelqueue/core/otel`'s `wrapHandler` to link the consumer span as a child\n * of the producer span (ADR-0028).\n */\nexport function headersOf(job: Job): HeaderCarrier {\n return decodeMetadata(job.opts?.telemetry?.metadata);\n}\n\n/**\n * A URN handler. Receives the validated envelope, the raw BullMQ job, and the out-of-band\n * {@link HeaderCarrier} carried in the job's `telemetry.metadata` (empty when there are none).\n */\nexport type BabelHandler = (envelope: Envelope, job: Job, headers: HeaderCarrier) => unknown | Promise<unknown>;\n\n/** A map of URN → handler. */\nexport type BabelHandlers = Record<string, BabelHandler>;\n\n/** Options for {@link publish}. */\nexport interface PublishOptions {\n /** Reuse an existing trace id (trace continuation). */\n traceId?: string;\n /** BullMQ job options (delay, attempts, backoff, …). */\n jobsOptions?: JobsOptions;\n /**\n * Out-of-band transport headers carried in BullMQ's native `telemetry.metadata` slot (ADR-0028) —\n * e.g. a W3C `traceparent` written by `@babelqueue/core/otel`'s `publish`. The canonical envelope\n * (`job.data`) stays byte-identical (GR-1); an empty/omitted carrier leaves the job options\n * unchanged. An explicit `jobsOptions.telemetry.metadata` wins (it is not clobbered).\n */\n headers?: HeaderCarrier;\n}\n\n/**\n * Build the canonical envelope for `(urn, data)` and add it as a BullMQ job (the\n * job name is the URN, the job data is the envelope). Returns the message id\n * (`meta.id`).\n *\n * When `options.headers` carries any out-of-band header (e.g. a `traceparent`) it is serialized\n * into the job's `telemetry.metadata` so a consumer can read it back via {@link headersOf} — the\n * envelope itself is never touched.\n */\nexport async function publish(\n queue: Queue,\n urn: string,\n data: Record<string, unknown>,\n options: PublishOptions = {},\n): Promise<string> {\n const envelope = EnvelopeCodec.make(urn, data, {\n queue: queue.name,\n traceId: options.traceId,\n });\n await queue.add(urn, envelope, withHeaders(options.jobsOptions, options.headers));\n return envelope.meta.id;\n}\n\n/**\n * Merge an out-of-band header carrier into a job's `telemetry.metadata` without clobbering an\n * explicit one the caller already set. Returns the original options unchanged when there is nothing\n * to carry, so a header-less publish stays byte-identical.\n */\nfunction withHeaders(jobsOptions: JobsOptions | undefined, headers: HeaderCarrier | undefined): JobsOptions | undefined {\n const metadata = encodeMetadata(headers);\n if (metadata === undefined) return jobsOptions;\n const telemetry = jobsOptions?.telemetry;\n if (telemetry?.metadata != null) return jobsOptions; // an explicit metadata wins (merge-not-clobber)\n return { ...jobsOptions, telemetry: { ...telemetry, metadata } };\n}\n\n/** Options for {@link processor}. */\nexport interface ProcessorOptions {\n /** Called instead of throwing when a job's URN has no handler. */\n onUnknownUrn?: (envelope: IncomingEnvelope, job: Job) => unknown | Promise<unknown>;\n}\n\n/**\n * Build a BullMQ processor that decodes each job's envelope, validates it, and\n * routes it to the handler registered for its URN. A non-conformant envelope\n * throws (so BullMQ retries / fails the job per its options); an unmapped URN\n * throws unless `onUnknownUrn` is given.\n *\n * new Worker(\"orders\", processor(handlers), { connection });\n */\nexport function processor(\n handlers: BabelHandlers,\n options: ProcessorOptions = {},\n): (job: Job) => Promise<unknown> {\n return async (job: Job): Promise<unknown> => {\n const envelope = job.data as IncomingEnvelope;\n\n if (!EnvelopeCodec.accepts(envelope)) {\n throw new BabelQueueError(\n `Rejected a non-conformant BabelQueue envelope on job ${job.id ?? \"?\"}.`,\n );\n }\n\n const urn = EnvelopeCodec.urn(envelope);\n const handler = handlers[urn];\n if (!handler) {\n if (options.onUnknownUrn) {\n return options.onUnknownUrn(envelope, job);\n }\n throw new UnknownUrnError(urn);\n }\n\n return handler(envelope, job, headersOf(job));\n };\n}\n","/**\n * Pure, dependency-free helpers for the out-of-band transport-header seam (ADR-0028) — the Node\n * adapter mirror of Go's `sanitizeHeaders` and PHP's `Support\\Headers`. They carry an injected\n * {@link HeaderCarrier} (e.g. a W3C `traceparent`) beside the frozen envelope (GR-1), never inside it.\n *\n * BullMQ has no AMQP-style header table; its native context-propagation slot is\n * `JobsOptions.telemetry.metadata` (a string, stored compactly as `tm` in Redis), so the carrier is\n * serialized to JSON there — leaving `job.data` (the canonical envelope) byte-identical.\n */\n\nimport type { HeaderCarrier } from \"@babelqueue/core\";\n\n/**\n * Copy `headers`, dropping blank keys and blank values. Returns an empty object when nothing\n * survives. A nullish input yields an empty object.\n */\nexport function sanitizeHeaders(headers: HeaderCarrier | null | undefined): HeaderCarrier {\n const out: HeaderCarrier = {};\n if (!headers) return out;\n for (const key of Object.keys(headers)) {\n const value = headers[key];\n if (key === \"\" || value == null || value === \"\") continue;\n out[key] = value;\n }\n return out;\n}\n\n/**\n * Serialize a header carrier for BullMQ's `telemetry.metadata` slot, or `undefined` when there is\n * nothing to carry (so a header-less publish leaves `telemetry` unset and the job byte-identical).\n */\nexport function encodeMetadata(headers: HeaderCarrier | null | undefined): string | undefined {\n const clean = sanitizeHeaders(headers);\n return Object.keys(clean).length === 0 ? undefined : JSON.stringify(clean);\n}\n\n/**\n * Read a header carrier back from a BullMQ `telemetry.metadata` string. Returns an empty object for\n * a missing or unparseable value, so a job produced without headers (or by a non-babelqueue\n * producer) consumes with no headers and no error.\n */\nexport function decodeMetadata(metadata: string | undefined | null): HeaderCarrier {\n if (!metadata) return {};\n try {\n const parsed = JSON.parse(metadata) as unknown;\n if (parsed == null || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n return sanitizeHeaders(parsed as HeaderCarrier);\n } catch {\n return {};\n }\n}\n"],"mappings":";AAmBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;;;ACVA,SAAS,gBAAgB,SAA0D;AACxF,QAAM,MAAqB,CAAC;AAC5B,MAAI,CAAC,QAAS,QAAO;AACrB,aAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,QAAQ,MAAM,SAAS,QAAQ,UAAU,GAAI;AACjD,QAAI,GAAG,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAMO,SAAS,eAAe,SAA+D;AAC5F,QAAM,QAAQ,gBAAgB,OAAO;AACrC,SAAO,OAAO,KAAK,KAAK,EAAE,WAAW,IAAI,SAAY,KAAK,UAAU,KAAK;AAC3E;AAOO,SAAS,eAAe,UAAoD;AACjF,MAAI,CAAC,SAAU,QAAO,CAAC;AACvB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,QAAI,UAAU,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AACnF,WAAO,gBAAgB,MAAuB;AAAA,EAChD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;;;ADXO,SAAS,UAAU,KAAyB;AACjD,SAAO,eAAe,IAAI,MAAM,WAAW,QAAQ;AACrD;AAmCA,eAAsB,QACpB,OACA,KACA,MACA,UAA0B,CAAC,GACV;AACjB,QAAM,WAAW,cAAc,KAAK,KAAK,MAAM;AAAA,IAC7C,OAAO,MAAM;AAAA,IACb,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,MAAM,IAAI,KAAK,UAAU,YAAY,QAAQ,aAAa,QAAQ,OAAO,CAAC;AAChF,SAAO,SAAS,KAAK;AACvB;AAOA,SAAS,YAAY,aAAsC,SAA6D;AACtH,QAAM,WAAW,eAAe,OAAO;AACvC,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,YAAY,aAAa;AAC/B,MAAI,WAAW,YAAY,KAAM,QAAO;AACxC,SAAO,EAAE,GAAG,aAAa,WAAW,EAAE,GAAG,WAAW,SAAS,EAAE;AACjE;AAgBO,SAAS,UACd,UACA,UAA4B,CAAC,GACG;AAChC,SAAO,OAAO,QAA+B;AAC3C,UAAM,WAAW,IAAI;AAErB,QAAI,CAAC,cAAc,QAAQ,QAAQ,GAAG;AACpC,YAAM,IAAI;AAAA,QACR,wDAAwD,IAAI,MAAM,GAAG;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,MAAM,cAAc,IAAI,QAAQ;AACtC,UAAM,UAAU,SAAS,GAAG;AAC5B,QAAI,CAAC,SAAS;AACZ,UAAI,QAAQ,cAAc;AACxB,eAAO,QAAQ,aAAa,UAAU,GAAG;AAAA,MAC3C;AACA,YAAM,IAAI,gBAAgB,GAAG;AAAA,IAC/B;AAEA,WAAO,QAAQ,UAAU,KAAK,UAAU,GAAG,CAAC;AAAA,EAC9C;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babelqueue/bullmq",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "BullMQ adapter for BabelQueue — canonical-envelope jobs and a URN-routed processor.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"babelqueue",
|
|
7
|
+
"bullmq",
|
|
8
|
+
"queue",
|
|
9
|
+
"polyglot",
|
|
10
|
+
"redis",
|
|
11
|
+
"messaging"
|
|
12
|
+
],
|
|
6
13
|
"homepage": "https://babelqueue.com",
|
|
7
14
|
"bugs": {
|
|
8
15
|
"url": "https://github.com/BabelQueue/babelqueue-node-adapters/issues"
|
|
@@ -30,7 +37,9 @@
|
|
|
30
37
|
"main": "./dist/index.cjs",
|
|
31
38
|
"module": "./dist/index.js",
|
|
32
39
|
"types": "./dist/index.d.ts",
|
|
33
|
-
"files": [
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
34
43
|
"sideEffects": false,
|
|
35
44
|
"engines": {
|
|
36
45
|
"node": ">=18"
|
|
@@ -41,7 +50,7 @@
|
|
|
41
50
|
"test": "node --import tsx --test test/*.test.ts"
|
|
42
51
|
},
|
|
43
52
|
"dependencies": {
|
|
44
|
-
"@babelqueue/core": "^1.
|
|
53
|
+
"@babelqueue/core": "^1.4.0"
|
|
45
54
|
},
|
|
46
55
|
"peerDependencies": {
|
|
47
56
|
"bullmq": "^5.0.0"
|