@adonis-agora/durable 0.15.0 → 0.15.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @adonis-agora/durable
2
2
 
3
+ ## 0.15.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#21](https://github.com/DavideCarvalho/adonis-durable/pull/21) [`68386e7`](https://github.com/DavideCarvalho/adonis-durable/commit/68386e722742fe95f6d852e442dd62760a8eb8e9) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Make `bullmq` an optional peer dependency instead of a hard dependency.
8
+
9
+ 0.15 added `bullmq` as a hard `dependency`. Because `bullmq` pins an EXACT `ioredis`
10
+ (e.g. `ioredis@5.11.1`), every app installing durable got a SECOND ioredis copy in its tree —
11
+ including apps that only use `transports.queue()`/`db`/`eventEmitter` and never touch the bullmq
12
+ transport. With two ioredis copies present, `@boringnode/queue`'s `redis()` adapter factory checks
13
+ `connection instanceof Redis` against its own ioredis copy; the live connection `@adonisjs/redis`
14
+ handed it was built by the OTHER copy, so the check is false, the factory falls through to
15
+ `new Redis({ host: 'localhost', port: 6379 })`, and the app hangs at boot in an
16
+ `ECONNREFUSED 127.0.0.1:6379` retry loop instead of reusing the configured Redis.
17
+
18
+ `bullmq` is now an optional peer dependency, loaded lazily (via a non-literal specifier) only inside
19
+ `createBullMQDeps`, the code path behind `transports.bullmq()`. Apps that do not select the bullmq
20
+ transport no longer install bullmq, no longer gain the duplicate ioredis, and no longer hit the
21
+ `instanceof` mismatch. Apps that DO use `transports.bullmq()` should add `bullmq` to their own
22
+ dependencies (the optional peer makes this explicit).
23
+
24
+ ## 0.15.1
25
+
26
+ ### Patch Changes
27
+
28
+ - [#19](https://github.com/DavideCarvalho/adonis-durable/pull/19) [`cc45f89`](https://github.com/DavideCarvalho/adonis-durable/commit/cc45f8988171db16a93700839a8745dffdb0d577) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Fix `transports.bullmq()`/`createBullMQDeps()` silently minting a Redis client bound to ioredis's own default (`127.0.0.1:6379`) instead of the caller's Redis when `connection` is falsy or an empty object — it now throws a clear, actionable error at boot instead of a silent misconnect that only surfaces as an `ECONNREFUSED 6379` retry loop once the real Redis is unreachable on the default host/port.
29
+
3
30
  ## 0.15.0
4
31
 
5
32
  ### Minor Changes
@@ -1,5 +1,5 @@
1
1
  /** Keep in sync with this package's `version` in package.json. */
2
- export declare const VERSION = "0.14.0";
2
+ export declare const VERSION = "0.15.2";
3
3
  export { defineConfig, defaultAuthorize, resolveConfig } from './define_config.js';
4
4
  export type { AuthorizeHook, DurableDashboardConfig, ResolvedDurableDashboardConfig, } from './define_config.js';
5
5
  export { listRuns, getRun, retryRun, redispatchPendingRun, cancelRun, health, ok, } from './handlers.js';
@@ -1,5 +1,5 @@
1
1
  /** Keep in sync with this package's `version` in package.json. */
2
- export const VERSION = '0.14.0';
2
+ export const VERSION = '0.15.2';
3
3
  export { defineConfig, defaultAuthorize, resolveConfig } from './define_config.js';
4
4
  export { listRuns, getRun, retryRun, redispatchPendingRun, cancelRun, health, ok, } from './handlers.js';
5
5
  export { renderDashboard } from './html.js';
@@ -1,5 +1,5 @@
1
1
  /** Keep in sync with this package's `version` in package.json. */
2
- export declare const VERSION = "0.14.0";
2
+ export declare const VERSION = "0.15.2";
3
3
  export * from './admission.js';
4
4
  export * from './control-flow-signal.js';
5
5
  export * from './duration.js';
package/dist/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Keep in sync with this package's `version` in package.json. */
2
- export const VERSION = '0.14.0';
2
+ export const VERSION = '0.15.2';
3
3
  // --- engine + core primitives -----------------------------------------------
4
4
  export * from './admission.js';
5
5
  export * from './control-flow-signal.js';
@@ -54,6 +54,10 @@ export interface BullMQDeps {
54
54
  * Workers require `maxRetriesPerRequest: null`; a plain-options connection is cloned with it set (a
55
55
  * passed-in `Redis` instance is preserved as-is). A standalone client for pub/sub / heartbeat keys is
56
56
  * a `duplicate()` of a passed-in instance, or a fresh client with a keepalive floor from the options.
57
+ *
58
+ * @throws when `connection` is falsy or an empty object — otherwise `makeRedis()` would silently mint
59
+ * an ioredis client with NO host/port, landing on ioredis's own default (`127.0.0.1:6379`) instead of
60
+ * the caller's Redis.
57
61
  */
58
62
  export declare function createBullMQDeps(connection: unknown, concurrency?: number): Promise<BullMQDeps>;
59
63
  //# sourceMappingURL=deps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../../src/transports/bullmq/deps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gGAAgG;AAChG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE3D,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IACvF,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,qGAAqG;AACrG,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACtE,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACvD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC;IACjE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACzF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,UAAU,CAAC;IACzD,6GAA6G;IAC7G,SAAS,IAAI,SAAS,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,SAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAiChG"}
1
+ {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../../src/transports/bullmq/deps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gGAAgG;AAChG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE3D,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IACvF,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,qGAAqG;AACrG,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACtE,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACvD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC;IACjE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACzF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,UAAU,IAAI,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,UAAU,CAAC;IACzD,6GAA6G;IAC7G,SAAS,IAAI,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,SAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAkDhG"}
@@ -14,6 +14,10 @@
14
14
  * Workers require `maxRetriesPerRequest: null`; a plain-options connection is cloned with it set (a
15
15
  * passed-in `Redis` instance is preserved as-is). A standalone client for pub/sub / heartbeat keys is
16
16
  * a `duplicate()` of a passed-in instance, or a fresh client with a keepalive floor from the options.
17
+ *
18
+ * @throws when `connection` is falsy or an empty object — otherwise `makeRedis()` would silently mint
19
+ * an ioredis client with NO host/port, landing on ioredis's own default (`127.0.0.1:6379`) instead of
20
+ * the caller's Redis.
17
21
  */
18
22
  export async function createBullMQDeps(connection, concurrency = 1) {
19
23
  // Non-literal specifiers: keep `tsc` from resolving 'bullmq'/'ioredis' at build time (they are a
@@ -23,6 +27,19 @@ export async function createBullMQDeps(connection, concurrency = 1) {
23
27
  const { Queue, Worker } = (await import(bullmqSpecifier));
24
28
  const { Redis } = (await import(ioredisSpecifier));
25
29
  const isRedisInstance = (value) => value instanceof Redis;
30
+ // A falsy/empty `connection` would otherwise reach `makeRedis()`'s `{ keepAlive: 10_000, ...connection }`
31
+ // spread with nothing useful in it, silently minting an ioredis client bound to ioredis's OWN default
32
+ // (127.0.0.1:6379) instead of the caller's Redis — a footgun that reads as "it connected" right up until
33
+ // it hits the wrong instance (see adonis-durable's redis-connection-standalone regression). Fail loudly
34
+ // instead, the same way `resolveQueueAdapter` does for a missing `transports.queue()` connection: an
35
+ // existing `Redis` instance, a connection string, or a non-empty options object is required.
36
+ const hasUsableConnection = isRedisInstance(connection) ||
37
+ typeof connection === 'string' ||
38
+ (typeof connection === 'object' && connection !== null && Object.keys(connection).length > 0);
39
+ if (!hasUsableConnection) {
40
+ const got = connection === undefined ? 'undefined' : JSON.stringify(connection);
41
+ throw new Error(`@agora/durable: transports.bullmq() needs a \`connection\` — an ioredis \`Redis\` instance, a connection string, or ConnectionOptions (host/port/path/sentinels/…). Got ${got}, which would otherwise silently fall back to ioredis's own default (127.0.0.1:6379) instead of your app's Redis.`);
42
+ }
26
43
  // Workers require `maxRetriesPerRequest: null`; preserve a passed-in Redis instance as-is.
27
44
  const workerConnection = () => connection && typeof connection === 'object' && !('options' in connection)
28
45
  ? { ...connection, maxRetriesPerRequest: null }
@@ -1 +1 @@
1
- {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/deps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgDH;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAmB,EAAE,WAAW,GAAG,CAAC;IACzE,iGAAiG;IACjG,gGAAgG;IAChG,MAAM,eAAe,GAAG,QAAQ,CAAC;IACjC,MAAM,gBAAgB,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAGvD,CAAC;IACF,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAEhD,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,KAAc,EAAmD,EAAE,CAC1F,KAAK,YAAa,KAA8D,CAAC;IAEnF,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,GAAY,EAAE,CACrC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,UAAU,CAAC;QACxE,CAAC,CAAC,EAAE,GAAI,UAAqB,EAAE,oBAAoB,EAAE,IAAI,EAAE;QAC3D,CAAC,CAAC,UAAU,CAAC;IAEjB,MAAM,SAAS,GAAG,GAAc,EAAE;QAChC,IAAI,eAAe,CAAC,UAAU,CAAC;YAAE,OAAO,UAAU,CAAC,SAAS,EAAE,CAAC;QAC/D,OAAO,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAI,UAAqB,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC;QACpD,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAC5B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,CAAC;QAC1F,SAAS;KACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/deps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgDH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAmB,EAAE,WAAW,GAAG,CAAC;IACzE,iGAAiG;IACjG,gGAAgG;IAChG,MAAM,eAAe,GAAG,QAAQ,CAAC;IACjC,MAAM,gBAAgB,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAGvD,CAAC;IACF,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAEhD,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,KAAc,EAAmD,EAAE,CAC1F,KAAK,YAAa,KAA8D,CAAC;IAEnF,0GAA0G;IAC1G,sGAAsG;IACtG,yGAAyG;IACzG,wGAAwG;IACxG,qGAAqG;IACrG,6FAA6F;IAC7F,MAAM,mBAAmB,GACvB,eAAe,CAAC,UAAU,CAAC;QAC3B,OAAO,UAAU,KAAK,QAAQ;QAC9B,CAAC,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAChF,MAAM,IAAI,KAAK,CACb,2KAA2K,GAAG,mHAAmH,CAClS,CAAC;IACJ,CAAC;IAED,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,GAAY,EAAE,CACrC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,UAAU,CAAC;QACxE,CAAC,CAAC,EAAE,GAAI,UAAqB,EAAE,oBAAoB,EAAE,IAAI,EAAE;QAC3D,CAAC,CAAC,UAAU,CAAC;IAEjB,MAAM,SAAS,GAAG,GAAc,EAAE;QAChC,IAAI,eAAe,CAAC,UAAU,CAAC;YAAE,OAAO,UAAU,CAAC,SAAS,EAAE,CAAC;QAC/D,OAAO,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAI,UAAqB,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC;QACpD,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAC5B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,CAAC;QAC1F,SAAS;KACV,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/durable",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "description": "Durable cross-app workflows for AdonisJS — deterministic replay engine, AdonisJS binding, ace commands, dashboard, OpenTelemetry, Telescope, testing harness and Redis admission, all in one package. Part of the Agora ecosystem.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -106,7 +106,6 @@
106
106
  ],
107
107
  "sideEffects": false,
108
108
  "dependencies": {
109
- "bullmq": "^5.0.0",
110
109
  "zod": "^3.23.0"
111
110
  },
112
111
  "peerDependencies": {
@@ -116,6 +115,7 @@
116
115
  "@adonisjs/queue": "^0.6.0",
117
116
  "@adonisjs/redis": "^9.2.0",
118
117
  "@opentelemetry/api": "^1.0.0",
118
+ "bullmq": "^5.0.0",
119
119
  "cron-parser": "^4.0.0 || ^5.0.0",
120
120
  "ioredis": "^5.0.0",
121
121
  "vitest": "^3.0.0"
@@ -124,6 +124,9 @@
124
124
  "@adonisjs/assembler": {
125
125
  "optional": true
126
126
  },
127
+ "bullmq": {
128
+ "optional": true
129
+ },
127
130
  "@adonisjs/lucid": {
128
131
  "optional": true
129
132
  },
@@ -157,6 +160,7 @@
157
160
  "@opentelemetry/sdk-trace-base": "^1.30.0",
158
161
  "@types/node": "^20.0.0",
159
162
  "better-sqlite3": "^11.0.0",
163
+ "bullmq": "^5.0.0",
160
164
  "cron-parser": "^4.9.0",
161
165
  "ioredis": "^5.4.0",
162
166
  "typescript": "^5.4.0",