@bymax-one/nest-queue 1.0.7 → 1.0.9

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
@@ -7,6 +7,42 @@ versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.0.9] — 2026-08-06
11
+
12
+ **Published-artifact change, not a behavioural one.** `dist/` differs from `1.0.8` — this
13
+ bundler preserves comments and the source gained mutation-suppression notes — but no runtime
14
+ path changed. Measured by building both revisions and diffing the output.
15
+
16
+ ### Documentation
17
+
18
+ - The mutation badge and README said **99.06%**; the measured score is **99.68%**.
19
+
20
+ ### Tests
21
+
22
+ - The withheld Redis connection now has the shape of its guarantee asserted: that the property is
23
+ non-enumerable, that redefining it throws, and that the URL's password stays out of both
24
+ `JSON.stringify` and `inspect({ showHidden: true })`.
25
+
26
+ ## [1.0.8] — 2026-08-04
27
+
28
+ **Runtime change.** `dist/` differs from `1.0.7`.
29
+
30
+ ### Security
31
+
32
+ - The Redis credentials are no longer disclosed when a service that holds them is
33
+ serialized. `connection` moves from a plain field on the resolved options to a
34
+ non-enumerable accessor, and `ConnectionResolver` keeps the ioredis client and the
35
+ consumer's module options in ECMAScript private fields, as do the maps holding the
36
+ `Queue`, `Worker` and `QueueEvents` instances. Those objects were all reachable by
37
+ walking a service: a `url` carries the password inline, and an ioredis instance carries
38
+ `options.password` as a plain field, so `JSON.stringify`, object spread and
39
+ `util.inspect` on `QueueService` emitted the password in plaintext — which is what a
40
+ structured logger does when it renders a provider it was handed, and what an error
41
+ reporter does when it captures the scope of a throw.
42
+
43
+ Reading on purpose is unchanged: `options.connection` resolves as before, and no public
44
+ type or export changed.
45
+
10
46
  ## [1.0.7] — 2026-08-04
11
47
 
12
48
  **Runtime change.** `dist/` differs from `1.0.6`: the four decorators no longer carry
@@ -369,6 +405,8 @@ v6 peer range.
369
405
 
370
406
  ---
371
407
 
408
+ [1.0.9]: https://github.com/bymaxone/nest-queue/compare/v1.0.8...v1.0.9
409
+ [1.0.8]: https://github.com/bymaxone/nest-queue/compare/v1.0.7...v1.0.8
372
410
  [1.0.7]: https://github.com/bymaxone/nest-queue/compare/v1.0.6...v1.0.7
373
411
  [1.0.6]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.6
374
412
  [1.0.5]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.5
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  <a href="https://www.npmjs.com/package/@bymax-one/nest-queue"><img src="https://img.shields.io/npm/dm/@bymax-one/nest-queue?style=flat-square&colorA=000000&colorB=000000" alt="npm downloads" /></a>
15
15
  <a href="https://github.com/bymaxone/nest-queue/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/bymaxone/nest-queue/ci.yml?branch=main&style=flat-square&colorA=000000&label=CI" alt="CI status" /></a>
16
16
  <a href="https://github.com/bymaxone/nest-queue/actions/workflows/ci.yml"><img src="https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square&colorA=000000" alt="coverage" /></a>
17
- <a href="https://github.com/bymaxone/nest-queue/blob/main/docs/mutation_testing_results.md"><img src="https://img.shields.io/badge/mutation-99.06%25-brightgreen?style=flat-square&colorA=000000" alt="mutation score" /></a>
17
+ <a href="https://github.com/bymaxone/nest-queue/blob/main/docs/mutation_testing_results.md"><img src="https://img.shields.io/badge/mutation-99.68%25-brightgreen?style=flat-square&colorA=000000" alt="mutation score" /></a>
18
18
  <a href="https://scorecard.dev/viewer/?uri=github.com/bymaxone/nest-queue"><img src="https://api.scorecard.dev/projects/github.com/bymaxone/nest-queue/badge?style=flat-square" alt="OpenSSF Scorecard" /></a>
19
19
  <a href="https://github.com/bymaxone/nest-queue/blob/main/LICENSE"><img src="https://img.shields.io/github/license/bymaxone/nest-queue?style=flat-square&colorA=000000&colorB=000000" alt="license" /></a>
20
20
  <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-strict-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
@@ -711,6 +711,14 @@ message, or an exception payload. `QueueException.details` carries only scalar
711
711
  configuration values (`{ actualValue, expectedValue, limit, received }`), never a
712
712
  connection object and never `job.data`.
713
713
 
714
+ They are also not reachable by serializing the objects that hold them. The connection is
715
+ attached to the resolved options as a non-enumerable accessor, and the resolver keeps the
716
+ ioredis client — which carries `options.password` as a plain field — in a private field,
717
+ as do the registries that hold the `Queue`, `Worker` and `QueueEvents` instances. So
718
+ `JSON.stringify`, object spread, `util.inspect` and `util.inspect` with `showHidden` all
719
+ come back without credentials, which is what matters when a structured logger renders a
720
+ provider it was handed or an error reporter captures the scope of a throw.
721
+
714
722
  ### Job data is opaque
715
723
 
716
724
  The library treats `job.data` as a payload to transport, never to inspect. It is never
@@ -755,16 +763,16 @@ key will do it twice at some point.
755
763
 
756
764
  ## 🛡️ Security Table
757
765
 
758
- | Layer | Implementation |
759
- | ----------------- | ---------------------------------------------------------------------------------------------------------- |
760
- | Credentials | Injected options only; never read from `process.env`, never logged, never placed in an exception |
761
- | Error payloads | `QueueException.details` restricted to scalar configuration values — no `job.data`, no connection object |
762
- | Job payloads | Treated as opaque; never deep-merged (prototype-pollution guard), never logged |
763
- | Namespacing | `prefix` applied uniformly to `Queue`, `Worker`, `QueueEvents` and `FlowProducer` |
764
- | Connection policy | `maxRetriesPerRequest: null` confined to duplicated consumer connections; producers keep fail-fast retries |
765
- | Delivery | At-least-once with a bounded drain; unacknowledged work is re-queued by BullMQ's stalled check |
766
- | Supply chain | `dependencies: {}`; SHA-pinned Actions, OSV-Scanner, TruffleHog, OpenSSF Scorecard; npm publish over OIDC |
767
- | Input validation | Options validated at bootstrap; cron patterns validated by BullMQ's own parser, never a hand-rolled regex |
766
+ | Layer | Implementation |
767
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
768
+ | Credentials | Injected options only; never read from `process.env`, never logged, never placed in an exception; held in a non-enumerable accessor and private fields, so serializing a service omits them |
769
+ | Error payloads | `QueueException.details` restricted to scalar configuration values — no `job.data`, no connection object |
770
+ | Job payloads | Treated as opaque; never deep-merged (prototype-pollution guard), never logged |
771
+ | Namespacing | `prefix` applied uniformly to `Queue`, `Worker`, `QueueEvents` and `FlowProducer` |
772
+ | Connection policy | `maxRetriesPerRequest: null` confined to duplicated consumer connections; producers keep fail-fast retries |
773
+ | Delivery | At-least-once with a bounded drain; unacknowledged work is re-queued by BullMQ's stalled check |
774
+ | Supply chain | `dependencies: {}`; SHA-pinned Actions, OSV-Scanner, TruffleHog, OpenSSF Scorecard; npm publish over OIDC |
775
+ | Input validation | Options validated at bootstrap; cron patterns validated by BullMQ's own parser, never a hand-rolled regex |
768
776
 
769
777
  > [!IMPORTANT]
770
778
  > **Delivery is at-least-once, and `prefix` is not an access boundary.** Handlers must be
@@ -788,7 +796,7 @@ key will do it twice at some point.
788
796
  ## 🧪 Testing & Quality
789
797
 
790
798
  - **100% line/branch coverage** on every implemented file (hard CI gate).
791
- - **Mutation score 99.06%** (Stryker `break 95`) — see [`docs/mutation_testing_results.md`](docs/mutation_testing_results.md).
799
+ - **Mutation score 99.68%** (Stryker `break 95`) — see [`docs/mutation_testing_results.md`](docs/mutation_testing_results.md).
792
800
  - **Real-Redis E2E** via Testcontainers (workers, flows, schedulers, deduplication, retries,
793
801
  DLQ, graceful shutdown).
794
802
  - **Type-level API tests** (`pnpm test:types`) pin the published signatures, so a refactor
@@ -6,7 +6,12 @@ var ioredis = require('ioredis');
6
6
  var bullmq = require('bullmq');
7
7
  var path = require('path');
8
8
 
9
+ var __defProp = Object.defineProperty;
9
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __typeError = (msg) => {
12
+ throw TypeError(msg);
13
+ };
14
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
15
  var __decorateClass = (decorators, target, key, kind) => {
11
16
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
12
17
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -15,6 +20,11 @@ var __decorateClass = (decorators, target, key, kind) => {
15
20
  return result;
16
21
  };
17
22
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
23
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
25
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
26
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
27
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
18
28
 
19
29
  // src/shared/constants/error-codes.ts
20
30
  var QUEUE_ERROR_CODES = {
@@ -111,8 +121,8 @@ var DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 3e4;
111
121
 
112
122
  // src/server/config/resolved-options.ts
113
123
  function applyDefaults(opts) {
124
+ const connection = opts.connection;
114
125
  const base = {
115
- connection: opts.connection,
116
126
  defaultJobOptions: { ...DEFAULT_JOB_OPTIONS, ...opts.defaultJobOptions ?? {} },
117
127
  prefix: opts.prefix ?? "bull",
118
128
  queueOptions: opts.queueOptions ?? {},
@@ -128,6 +138,12 @@ function applyDefaults(opts) {
128
138
  connectionReadyTimeoutMs: opts.connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
129
139
  };
130
140
  if (opts.telemetry !== void 0) base.telemetry = opts.telemetry;
141
+ Object.defineProperty(base, "connection", {
142
+ get: () => connection,
143
+ enumerable: false,
144
+ // Stryker disable next-line BooleanLiteral: equivalent HERE — this object is `Object.freeze`d on the way out, and freezing makes every property non-configurable regardless. The flag stays because it states the guarantee at the point the accessor is defined, and because the sibling packages that withhold secrets the same way are NOT frozen, where it is load-bearing
145
+ configurable: false
146
+ });
131
147
  return Object.freeze(base);
132
148
  }
133
149
 
@@ -157,34 +173,44 @@ function duplicateConnection(client) {
157
173
  }
158
174
 
159
175
  // src/server/services/connection-resolver.service.ts
176
+ var _client, _options;
160
177
  exports.ConnectionResolver = class ConnectionResolver {
161
178
  constructor(options) {
162
- this.options = options;
179
+ /**
180
+ * The resolved Redis client.
181
+ *
182
+ * An ECMAScript private field rather than a TypeScript `private` one, which
183
+ * is erased at runtime: an ioredis instance carries `options.password` as a
184
+ * plain field, so leaving this enumerable would let anything that serializes
185
+ * a service holding this resolver walk into the credentials.
186
+ */
187
+ __privateAdd(this, _client);
188
+ /** The consumer's module options, which carry the Redis credentials. */
189
+ __privateAdd(this, _options);
190
+ __publicField(this, "mode");
191
+ __privateSet(this, _options, options);
163
192
  }
164
- options;
165
- client;
166
- mode;
167
193
  /** Resolve and validate the connection. Call once during module bootstrap. */
168
194
  async init() {
169
- const cfg = this.options.connection;
195
+ const cfg = __privateGet(this, _options).connection;
170
196
  if ("client" in cfg) {
171
197
  this.initModeA(cfg.client);
172
198
  return;
173
199
  }
174
200
  this.mode = "mode-b-owned";
175
- this.client = "url" in cfg ? new ioredis.Redis(cfg.url, { ...cfg.options ?? {}, lazyConnect: false }) : new ioredis.Redis({ ...cfg.options, lazyConnect: false });
201
+ __privateSet(this, _client, "url" in cfg ? new ioredis.Redis(cfg.url, { ...cfg.options ?? {}, lazyConnect: false }) : new ioredis.Redis({ ...cfg.options, lazyConnect: false }));
176
202
  await this.waitReady(
177
- this.options.connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
203
+ __privateGet(this, _options).connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
178
204
  );
179
205
  }
180
206
  /** The resolved Queue-role client. */
181
207
  getClient() {
182
- if (!this.client) {
208
+ if (!__privateGet(this, _client)) {
183
209
  throw new QueueException(QUEUE_ERROR_CODES.CONNECTION_INVALID, 500, {
184
210
  reason: "not initialized"
185
211
  });
186
212
  }
187
- return this.client;
213
+ return __privateGet(this, _client);
188
214
  }
189
215
  /** The resolved connection mode. */
190
216
  getMode() {
@@ -201,8 +227,8 @@ exports.ConnectionResolver = class ConnectionResolver {
201
227
  }
202
228
  /** Close the library-owned connection on shutdown; never touch a BYO client. */
203
229
  async teardown() {
204
- if (this.isOwned() && this.client) {
205
- const client = this.client;
230
+ if (this.isOwned() && __privateGet(this, _client)) {
231
+ const client = __privateGet(this, _client);
206
232
  await client.quit().catch(() => {
207
233
  client.disconnect();
208
234
  });
@@ -211,7 +237,7 @@ exports.ConnectionResolver = class ConnectionResolver {
211
237
  /** Validate and adopt a bring-your-own client for the Queue role. */
212
238
  initModeA(client) {
213
239
  this.mode = "mode-a-byo";
214
- this.client = client;
240
+ __privateSet(this, _client, client);
215
241
  if (!isClientUsable(client)) {
216
242
  throw new QueueException(QUEUE_ERROR_CODES.CONNECTION_INVALID, 500, { status: client.status });
217
243
  }
@@ -249,6 +275,8 @@ exports.ConnectionResolver = class ConnectionResolver {
249
275
  });
250
276
  }
251
277
  };
278
+ _client = new WeakMap();
279
+ _options = new WeakMap();
252
280
  exports.ConnectionResolver = __decorateClass([
253
281
  common.Injectable(),
254
282
  __decorateParam(0, common.Inject(BYMAX_QUEUE_OPTIONS))
@@ -297,15 +325,16 @@ var MAX_BULK_SIZE = 1e3;
297
325
  function isOperationalError(err) {
298
326
  return typeof err?.code === "string";
299
327
  }
328
+ var _queues;
300
329
  exports.QueueService = class QueueService {
301
330
  constructor(connection, options) {
302
331
  this.connection = connection;
303
332
  this.options = options;
333
+ __publicField(this, "logger", new common.Logger(exports.QueueService.name));
334
+ __privateAdd(this, _queues, /* @__PURE__ */ new Map());
304
335
  }
305
336
  connection;
306
337
  options;
307
- logger = new common.Logger(exports.QueueService.name);
308
- queues = /* @__PURE__ */ new Map();
309
338
  /**
310
339
  * Return the cached `Queue` for `queueName`, or create one with the module
311
340
  * defaults applied. Subsequent calls with the same name return the same
@@ -315,7 +344,7 @@ exports.QueueService = class QueueService {
315
344
  * @param overrides - Optional per-queue option overrides.
316
345
  */
317
346
  getOrCreateQueue(queueName, overrides) {
318
- const existing = this.queues.get(queueName);
347
+ const existing = __privateGet(this, _queues).get(queueName);
319
348
  if (existing) return existing;
320
349
  const queue = new bullmq.Queue(queueName, {
321
350
  connection: this.connection.getClient(),
@@ -326,7 +355,7 @@ exports.QueueService = class QueueService {
326
355
  ...overrides
327
356
  });
328
357
  attachDefaultErrorListener(queue, this.logger, "Queue", queueName);
329
- this.queues.set(queueName, queue);
358
+ __privateGet(this, _queues).set(queueName, queue);
330
359
  return queue;
331
360
  }
332
361
  /** Resolve the raw cached queue (default generics) for internal delegation. */
@@ -530,7 +559,7 @@ exports.QueueService = class QueueService {
530
559
  }
531
560
  /** Return a read-only view of the cached queues. */
532
561
  getCachedQueues() {
533
- return this.queues;
562
+ return __privateGet(this, _queues);
534
563
  }
535
564
  /**
536
565
  * Close every cached queue (swallowing per-queue errors) and clear the cache.
@@ -542,12 +571,13 @@ exports.QueueService = class QueueService {
542
571
  * exists to prevent. `QueueLifecycle` is the only caller.
543
572
  */
544
573
  async closeAll() {
545
- for (const queue of this.queues.values()) {
574
+ for (const queue of __privateGet(this, _queues).values()) {
546
575
  await queue.close().catch(() => void 0);
547
576
  }
548
- this.queues.clear();
577
+ __privateGet(this, _queues).clear();
549
578
  }
550
579
  };
580
+ _queues = new WeakMap();
551
581
  exports.QueueService = __decorateClass([
552
582
  common.Injectable(),
553
583
  __decorateParam(0, common.Inject(exports.ConnectionResolver)),
@@ -704,15 +734,16 @@ exports.MetricsService = class MetricsService {
704
734
  exports.MetricsService = __decorateClass([
705
735
  common.Injectable()
706
736
  ], exports.MetricsService);
737
+ var _entries;
707
738
  exports.WorkerRegistry = class WorkerRegistry {
708
739
  constructor(connection, options) {
709
740
  this.connection = connection;
710
741
  this.options = options;
742
+ __publicField(this, "logger", new common.Logger(exports.WorkerRegistry.name));
743
+ __privateAdd(this, _entries, /* @__PURE__ */ new Map());
711
744
  }
712
745
  connection;
713
746
  options;
714
- logger = new common.Logger(exports.WorkerRegistry.name);
715
- entries = /* @__PURE__ */ new Map();
716
747
  /**
717
748
  * Register an in-process worker with a handler function. The BullMQ `Worker`
718
749
  * constructor is synchronous — no Redis handshake is performed at registration
@@ -743,7 +774,7 @@ exports.WorkerRegistry = class WorkerRegistry {
743
774
  });
744
775
  }
745
776
  attachDefaultErrorListener(worker, this.logger, "Worker", queueName);
746
- this.entries.set(queueName, { worker, connection: conn });
777
+ __privateGet(this, _entries).set(queueName, { worker, connection: conn });
747
778
  return worker;
748
779
  }
749
780
  /**
@@ -782,7 +813,7 @@ exports.WorkerRegistry = class WorkerRegistry {
782
813
  });
783
814
  }
784
815
  attachDefaultErrorListener(worker, this.logger, "Worker", queueName);
785
- this.entries.set(queueName, { worker, connection: conn });
816
+ __privateGet(this, _entries).set(queueName, { worker, connection: conn });
786
817
  return worker;
787
818
  }
788
819
  /**
@@ -793,11 +824,11 @@ exports.WorkerRegistry = class WorkerRegistry {
793
824
  * @param queueName - The queue whose worker should be removed.
794
825
  */
795
826
  async unregister(queueName) {
796
- const entry = this.entries.get(queueName);
827
+ const entry = __privateGet(this, _entries).get(queueName);
797
828
  if (!entry) return;
798
829
  await entry.worker.close();
799
830
  await this.closeConnection(entry.connection);
800
- this.entries.delete(queueName);
831
+ __privateGet(this, _entries).delete(queueName);
801
832
  }
802
833
  /**
803
834
  * Returns the queue names of all currently registered workers.
@@ -805,7 +836,7 @@ exports.WorkerRegistry = class WorkerRegistry {
805
836
  * @returns An immutable array of queue names.
806
837
  */
807
838
  list() {
808
- return Array.from(this.entries.keys());
839
+ return Array.from(__privateGet(this, _entries).keys());
809
840
  }
810
841
  /**
811
842
  * Returns a read-only view of the registered workers keyed by queue name.
@@ -815,7 +846,7 @@ exports.WorkerRegistry = class WorkerRegistry {
815
846
  */
816
847
  getAll() {
817
848
  return new Map(
818
- Array.from(this.entries, ([name, entry]) => [name, entry.worker])
849
+ Array.from(__privateGet(this, _entries), ([name, entry]) => [name, entry.worker])
819
850
  );
820
851
  }
821
852
  /**
@@ -828,7 +859,7 @@ exports.WorkerRegistry = class WorkerRegistry {
828
859
  */
829
860
  getConnections() {
830
861
  return new Map(
831
- Array.from(this.entries, ([name, entry]) => [name, entry.connection])
862
+ Array.from(__privateGet(this, _entries), ([name, entry]) => [name, entry.connection])
832
863
  );
833
864
  }
834
865
  /**
@@ -851,7 +882,7 @@ exports.WorkerRegistry = class WorkerRegistry {
851
882
  * @throws {QueueException} `DUPLICATE_PROCESSOR` if the queue is already registered.
852
883
  */
853
884
  guardDuplicate(queueName) {
854
- if (this.entries.has(queueName)) {
885
+ if (__privateGet(this, _entries).has(queueName)) {
855
886
  throw new QueueException(QUEUE_ERROR_CODES.DUPLICATE_PROCESSOR, 500, { queueName });
856
887
  }
857
888
  }
@@ -960,21 +991,23 @@ exports.WorkerRegistry = class WorkerRegistry {
960
991
  return result;
961
992
  }
962
993
  };
994
+ _entries = new WeakMap();
963
995
  exports.WorkerRegistry = __decorateClass([
964
996
  common.Injectable(),
965
997
  __decorateParam(0, common.Inject(exports.ConnectionResolver)),
966
998
  __decorateParam(1, common.Inject(BYMAX_QUEUE_RESOLVED_OPTIONS))
967
999
  ], exports.WorkerRegistry);
1000
+ var _events, _connections;
968
1001
  exports.QueueEventsRegistry = class QueueEventsRegistry {
969
1002
  constructor(connection, options) {
970
1003
  this.connection = connection;
971
1004
  this.options = options;
1005
+ __publicField(this, "logger", new common.Logger(exports.QueueEventsRegistry.name));
1006
+ __privateAdd(this, _events, /* @__PURE__ */ new Map());
1007
+ __privateAdd(this, _connections, /* @__PURE__ */ new Map());
972
1008
  }
973
1009
  connection;
974
1010
  options;
975
- logger = new common.Logger(exports.QueueEventsRegistry.name);
976
- events = /* @__PURE__ */ new Map();
977
- connections = /* @__PURE__ */ new Map();
978
1011
  /**
979
1012
  * Returns the cached `QueueEvents` for `queueName`, creating one on first
980
1013
  * call. Subsequent calls for the same name return the same instance without
@@ -984,7 +1017,7 @@ exports.QueueEventsRegistry = class QueueEventsRegistry {
984
1017
  * @returns The `QueueEvents` instance for the queue.
985
1018
  */
986
1019
  getOrCreate(queueName) {
987
- const existing = this.events.get(queueName);
1020
+ const existing = __privateGet(this, _events).get(queueName);
988
1021
  if (existing) return existing;
989
1022
  const conn = duplicateConnection(this.connection.getClient());
990
1023
  let qe;
@@ -995,8 +1028,8 @@ exports.QueueEventsRegistry = class QueueEventsRegistry {
995
1028
  throw err;
996
1029
  }
997
1030
  attachDefaultErrorListener(qe, this.logger, "QueueEvents", queueName);
998
- this.events.set(queueName, qe);
999
- this.connections.set(queueName, conn);
1031
+ __privateGet(this, _events).set(queueName, qe);
1032
+ __privateGet(this, _connections).set(queueName, conn);
1000
1033
  return qe;
1001
1034
  }
1002
1035
  /**
@@ -1005,7 +1038,7 @@ exports.QueueEventsRegistry = class QueueEventsRegistry {
1005
1038
  * @returns An immutable array of queue names.
1006
1039
  */
1007
1040
  list() {
1008
- return Array.from(this.events.keys());
1041
+ return Array.from(__privateGet(this, _events).keys());
1009
1042
  }
1010
1043
  /**
1011
1044
  * Returns the live `QueueEvents` map. Intended for the shutdown orchestrator.
@@ -1013,7 +1046,7 @@ exports.QueueEventsRegistry = class QueueEventsRegistry {
1013
1046
  * @returns A read-only view of the internal map.
1014
1047
  */
1015
1048
  getAll() {
1016
- return this.events;
1049
+ return __privateGet(this, _events);
1017
1050
  }
1018
1051
  /**
1019
1052
  * Returns a read-only view of the duplicated connections the library opened
@@ -1029,9 +1062,11 @@ exports.QueueEventsRegistry = class QueueEventsRegistry {
1029
1062
  * @returns A read-only snapshot of queue name to duplicated connection.
1030
1063
  */
1031
1064
  getConnections() {
1032
- return new Map(this.connections);
1065
+ return new Map(__privateGet(this, _connections));
1033
1066
  }
1034
1067
  };
1068
+ _events = new WeakMap();
1069
+ _connections = new WeakMap();
1035
1070
  exports.QueueEventsRegistry = __decorateClass([
1036
1071
  common.Injectable(),
1037
1072
  __decorateParam(0, common.Inject(exports.ConnectionResolver)),
@@ -1299,10 +1334,15 @@ QueueLifecycle = __decorateClass([
1299
1334
  ], QueueLifecycle);
1300
1335
 
1301
1336
  // src/server/bymax-queue.module.ts
1302
- var { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = new common.ConfigurableModuleBuilder({ moduleName: "BymaxQueue" }).setClassMethodName("forRoot").setFactoryMethodName("createQueueOptions").setExtras({ isGlobal: true }, (definition, extras) => ({
1303
- ...definition,
1304
- global: extras.isGlobal
1305
- })).build();
1337
+ var { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = (
1338
+ // The `moduleName` shapes the generated token's description only — a label read in Nest's DI
1339
+ // error output, never compared against anything. Mutation testing reports it as surviving for
1340
+ // that reason; no Stryker directive attaches inside this builder chain, so the note lives here.
1341
+ new common.ConfigurableModuleBuilder({ moduleName: "BymaxQueue" }).setClassMethodName("forRoot").setFactoryMethodName("createQueueOptions").setExtras({ isGlobal: true }, (definition, extras) => ({
1342
+ ...definition,
1343
+ global: extras.isGlobal
1344
+ })).build()
1345
+ );
1306
1346
  exports.BymaxQueueModule = class BymaxQueueModule extends ConfigurableModuleClass {
1307
1347
  /**
1308
1348
  * Synchronous registration. Validates options, resolves defaults, and wires the
@@ -354,8 +354,7 @@ type JobSchedulerRepeatOptions = {
354
354
  * for `ready`, closing it on shutdown.
355
355
  */
356
356
  declare class ConnectionResolver {
357
- private readonly options;
358
- private client;
357
+ #private;
359
358
  private mode;
360
359
  constructor(options: BymaxQueueModuleOptions);
361
360
  /** Resolve and validate the connection. Call once during module bootstrap. */
@@ -390,10 +389,10 @@ type CleanableStatus = 'completed' | 'failed' | 'delayed' | 'wait' | 'active' |
390
389
  * enqueueing, inspection, metrics, and lifecycle control.
391
390
  */
392
391
  declare class QueueService {
392
+ #private;
393
393
  private readonly connection;
394
394
  private readonly options;
395
395
  private readonly logger;
396
- private readonly queues;
397
396
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
398
397
  /**
399
398
  * Return the cached `Queue` for `queueName`, or create one with the module
@@ -792,10 +791,10 @@ interface SandboxedWorkerConfig {
792
791
  * })
793
792
  */
794
793
  declare class WorkerRegistry {
794
+ #private;
795
795
  private readonly connection;
796
796
  private readonly options;
797
797
  private readonly logger;
798
- private readonly entries;
799
798
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
800
799
  /**
801
800
  * Register an in-process worker with a handler function. The BullMQ `Worker`
@@ -937,11 +936,10 @@ declare class WorkerRegistry {
937
936
  * qe.on('completed', ({ jobId }) => console.log(jobId))
938
937
  */
939
938
  declare class QueueEventsRegistry {
939
+ #private;
940
940
  private readonly connection;
941
941
  private readonly options;
942
942
  private readonly logger;
943
- private readonly events;
944
- private readonly connections;
945
943
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
946
944
  /**
947
945
  * Returns the cached `QueueEvents` for `queueName`, creating one on first
@@ -354,8 +354,7 @@ type JobSchedulerRepeatOptions = {
354
354
  * for `ready`, closing it on shutdown.
355
355
  */
356
356
  declare class ConnectionResolver {
357
- private readonly options;
358
- private client;
357
+ #private;
359
358
  private mode;
360
359
  constructor(options: BymaxQueueModuleOptions);
361
360
  /** Resolve and validate the connection. Call once during module bootstrap. */
@@ -390,10 +389,10 @@ type CleanableStatus = 'completed' | 'failed' | 'delayed' | 'wait' | 'active' |
390
389
  * enqueueing, inspection, metrics, and lifecycle control.
391
390
  */
392
391
  declare class QueueService {
392
+ #private;
393
393
  private readonly connection;
394
394
  private readonly options;
395
395
  private readonly logger;
396
- private readonly queues;
397
396
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
398
397
  /**
399
398
  * Return the cached `Queue` for `queueName`, or create one with the module
@@ -792,10 +791,10 @@ interface SandboxedWorkerConfig {
792
791
  * })
793
792
  */
794
793
  declare class WorkerRegistry {
794
+ #private;
795
795
  private readonly connection;
796
796
  private readonly options;
797
797
  private readonly logger;
798
- private readonly entries;
799
798
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
800
799
  /**
801
800
  * Register an in-process worker with a handler function. The BullMQ `Worker`
@@ -937,11 +936,10 @@ declare class WorkerRegistry {
937
936
  * qe.on('completed', ({ jobId }) => console.log(jobId))
938
937
  */
939
938
  declare class QueueEventsRegistry {
939
+ #private;
940
940
  private readonly connection;
941
941
  private readonly options;
942
942
  private readonly logger;
943
- private readonly events;
944
- private readonly connections;
945
943
  constructor(connection: ConnectionResolver, options: ResolvedQueueOptions);
946
944
  /**
947
945
  * Returns the cached `QueueEvents` for `queueName`, creating one on first
@@ -4,7 +4,12 @@ import { Redis } from 'ioredis';
4
4
  import { Worker, QueueEvents, Queue, FlowProducer } from 'bullmq';
5
5
  import { isAbsolute, extname } from 'path';
6
6
 
7
+ var __defProp = Object.defineProperty;
7
8
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __typeError = (msg) => {
10
+ throw TypeError(msg);
11
+ };
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
13
  var __decorateClass = (decorators, target, key, kind) => {
9
14
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
10
15
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -13,6 +18,11 @@ var __decorateClass = (decorators, target, key, kind) => {
13
18
  return result;
14
19
  };
15
20
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
21
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
23
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
24
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
25
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
16
26
 
17
27
  // src/shared/constants/error-codes.ts
18
28
  var QUEUE_ERROR_CODES = {
@@ -109,8 +119,8 @@ var DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 3e4;
109
119
 
110
120
  // src/server/config/resolved-options.ts
111
121
  function applyDefaults(opts) {
122
+ const connection = opts.connection;
112
123
  const base = {
113
- connection: opts.connection,
114
124
  defaultJobOptions: { ...DEFAULT_JOB_OPTIONS, ...opts.defaultJobOptions ?? {} },
115
125
  prefix: opts.prefix ?? "bull",
116
126
  queueOptions: opts.queueOptions ?? {},
@@ -126,6 +136,12 @@ function applyDefaults(opts) {
126
136
  connectionReadyTimeoutMs: opts.connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
127
137
  };
128
138
  if (opts.telemetry !== void 0) base.telemetry = opts.telemetry;
139
+ Object.defineProperty(base, "connection", {
140
+ get: () => connection,
141
+ enumerable: false,
142
+ // Stryker disable next-line BooleanLiteral: equivalent HERE — this object is `Object.freeze`d on the way out, and freezing makes every property non-configurable regardless. The flag stays because it states the guarantee at the point the accessor is defined, and because the sibling packages that withhold secrets the same way are NOT frozen, where it is load-bearing
143
+ configurable: false
144
+ });
129
145
  return Object.freeze(base);
130
146
  }
131
147
 
@@ -155,34 +171,44 @@ function duplicateConnection(client) {
155
171
  }
156
172
 
157
173
  // src/server/services/connection-resolver.service.ts
174
+ var _client, _options;
158
175
  var ConnectionResolver = class {
159
176
  constructor(options) {
160
- this.options = options;
177
+ /**
178
+ * The resolved Redis client.
179
+ *
180
+ * An ECMAScript private field rather than a TypeScript `private` one, which
181
+ * is erased at runtime: an ioredis instance carries `options.password` as a
182
+ * plain field, so leaving this enumerable would let anything that serializes
183
+ * a service holding this resolver walk into the credentials.
184
+ */
185
+ __privateAdd(this, _client);
186
+ /** The consumer's module options, which carry the Redis credentials. */
187
+ __privateAdd(this, _options);
188
+ __publicField(this, "mode");
189
+ __privateSet(this, _options, options);
161
190
  }
162
- options;
163
- client;
164
- mode;
165
191
  /** Resolve and validate the connection. Call once during module bootstrap. */
166
192
  async init() {
167
- const cfg = this.options.connection;
193
+ const cfg = __privateGet(this, _options).connection;
168
194
  if ("client" in cfg) {
169
195
  this.initModeA(cfg.client);
170
196
  return;
171
197
  }
172
198
  this.mode = "mode-b-owned";
173
- this.client = "url" in cfg ? new Redis(cfg.url, { ...cfg.options ?? {}, lazyConnect: false }) : new Redis({ ...cfg.options, lazyConnect: false });
199
+ __privateSet(this, _client, "url" in cfg ? new Redis(cfg.url, { ...cfg.options ?? {}, lazyConnect: false }) : new Redis({ ...cfg.options, lazyConnect: false }));
174
200
  await this.waitReady(
175
- this.options.connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
201
+ __privateGet(this, _options).connectionReadyTimeoutMs ?? DEFAULT_CONNECTION_READY_TIMEOUT_MS
176
202
  );
177
203
  }
178
204
  /** The resolved Queue-role client. */
179
205
  getClient() {
180
- if (!this.client) {
206
+ if (!__privateGet(this, _client)) {
181
207
  throw new QueueException(QUEUE_ERROR_CODES.CONNECTION_INVALID, 500, {
182
208
  reason: "not initialized"
183
209
  });
184
210
  }
185
- return this.client;
211
+ return __privateGet(this, _client);
186
212
  }
187
213
  /** The resolved connection mode. */
188
214
  getMode() {
@@ -199,8 +225,8 @@ var ConnectionResolver = class {
199
225
  }
200
226
  /** Close the library-owned connection on shutdown; never touch a BYO client. */
201
227
  async teardown() {
202
- if (this.isOwned() && this.client) {
203
- const client = this.client;
228
+ if (this.isOwned() && __privateGet(this, _client)) {
229
+ const client = __privateGet(this, _client);
204
230
  await client.quit().catch(() => {
205
231
  client.disconnect();
206
232
  });
@@ -209,7 +235,7 @@ var ConnectionResolver = class {
209
235
  /** Validate and adopt a bring-your-own client for the Queue role. */
210
236
  initModeA(client) {
211
237
  this.mode = "mode-a-byo";
212
- this.client = client;
238
+ __privateSet(this, _client, client);
213
239
  if (!isClientUsable(client)) {
214
240
  throw new QueueException(QUEUE_ERROR_CODES.CONNECTION_INVALID, 500, { status: client.status });
215
241
  }
@@ -247,6 +273,8 @@ var ConnectionResolver = class {
247
273
  });
248
274
  }
249
275
  };
276
+ _client = new WeakMap();
277
+ _options = new WeakMap();
250
278
  ConnectionResolver = __decorateClass([
251
279
  Injectable(),
252
280
  __decorateParam(0, Inject(BYMAX_QUEUE_OPTIONS))
@@ -295,15 +323,16 @@ var MAX_BULK_SIZE = 1e3;
295
323
  function isOperationalError(err) {
296
324
  return typeof err?.code === "string";
297
325
  }
326
+ var _queues;
298
327
  var QueueService = class {
299
328
  constructor(connection, options) {
300
329
  this.connection = connection;
301
330
  this.options = options;
331
+ __publicField(this, "logger", new Logger(QueueService.name));
332
+ __privateAdd(this, _queues, /* @__PURE__ */ new Map());
302
333
  }
303
334
  connection;
304
335
  options;
305
- logger = new Logger(QueueService.name);
306
- queues = /* @__PURE__ */ new Map();
307
336
  /**
308
337
  * Return the cached `Queue` for `queueName`, or create one with the module
309
338
  * defaults applied. Subsequent calls with the same name return the same
@@ -313,7 +342,7 @@ var QueueService = class {
313
342
  * @param overrides - Optional per-queue option overrides.
314
343
  */
315
344
  getOrCreateQueue(queueName, overrides) {
316
- const existing = this.queues.get(queueName);
345
+ const existing = __privateGet(this, _queues).get(queueName);
317
346
  if (existing) return existing;
318
347
  const queue = new Queue(queueName, {
319
348
  connection: this.connection.getClient(),
@@ -324,7 +353,7 @@ var QueueService = class {
324
353
  ...overrides
325
354
  });
326
355
  attachDefaultErrorListener(queue, this.logger, "Queue", queueName);
327
- this.queues.set(queueName, queue);
356
+ __privateGet(this, _queues).set(queueName, queue);
328
357
  return queue;
329
358
  }
330
359
  /** Resolve the raw cached queue (default generics) for internal delegation. */
@@ -528,7 +557,7 @@ var QueueService = class {
528
557
  }
529
558
  /** Return a read-only view of the cached queues. */
530
559
  getCachedQueues() {
531
- return this.queues;
560
+ return __privateGet(this, _queues);
532
561
  }
533
562
  /**
534
563
  * Close every cached queue (swallowing per-queue errors) and clear the cache.
@@ -540,12 +569,13 @@ var QueueService = class {
540
569
  * exists to prevent. `QueueLifecycle` is the only caller.
541
570
  */
542
571
  async closeAll() {
543
- for (const queue of this.queues.values()) {
572
+ for (const queue of __privateGet(this, _queues).values()) {
544
573
  await queue.close().catch(() => void 0);
545
574
  }
546
- this.queues.clear();
575
+ __privateGet(this, _queues).clear();
547
576
  }
548
577
  };
578
+ _queues = new WeakMap();
549
579
  QueueService = __decorateClass([
550
580
  Injectable(),
551
581
  __decorateParam(0, Inject(ConnectionResolver)),
@@ -702,15 +732,16 @@ var MetricsService = class {
702
732
  MetricsService = __decorateClass([
703
733
  Injectable()
704
734
  ], MetricsService);
735
+ var _entries;
705
736
  var WorkerRegistry = class {
706
737
  constructor(connection, options) {
707
738
  this.connection = connection;
708
739
  this.options = options;
740
+ __publicField(this, "logger", new Logger(WorkerRegistry.name));
741
+ __privateAdd(this, _entries, /* @__PURE__ */ new Map());
709
742
  }
710
743
  connection;
711
744
  options;
712
- logger = new Logger(WorkerRegistry.name);
713
- entries = /* @__PURE__ */ new Map();
714
745
  /**
715
746
  * Register an in-process worker with a handler function. The BullMQ `Worker`
716
747
  * constructor is synchronous — no Redis handshake is performed at registration
@@ -741,7 +772,7 @@ var WorkerRegistry = class {
741
772
  });
742
773
  }
743
774
  attachDefaultErrorListener(worker, this.logger, "Worker", queueName);
744
- this.entries.set(queueName, { worker, connection: conn });
775
+ __privateGet(this, _entries).set(queueName, { worker, connection: conn });
745
776
  return worker;
746
777
  }
747
778
  /**
@@ -780,7 +811,7 @@ var WorkerRegistry = class {
780
811
  });
781
812
  }
782
813
  attachDefaultErrorListener(worker, this.logger, "Worker", queueName);
783
- this.entries.set(queueName, { worker, connection: conn });
814
+ __privateGet(this, _entries).set(queueName, { worker, connection: conn });
784
815
  return worker;
785
816
  }
786
817
  /**
@@ -791,11 +822,11 @@ var WorkerRegistry = class {
791
822
  * @param queueName - The queue whose worker should be removed.
792
823
  */
793
824
  async unregister(queueName) {
794
- const entry = this.entries.get(queueName);
825
+ const entry = __privateGet(this, _entries).get(queueName);
795
826
  if (!entry) return;
796
827
  await entry.worker.close();
797
828
  await this.closeConnection(entry.connection);
798
- this.entries.delete(queueName);
829
+ __privateGet(this, _entries).delete(queueName);
799
830
  }
800
831
  /**
801
832
  * Returns the queue names of all currently registered workers.
@@ -803,7 +834,7 @@ var WorkerRegistry = class {
803
834
  * @returns An immutable array of queue names.
804
835
  */
805
836
  list() {
806
- return Array.from(this.entries.keys());
837
+ return Array.from(__privateGet(this, _entries).keys());
807
838
  }
808
839
  /**
809
840
  * Returns a read-only view of the registered workers keyed by queue name.
@@ -813,7 +844,7 @@ var WorkerRegistry = class {
813
844
  */
814
845
  getAll() {
815
846
  return new Map(
816
- Array.from(this.entries, ([name, entry]) => [name, entry.worker])
847
+ Array.from(__privateGet(this, _entries), ([name, entry]) => [name, entry.worker])
817
848
  );
818
849
  }
819
850
  /**
@@ -826,7 +857,7 @@ var WorkerRegistry = class {
826
857
  */
827
858
  getConnections() {
828
859
  return new Map(
829
- Array.from(this.entries, ([name, entry]) => [name, entry.connection])
860
+ Array.from(__privateGet(this, _entries), ([name, entry]) => [name, entry.connection])
830
861
  );
831
862
  }
832
863
  /**
@@ -849,7 +880,7 @@ var WorkerRegistry = class {
849
880
  * @throws {QueueException} `DUPLICATE_PROCESSOR` if the queue is already registered.
850
881
  */
851
882
  guardDuplicate(queueName) {
852
- if (this.entries.has(queueName)) {
883
+ if (__privateGet(this, _entries).has(queueName)) {
853
884
  throw new QueueException(QUEUE_ERROR_CODES.DUPLICATE_PROCESSOR, 500, { queueName });
854
885
  }
855
886
  }
@@ -958,21 +989,23 @@ var WorkerRegistry = class {
958
989
  return result;
959
990
  }
960
991
  };
992
+ _entries = new WeakMap();
961
993
  WorkerRegistry = __decorateClass([
962
994
  Injectable(),
963
995
  __decorateParam(0, Inject(ConnectionResolver)),
964
996
  __decorateParam(1, Inject(BYMAX_QUEUE_RESOLVED_OPTIONS))
965
997
  ], WorkerRegistry);
998
+ var _events, _connections;
966
999
  var QueueEventsRegistry = class {
967
1000
  constructor(connection, options) {
968
1001
  this.connection = connection;
969
1002
  this.options = options;
1003
+ __publicField(this, "logger", new Logger(QueueEventsRegistry.name));
1004
+ __privateAdd(this, _events, /* @__PURE__ */ new Map());
1005
+ __privateAdd(this, _connections, /* @__PURE__ */ new Map());
970
1006
  }
971
1007
  connection;
972
1008
  options;
973
- logger = new Logger(QueueEventsRegistry.name);
974
- events = /* @__PURE__ */ new Map();
975
- connections = /* @__PURE__ */ new Map();
976
1009
  /**
977
1010
  * Returns the cached `QueueEvents` for `queueName`, creating one on first
978
1011
  * call. Subsequent calls for the same name return the same instance without
@@ -982,7 +1015,7 @@ var QueueEventsRegistry = class {
982
1015
  * @returns The `QueueEvents` instance for the queue.
983
1016
  */
984
1017
  getOrCreate(queueName) {
985
- const existing = this.events.get(queueName);
1018
+ const existing = __privateGet(this, _events).get(queueName);
986
1019
  if (existing) return existing;
987
1020
  const conn = duplicateConnection(this.connection.getClient());
988
1021
  let qe;
@@ -993,8 +1026,8 @@ var QueueEventsRegistry = class {
993
1026
  throw err;
994
1027
  }
995
1028
  attachDefaultErrorListener(qe, this.logger, "QueueEvents", queueName);
996
- this.events.set(queueName, qe);
997
- this.connections.set(queueName, conn);
1029
+ __privateGet(this, _events).set(queueName, qe);
1030
+ __privateGet(this, _connections).set(queueName, conn);
998
1031
  return qe;
999
1032
  }
1000
1033
  /**
@@ -1003,7 +1036,7 @@ var QueueEventsRegistry = class {
1003
1036
  * @returns An immutable array of queue names.
1004
1037
  */
1005
1038
  list() {
1006
- return Array.from(this.events.keys());
1039
+ return Array.from(__privateGet(this, _events).keys());
1007
1040
  }
1008
1041
  /**
1009
1042
  * Returns the live `QueueEvents` map. Intended for the shutdown orchestrator.
@@ -1011,7 +1044,7 @@ var QueueEventsRegistry = class {
1011
1044
  * @returns A read-only view of the internal map.
1012
1045
  */
1013
1046
  getAll() {
1014
- return this.events;
1047
+ return __privateGet(this, _events);
1015
1048
  }
1016
1049
  /**
1017
1050
  * Returns a read-only view of the duplicated connections the library opened
@@ -1027,9 +1060,11 @@ var QueueEventsRegistry = class {
1027
1060
  * @returns A read-only snapshot of queue name to duplicated connection.
1028
1061
  */
1029
1062
  getConnections() {
1030
- return new Map(this.connections);
1063
+ return new Map(__privateGet(this, _connections));
1031
1064
  }
1032
1065
  };
1066
+ _events = new WeakMap();
1067
+ _connections = new WeakMap();
1033
1068
  QueueEventsRegistry = __decorateClass([
1034
1069
  Injectable(),
1035
1070
  __decorateParam(0, Inject(ConnectionResolver)),
@@ -1297,10 +1332,15 @@ QueueLifecycle = __decorateClass([
1297
1332
  ], QueueLifecycle);
1298
1333
 
1299
1334
  // src/server/bymax-queue.module.ts
1300
- var { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = new ConfigurableModuleBuilder({ moduleName: "BymaxQueue" }).setClassMethodName("forRoot").setFactoryMethodName("createQueueOptions").setExtras({ isGlobal: true }, (definition, extras) => ({
1301
- ...definition,
1302
- global: extras.isGlobal
1303
- })).build();
1335
+ var { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = (
1336
+ // The `moduleName` shapes the generated token's description only — a label read in Nest's DI
1337
+ // error output, never compared against anything. Mutation testing reports it as surviving for
1338
+ // that reason; no Stryker directive attaches inside this builder chain, so the note lives here.
1339
+ new ConfigurableModuleBuilder({ moduleName: "BymaxQueue" }).setClassMethodName("forRoot").setFactoryMethodName("createQueueOptions").setExtras({ isGlobal: true }, (definition, extras) => ({
1340
+ ...definition,
1341
+ global: extras.isGlobal
1342
+ })).build()
1343
+ );
1304
1344
  var BymaxQueueModule = class extends ConfigurableModuleClass {
1305
1345
  /**
1306
1346
  * Synchronous registration. Validates options, resolves defaults, and wires the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-queue",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "NestJS dynamic module wrapping BullMQ — typed jobs, flows, job schedulers, deduplication, OpenTelemetry, graceful shutdown",
5
5
  "author": "Bymax One <support@bymax.one>",
6
6
  "license": "MIT",
@@ -146,7 +146,7 @@
146
146
  "prettier --write"
147
147
  ]
148
148
  },
149
- "packageManager": "pnpm@11.0.0",
149
+ "packageManager": "pnpm@11.20.0",
150
150
  "engines": {
151
151
  "node": ">=24.0.0"
152
152
  },