@zintrust/workers 0.4.27 → 0.4.34

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.
@@ -100,7 +100,6 @@ const resolvePackageSpecifierUrl = (specifier) => {
100
100
  return resolveLocalPackageFallback(specifier);
101
101
  }
102
102
  };
103
- const escapeRegExp = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
104
103
  const rewriteProcessorImports = (code) => {
105
104
  const replacements = [];
106
105
  const coreUrl = resolvePackageSpecifierUrl('@zintrust/core');
@@ -113,8 +112,8 @@ const rewriteProcessorImports = (code) => {
113
112
  return code;
114
113
  let updated = code;
115
114
  for (const { from, to } of replacements) {
116
- const pattern = new RegExp(String.raw `(['"])${escapeRegExp(from)}\1`, 'g');
117
- updated = updated.replace(pattern, `$1${to}$1`);
115
+ updated = updated.replaceAll(`'${from}'`, `'${to}'`);
116
+ updated = updated.replaceAll(`"${from}"`, `"${to}"`);
118
117
  }
119
118
  return updated;
120
119
  };
@@ -330,14 +329,43 @@ const parseCacheControl = (value) => {
330
329
  };
331
330
  const getProcessorSpecConfig = () => workersConfig.processorSpec;
332
331
  const toPosixPath = (value) => value.split(path.sep).join('/');
332
+ const isUpperAlpha = (value) => /^[A-Z]$/.test(value);
333
+ const isLowerAlphaOrDigit = (value) => /^[a-z\d]$/.test(value);
334
+ const isAlphaNumeric = (value) => /^[A-Za-z\d]$/.test(value);
335
+ const shouldInsertWorkerNameDash = (previous, current, next) => {
336
+ if (!isAlphaNumeric(previous) || !isAlphaNumeric(current))
337
+ return false;
338
+ if (isLowerAlphaOrDigit(previous) && isUpperAlpha(current)) {
339
+ return true;
340
+ }
341
+ if (isUpperAlpha(previous) && isUpperAlpha(current) && isLowerAlphaOrDigit(next ?? '')) {
342
+ return true;
343
+ }
344
+ return false;
345
+ };
346
+ const toKebabWorkerName = (value) => {
347
+ if (!isNonEmptyString(value))
348
+ return value;
349
+ let normalized = '';
350
+ for (let index = 0; index < value.length; index += 1) {
351
+ const current = value[index] ?? '';
352
+ const previous = index > 0 ? (value[index - 1] ?? '') : '';
353
+ const next = value[index + 1];
354
+ if (current === ' ' || current === '_') {
355
+ if (!normalized.endsWith('-'))
356
+ normalized += '-';
357
+ continue;
358
+ }
359
+ if (shouldInsertWorkerNameDash(previous, current, next) && !normalized.endsWith('-')) {
360
+ normalized += '-';
361
+ }
362
+ normalized += current;
363
+ }
364
+ return normalized.replaceAll(/-+/g, '-');
365
+ };
333
366
  const normalizeWorkerFileName = (fileName) => {
334
- const baseName = fileName.replaceAll(/\.[^.]+$/, '');
335
- return baseName
336
- .replaceAll(/([a-z\d])([A-Z])/g, '$1-$2')
337
- .replaceAll(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1-$2')
338
- .replaceAll(/[\s_]+/g, '-')
339
- .replaceAll(/-+/g, '-')
340
- .toLowerCase();
367
+ const baseName = fileName.replace(/\.[^.]+$/, '');
368
+ return toKebabWorkerName(baseName).toLowerCase();
341
369
  };
342
370
  const supportsWorkerFileDiscovery = () => {
343
371
  return (isNodeRuntime() &&
@@ -1364,19 +1392,15 @@ const resolveRedisConfigFromEnv = (config, context) => {
1364
1392
  };
1365
1393
  const resolveRedisConfigFromDirect = (config, context) => {
1366
1394
  const fallbackDb = Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB);
1367
- const redisConfigWithDatabase = config;
1368
1395
  let normalizedDb = fallbackDb;
1369
1396
  if (typeof config.db === 'number') {
1370
1397
  normalizedDb = config.db;
1371
1398
  }
1372
- else if (typeof redisConfigWithDatabase.database === 'number') {
1373
- normalizedDb = redisConfigWithDatabase.database;
1374
- }
1375
1399
  return {
1376
1400
  host: requireRedisHost(config.host, context),
1377
1401
  port: config.port,
1378
1402
  db: normalizedDb,
1379
- password: config.password ?? Env.get('REDIS_PASSWORD', undefined),
1403
+ password: config.password ?? Env.get('REDIS_PASSWORD'),
1380
1404
  };
1381
1405
  };
1382
1406
  const resolveRedisConfig = (config, context) => isRedisEnvConfig(config)
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@zintrust/workers",
3
- "version": "0.1.52",
4
- "buildDate": "2026-03-26T09:12:29.177Z",
3
+ "version": "0.4.34",
4
+ "buildDate": "2026-03-29T19:24:26.213Z",
5
5
  "buildEnvironment": {
6
- "node": "v25.6.1",
6
+ "node": "v22.22.1",
7
7
  "platform": "darwin",
8
8
  "arch": "arm64"
9
9
  },
10
10
  "git": {
11
- "commit": "597f453f",
11
+ "commit": "4abfecc6",
12
12
  "branch": "dev"
13
13
  },
14
14
  "package": {
@@ -19,7 +19,6 @@
19
19
  "@opentelemetry/api",
20
20
  "hot-shots",
21
21
  "ioredis",
22
- "ml.js",
23
22
  "prom-client",
24
23
  "simple-statistics"
25
24
  ],
@@ -47,8 +46,8 @@
47
46
  "sha256": "1a6d9ea39ba9e17fc16eb52294c10c3912024cb3009a8f9c07ffa576e754c7f4"
48
47
  },
49
48
  "BroadcastWorker.d.ts": {
50
- "size": 793,
51
- "sha256": "63d5877e1363fd8f43cd0b0f63efca27a46e46fc2203cc073bd4110bb8e673b9"
49
+ "size": 934,
50
+ "sha256": "ea5b05820fdd30d80f4483f476e400c78fa842ebbb29a442b2f1261dc0b2de8a"
52
51
  },
53
52
  "BroadcastWorker.js": {
54
53
  "size": 821,
@@ -127,8 +126,8 @@
127
126
  "sha256": "23837171b31c5242e4b43226cb0acae815dea0ce7b1628aa1428a86b24689230"
128
127
  },
129
128
  "NotificationWorker.d.ts": {
130
- "size": 811,
131
- "sha256": "dd22674e6955c32c7ac7af8af8fee583e62d4f0e224da14a72a7f1799e734f96"
129
+ "size": 952,
130
+ "sha256": "facdae5d7e82364ad9aab4398f8a3f8b5be8d8e9cb3aaa18fde76a88cd05b959"
132
131
  },
133
132
  "NotificationWorker.js": {
134
133
  "size": 828,
@@ -175,20 +174,20 @@
175
174
  "sha256": "555277c91f87899415cebf35eddc08d7c0b80cc55bfac7cb7fe96529cc927257"
176
175
  },
177
176
  "WorkerFactory.d.ts": {
178
- "size": 7447,
179
- "sha256": "b31131698eae955a7fcd6d3ef872d0bc1d3557c7f18695850e9407707fcf548d"
177
+ "size": 7716,
178
+ "sha256": "3869f960c87260588e40941ff91bffcfa0757be7a04815fd28b57dd4840c51df"
180
179
  },
181
180
  "WorkerFactory.js": {
182
- "size": 90728,
183
- "sha256": "231c5af0f6b472649e82a9a062479f68dec18ea8c8298443e40d02fe3c9338f4"
181
+ "size": 102783,
182
+ "sha256": "f2928a648eaedba8b8c9f6e211cd6fc5e8a5bb531dc656899b20db7ddaa702b9"
184
183
  },
185
184
  "WorkerInit.d.ts": {
186
- "size": 2391,
187
- "sha256": "8a6fdec7b592dd92162b3ad1b3d3fd6462abcf11028e510dbdb747748774d626"
185
+ "size": 3284,
186
+ "sha256": "f902550cda7fca36f2db6297d39a4339ed6b5ff1c738da867233309cf0ca8fe1"
188
187
  },
189
188
  "WorkerInit.js": {
190
- "size": 11908,
191
- "sha256": "71e4fd64b44d48b0bbd2fbebfb71fcf75c528734e90359994c492f9cc2590df6"
189
+ "size": 14031,
190
+ "sha256": "51f44ca085a1682130aa36fed3acfd575108e974bf4c21eaa772001719c18853"
192
191
  },
193
192
  "WorkerMetrics.d.ts": {
194
193
  "size": 3304,
@@ -231,8 +230,8 @@
231
230
  "sha256": "8af20d462270e7044c6ea983821f5b6e6ce8a5caf39b6e8fefff07c9a0bf071e"
232
231
  },
233
232
  "build-manifest.json": {
234
- "size": 19603,
235
- "sha256": "ee6386bb995df82724f76c33f1333c0f77863bff9c3cb6007ac2fd20969dec90"
233
+ "size": 19590,
234
+ "sha256": "627732a0b46235bfeb923176bfc8e40265d42bc5abac5250002e431301a552e2"
236
235
  },
237
236
  "config/workerConfig.d.ts": {
238
237
  "size": 132,
@@ -243,12 +242,12 @@
243
242
  "sha256": "189c3b1d8a31de1c04206fcfacc1fed974a74684d7d70895cd20a03b35860ac6"
244
243
  },
245
244
  "createQueueWorker.d.ts": {
246
- "size": 890,
247
- "sha256": "c0e07ac27f1ec74fff817ce82eb1cbcfae45ab3cd079748766dcbf4a73c5ec98"
245
+ "size": 1031,
246
+ "sha256": "dacd49f6c112eba439bdd9bb457eea90daedbf32efc381cd3189ce562fa5b0a8"
248
247
  },
249
248
  "createQueueWorker.js": {
250
- "size": 13717,
251
- "sha256": "b8cfe312445a150824d26ba3867147aa6a10e8dece2e342c7447404fb7fa4991"
249
+ "size": 14103,
250
+ "sha256": "8e619da00200c0c1270674a6a2941ae050c8ade3e38925b5446916cddc2a8b65"
252
251
  },
253
252
  "dashboard/index.d.ts": {
254
253
  "size": 109,
@@ -271,8 +270,8 @@
271
270
  "sha256": "8e0e04329e1119d8ae835dd4458efead084293bcc2c263c09dd5a19d467e5ca4"
272
271
  },
273
272
  "dashboard/workers-api.js": {
274
- "size": 26774,
275
- "sha256": "8d49b06c88df07afabfb49a4d3a4459e3f40340eccd03610d6be9095409e422e"
273
+ "size": 28207,
274
+ "sha256": "ae1ff0e962b1f64e6d200a35c3b8b1de968341d8df6283625a3efce50a23826c"
276
275
  },
277
276
  "helper/index.d.ts": {
278
277
  "size": 159,
@@ -411,12 +410,12 @@
411
410
  "sha256": "e90a171f2d8f6a62518099f825775b80299b934a7d48421bc1a3ebd6b065d617"
412
411
  },
413
412
  "index.d.ts": {
414
- "size": 2601,
415
- "sha256": "6943403aba7442451a5abd3eb64a12d2842bb310360477b5a7180cf3b4373efa"
413
+ "size": 2721,
414
+ "sha256": "0dcb7ca21683ab210eeb23d067e41b55ae996fa9e52c688371dc177f070ec059"
416
415
  },
417
416
  "index.js": {
418
- "size": 2261,
419
- "sha256": "afd4bf4715321d1e073366a7cb93ac17a1f9f647500ac4027102de65f26bc213"
417
+ "size": 2337,
418
+ "sha256": "223686f6a65ebbea5599bdb509d8857d1cbdf57d20669a8d00eee5190ff654d3"
420
419
  },
421
420
  "register.d.ts": {
422
421
  "size": 256,
@@ -1,5 +1,6 @@
1
1
  import * as Core from '@zintrust/core';
2
2
  import { Env, Logger, Queue } from '@zintrust/core';
3
+ const TypedQueue = Queue;
3
4
  const RETRY_BASE_DELAY_MS = 1000;
4
5
  const RETRY_MAX_DELAY_MS = 30000;
5
6
  const getJobStateTracker = () => {
@@ -92,6 +93,12 @@ const buildBaseLogFields = (message, getLogFields) => {
92
93
  ...getLogFields(message.payload),
93
94
  };
94
95
  };
96
+ const toBullMQPayload = (payload) => {
97
+ if (typeof payload === 'object' && payload !== null) {
98
+ return { ...payload };
99
+ }
100
+ return { payload };
101
+ };
95
102
  const getWorkerInstanceId = () => {
96
103
  return typeof Env['WORKER_INSTANCE_ID'] === 'string'
97
104
  ? String(Env['WORKER_INSTANCE_ID'])
@@ -139,12 +146,12 @@ const checkAndRequeueIfNotDue = async (options, queueName, driverName, message,
139
146
  ...baseLogFields,
140
147
  dueAt: new Date(timestamp).toISOString(),
141
148
  });
142
- await Queue.enqueue(queueName, message.payload, driverName);
143
- await Queue.ack(queueName, message.id, driverName);
149
+ await TypedQueue.enqueue(queueName, toBullMQPayload(message.payload), driverName);
150
+ await TypedQueue.ack(queueName, message.id, driverName);
144
151
  return true;
145
152
  };
146
153
  const onProcessSuccess = async (input) => {
147
- await Queue.ack(input.queueName, input.message.id, input.driverName);
154
+ await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
148
155
  if (typeof input.trackerApi.completed === 'function') {
149
156
  await input.trackerApi.completed({
150
157
  queueName: input.queueName,
@@ -177,22 +184,20 @@ const onProcessFailure = async (input) => {
177
184
  if (nextAttempts < input.options.maxAttempts) {
178
185
  const retryDelayMs = getRetryDelayMs(nextAttempts);
179
186
  retryAt = new Date(Date.now() + retryDelayMs).toISOString();
180
- const currentPayload = typeof input.message.payload === 'object' && input.message.payload !== null
181
- ? input.message.payload
182
- : { payload: input.message.payload };
187
+ const currentPayload = toBullMQPayload(input.message.payload);
183
188
  const payloadForRetry = {
184
189
  ...currentPayload,
185
190
  attempts: nextAttempts,
186
191
  timestamp: Date.now() + retryDelayMs,
187
192
  };
188
- await Queue.enqueue(input.queueName, payloadForRetry, input.driverName);
193
+ await TypedQueue.enqueue(input.queueName, payloadForRetry, input.driverName);
189
194
  Logger.info(`${input.options.kindLabel} re-queued for retry`, {
190
195
  ...input.baseLogFields,
191
196
  attempts: nextAttempts,
192
197
  retryDelayMs,
193
198
  });
194
199
  }
195
- await Queue.ack(input.queueName, input.message.id, input.driverName);
200
+ await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
196
201
  await removeHeartbeatIfSupported(input.queueName, input.message.id);
197
202
  if (typeof input.trackerApi.failed === 'function') {
198
203
  await input.trackerApi.failed({
@@ -235,7 +240,7 @@ const startTrackingAndHeartbeat = async (input) => {
235
240
  return { startedAtMs, heartbeatTimer };
236
241
  };
237
242
  const processQueueMessage = async (options, queueName, driverName) => {
238
- const message = (await Queue.dequeue(queueName, driverName));
243
+ const message = await TypedQueue.dequeue(queueName, driverName);
239
244
  if (!message)
240
245
  return false;
241
246
  const baseLogFields = buildBaseLogFields(message, options.getLogFields);
package/dist/index.d.ts CHANGED
@@ -32,11 +32,12 @@ export { BroadcastWorker } from './BroadcastWorker';
32
32
  export { createQueueWorker } from './createQueueWorker';
33
33
  export type { CreateQueueWorkerOptions } from './createQueueWorker';
34
34
  export { NotificationWorker } from './NotificationWorker';
35
- export type { RedisConfig, WorkerAutoScalingConfig, WorkerComplianceConfig, WorkerConfig, WorkerCostConfig, WorkerObservabilityConfig, WorkerStatus, WorkerVersioningConfig, WorkersConfigOverrides, WorkersGlobalConfig, } from '@zintrust/core';
35
+ export type { RedisConfig, WorkerAutoScalingConfig, WorkerComplianceConfig, WorkerConfig, WorkerCostConfig, WorkerObservabilityConfig, WorkersConfigOverrides, WorkersGlobalConfig, WorkerStatus, WorkerVersioningConfig, } from '@zintrust/core';
36
36
  export type { Job, Worker, WorkerOptions } from 'bullmq';
37
37
  export type { IAnomaly, IAnomalyConfig, IForecast, IMetric, IPrediction, IRecommendation, IRootCauseAnalysis, } from './AnomalyDetection';
38
38
  export type { IChaosComparison, IChaosExperiment, IChaosReport, IChaosStatus, } from './ChaosEngineering';
39
39
  export type { ISLAConfig, ISLAReport, ISLAStatus, ISLAViolation, ITimeRange } from './SLAMonitor';
40
+ export type * from './config/workerConfig';
40
41
  export type * from './type';
41
42
  /**
42
43
  * Package version and build metadata
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/workers",
3
- "version": "0.4.27",
3
+ "version": "0.4.34",
4
4
  "description": "Worker orchestration and background job management for ZinTrust.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@zintrust/core": "^0.4.27",
43
+ "@zintrust/core": "^0.4.34",
44
44
  "@zintrust/queue-monitor": "*",
45
45
  "@zintrust/queue-redis": "*"
46
46
  },
@@ -141,9 +141,6 @@ const resolvePackageSpecifierUrl = (specifier: string): string | null => {
141
141
  }
142
142
  };
143
143
 
144
- const escapeRegExp = (value: string): string =>
145
- value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
146
-
147
144
  const rewriteProcessorImports = (code: string): string => {
148
145
  const replacements: Array<{ from: string; to: string }> = [];
149
146
  const coreUrl = resolvePackageSpecifierUrl('@zintrust/core');
@@ -155,8 +152,8 @@ const rewriteProcessorImports = (code: string): string => {
155
152
 
156
153
  let updated = code;
157
154
  for (const { from, to } of replacements) {
158
- const pattern = new RegExp(String.raw`(['"])${escapeRegExp(from)}\1`, 'g');
159
- updated = updated.replace(pattern, `$1${to}$1`);
155
+ updated = updated.replaceAll(`'${from}'`, `'${to}'`);
156
+ updated = updated.replaceAll(`"${from}"`, `"${to}"`);
160
157
  }
161
158
 
162
159
  return updated;
@@ -548,14 +545,58 @@ const getProcessorSpecConfig = (): typeof workersConfig.processorSpec =>
548
545
 
549
546
  const toPosixPath = (value: string): string => value.split(path.sep).join('/');
550
547
 
548
+ const isUpperAlpha = (value: string): boolean => /^[A-Z]$/.test(value);
549
+
550
+ const isLowerAlphaOrDigit = (value: string): boolean => /^[a-z\d]$/.test(value);
551
+
552
+ const isAlphaNumeric = (value: string): boolean => /^[A-Za-z\d]$/.test(value);
553
+
554
+ const shouldInsertWorkerNameDash = (
555
+ previous: string,
556
+ current: string,
557
+ next: string | undefined
558
+ ): boolean => {
559
+ if (!isAlphaNumeric(previous) || !isAlphaNumeric(current)) return false;
560
+
561
+ if (isLowerAlphaOrDigit(previous) && isUpperAlpha(current)) {
562
+ return true;
563
+ }
564
+
565
+ if (isUpperAlpha(previous) && isUpperAlpha(current) && isLowerAlphaOrDigit(next ?? '')) {
566
+ return true;
567
+ }
568
+
569
+ return false;
570
+ };
571
+
572
+ const toKebabWorkerName = (value: string): string => {
573
+ if (!isNonEmptyString(value)) return value;
574
+
575
+ let normalized = '';
576
+
577
+ for (let index = 0; index < value.length; index += 1) {
578
+ const current = value[index] ?? '';
579
+ const previous = index > 0 ? (value[index - 1] ?? '') : '';
580
+ const next = value[index + 1];
581
+
582
+ if (current === ' ' || current === '_') {
583
+ if (!normalized.endsWith('-')) normalized += '-';
584
+ continue;
585
+ }
586
+
587
+ if (shouldInsertWorkerNameDash(previous, current, next) && !normalized.endsWith('-')) {
588
+ normalized += '-';
589
+ }
590
+
591
+ normalized += current;
592
+ }
593
+
594
+ return normalized.replaceAll(/-+/g, '-');
595
+ };
596
+
551
597
  const normalizeWorkerFileName = (fileName: string): string => {
552
- const baseName = fileName.replaceAll(/\.[^.]+$/, '');
553
- return baseName
554
- .replaceAll(/([a-z\d])([A-Z])/g, '$1-$2')
555
- .replaceAll(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1-$2')
556
- .replaceAll(/[\s_]+/g, '-')
557
- .replaceAll(/-+/g, '-')
558
- .toLowerCase();
598
+ const baseName = fileName.replace(/\.[^.]+$/, '');
599
+ return toKebabWorkerName(baseName).toLowerCase();
559
600
  };
560
601
 
561
602
  const supportsWorkerFileDiscovery = (): boolean => {
@@ -1984,20 +2025,17 @@ const resolveRedisConfigFromEnv = (config: RedisEnvConfig, context: string): Red
1984
2025
 
1985
2026
  const resolveRedisConfigFromDirect = (config: RedisConfig, context: string): RedisConfig => {
1986
2027
  const fallbackDb = Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB);
1987
- const redisConfigWithDatabase = config as RedisConfig & { database?: number };
1988
2028
 
1989
2029
  let normalizedDb = fallbackDb;
1990
2030
  if (typeof config.db === 'number') {
1991
2031
  normalizedDb = config.db;
1992
- } else if (typeof redisConfigWithDatabase.database === 'number') {
1993
- normalizedDb = redisConfigWithDatabase.database;
1994
2032
  }
1995
2033
 
1996
2034
  return {
1997
2035
  host: requireRedisHost(config.host, context),
1998
2036
  port: config.port,
1999
2037
  db: normalizedDb,
2000
- password: config.password ?? Env.get('REDIS_PASSWORD', undefined),
2038
+ password: config.password ?? Env.get('REDIS_PASSWORD'),
2001
2039
  };
2002
2040
  };
2003
2041
 
@@ -2,6 +2,17 @@ import type { BullMQPayload, QueueMessage } from '@zintrust/core';
2
2
  import * as Core from '@zintrust/core';
3
3
  import { Env, Logger, Queue } from '@zintrust/core';
4
4
 
5
+ type QueueApi = Readonly<{
6
+ enqueue: (queue: string, payload: BullMQPayload, driverName?: string) => Promise<string>;
7
+ dequeue: <TPayload>(
8
+ queue: string,
9
+ driverName?: string
10
+ ) => Promise<QueueMessage<TPayload> | undefined>;
11
+ ack: (queue: string, id: string, driverName?: string) => Promise<void>;
12
+ }>;
13
+
14
+ const TypedQueue = Queue as QueueApi;
15
+
5
16
  const RETRY_BASE_DELAY_MS = 1000;
6
17
  const RETRY_MAX_DELAY_MS = 30000;
7
18
 
@@ -97,9 +108,7 @@ const getAttemptsFromMessage = <TPayload>(message: QueueMessage<TPayload>): numb
97
108
  typeof message.payload === 'object' && message.payload !== null
98
109
  ? normalizeAttempts((message.payload as Record<string, unknown>)['attempts'])
99
110
  : 0;
100
- const messageAttempts = normalizeAttempts(
101
- (message as QueueMessage<TPayload> & { attempts?: number }).attempts
102
- );
111
+ const messageAttempts = normalizeAttempts(message.attempts);
103
112
  return Math.max(payloadAttempts, messageAttempts);
104
113
  };
105
114
 
@@ -152,6 +161,14 @@ const buildBaseLogFields = <TPayload>(
152
161
  };
153
162
  };
154
163
 
164
+ const toBullMQPayload = <TPayload>(payload: TPayload): BullMQPayload => {
165
+ if (typeof payload === 'object' && payload !== null) {
166
+ return { ...(payload as Record<string, unknown>) };
167
+ }
168
+
169
+ return { payload };
170
+ };
171
+
155
172
  type TrackerApi = {
156
173
  started?: (input: {
157
174
  queueName: string;
@@ -263,8 +280,8 @@ const checkAndRequeueIfNotDue = async <TPayload>(
263
280
  ...baseLogFields,
264
281
  dueAt: new Date(timestamp).toISOString(),
265
282
  });
266
- await Queue.enqueue(queueName, message.payload as BullMQPayload, driverName);
267
- await Queue.ack(queueName, message.id, driverName);
283
+ await TypedQueue.enqueue(queueName, toBullMQPayload(message.payload), driverName);
284
+ await TypedQueue.ack(queueName, message.id, driverName);
268
285
  return true;
269
286
  };
270
287
 
@@ -277,7 +294,7 @@ const onProcessSuccess = async <TPayload>(input: {
277
294
  startedAtMs: number;
278
295
  baseLogFields: Record<string, unknown>;
279
296
  }): Promise<boolean> => {
280
- await Queue.ack(input.queueName, input.message.id, input.driverName);
297
+ await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
281
298
 
282
299
  if (typeof input.trackerApi.completed === 'function') {
283
300
  await input.trackerApi.completed({
@@ -324,10 +341,7 @@ const onProcessFailure = async <TPayload>(input: {
324
341
  if (nextAttempts < input.options.maxAttempts) {
325
342
  const retryDelayMs = getRetryDelayMs(nextAttempts);
326
343
  retryAt = new Date(Date.now() + retryDelayMs).toISOString();
327
- const currentPayload =
328
- typeof input.message.payload === 'object' && input.message.payload !== null
329
- ? (input.message.payload as Record<string, unknown>)
330
- : ({ payload: input.message.payload } as Record<string, unknown>);
344
+ const currentPayload = toBullMQPayload(input.message.payload);
331
345
 
332
346
  const payloadForRetry: BullMQPayload = {
333
347
  ...currentPayload,
@@ -335,7 +349,7 @@ const onProcessFailure = async <TPayload>(input: {
335
349
  timestamp: Date.now() + retryDelayMs,
336
350
  };
337
351
 
338
- await Queue.enqueue(input.queueName, payloadForRetry, input.driverName);
352
+ await TypedQueue.enqueue(input.queueName, payloadForRetry, input.driverName);
339
353
  Logger.info(`${input.options.kindLabel} re-queued for retry`, {
340
354
  ...input.baseLogFields,
341
355
  attempts: nextAttempts,
@@ -343,7 +357,7 @@ const onProcessFailure = async <TPayload>(input: {
343
357
  });
344
358
  }
345
359
 
346
- await Queue.ack(input.queueName, input.message.id, input.driverName);
360
+ await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
347
361
  await removeHeartbeatIfSupported(input.queueName, input.message.id);
348
362
 
349
363
  if (typeof input.trackerApi.failed === 'function') {
@@ -409,7 +423,7 @@ const processQueueMessage = async <TPayload>(
409
423
  queueName: string,
410
424
  driverName?: string
411
425
  ): Promise<boolean> => {
412
- const message = (await Queue.dequeue(queueName, driverName)) as QueueMessage<TPayload> | null;
426
+ const message = await TypedQueue.dequeue<TPayload>(queueName, driverName);
413
427
  if (!message) return false;
414
428
 
415
429
  const baseLogFields = buildBaseLogFields(message, options.getLogFields);
package/src/index.ts CHANGED
@@ -71,10 +71,10 @@ export type {
71
71
  WorkerConfig,
72
72
  WorkerCostConfig,
73
73
  WorkerObservabilityConfig,
74
- WorkerStatus,
75
- WorkerVersioningConfig,
76
74
  WorkersConfigOverrides,
77
75
  WorkersGlobalConfig,
76
+ WorkerStatus,
77
+ WorkerVersioningConfig,
78
78
  } from '@zintrust/core';
79
79
 
80
80
  // Re-export bullmq types for type compatibility
@@ -97,6 +97,7 @@ export type {
97
97
  } from './ChaosEngineering';
98
98
  export type { ISLAConfig, ISLAReport, ISLAStatus, ISLAViolation, ITimeRange } from './SLAMonitor';
99
99
 
100
+ export type * from './config/workerConfig';
100
101
  export type * from './type';
101
102
 
102
103
  /**