@zintrust/core 2.2.1 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
package/src/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @zintrust/core v2.2.1
2
+ * @zintrust/core v2.2.2
3
3
  *
4
4
  * ZinTrust Framework - Production-Grade TypeScript Backend
5
5
  * Built for performance, type safety, and exceptional developer experience
6
6
  *
7
7
  * Build Information:
8
- * Built: 2026-05-27T19:51:45.261Z
8
+ * Built: 2026-05-28T12:49:02.769Z
9
9
  * Node: >=20.0.0
10
10
  * License: MIT
11
11
  *
@@ -21,7 +21,7 @@
21
21
  * Available at runtime for debugging and health checks
22
22
  */
23
23
  export const ZINTRUST_VERSION = '0.1.41';
24
- export const ZINTRUST_BUILD_DATE = '2026-05-27T19:51:45.222Z'; // Replaced during build
24
+ export const ZINTRUST_BUILD_DATE = '2026-05-28T12:49:02.707Z'; // Replaced during build
25
25
  export { Application } from './boot/Application.js';
26
26
  export { AwsSigV4 } from './common/index.js';
27
27
  export { SignedRequest } from './security/SignedRequest.js';
@@ -6,17 +6,34 @@ export type RedisTransportOptions = Readonly<{
6
6
  }>;
7
7
  type RedisProxyConnection = {
8
8
  [x: string]: unknown;
9
+ __bullmq_iredis?: true;
10
+ isCluster?: false;
11
+ options?: Readonly<Record<string, unknown>>;
9
12
  status: 'ready';
10
13
  connect: () => Promise<void>;
11
14
  quit: () => Promise<'OK'>;
12
15
  disconnect: () => void;
16
+ duplicate: () => RedisProxyConnection;
17
+ defineCommand: (name: string, definition: {
18
+ numberOfKeys: number;
19
+ lua: string;
20
+ }) => void;
21
+ runCommand: (name: string, args: unknown[]) => Promise<unknown>;
13
22
  on: (event: string, handler: (...args: unknown[]) => void) => RedisProxyConnection;
14
23
  once: (event: string, handler: (...args: unknown[]) => void) => RedisProxyConnection;
15
24
  off: (event: string, handler: (...args: unknown[]) => void) => RedisProxyConnection;
16
25
  removeListener: (event: string, handler: (...args: unknown[]) => void) => RedisProxyConnection;
26
+ setMaxListeners: (count: number) => RedisProxyConnection;
27
+ getMaxListeners: () => number;
17
28
  call: (command: string, ...args: unknown[]) => Promise<unknown>;
18
29
  pipeline: () => {
19
30
  exec: () => Promise<Array<[Error | null, unknown]>>;
31
+ runCommand?: (name: string, args: unknown[]) => unknown;
32
+ [key: string]: unknown;
33
+ };
34
+ multi: () => {
35
+ exec: () => Promise<Array<[Error | null, unknown]>>;
36
+ runCommand?: (name: string, args: unknown[]) => unknown;
20
37
  [key: string]: unknown;
21
38
  };
22
39
  scanStream: (options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"RedisTransport.d.ts","sourceRoot":"","sources":["../../../../src/tools/redis/RedisTransport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpD,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC,CAAC;AAUH,KAAK,oBAAoB,GAAG;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,oBAAoB,CAAC;IACnF,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,oBAAoB,CAAC;IACrF,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,oBAAoB,CAAC;IACpF,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,oBAAoB,CAAC;IAC/F,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,QAAQ,EAAE,MAAM;QACd,IAAI,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK;QAC5D,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,OAAO,CAAC;QACtE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,OAAO,CAAC;QACxE,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,OAAO,CAAC;KACxE,CAAC;CACH,CAAC;AAiRF,eAAO,MAAM,yBAAyB,QAAO,kBAI5C,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,QAAQ,WAAW,EACnB,UAAU,qBAAqB,KAC9B,oBAgDF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,WAAW,EACnB,UAAU,qBAAqB,KAC9B,kBAaF,CAAC"}
1
+ {"version":3,"file":"RedisTransport.d.ts","sourceRoot":"","sources":["../../../../src/tools/redis/RedisTransport.ts"],"names":[],"mappings":"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"}
@@ -186,10 +186,14 @@ const createScanStream = (settings, options) => {
186
186
  });
187
187
  return stream;
188
188
  };
189
- const createPipeline = (settings) => {
189
+ const createPipeline = (settings, _runCommand) => {
190
190
  const commands = [];
191
191
  const target = {
192
192
  async exec() {
193
+ Logger.debug('[redis][proxy][pipeline] Executing pipeline', {
194
+ commandCount: commands.length,
195
+ commands: commands.map((c) => ({ command: c.command, argsCount: c.args.length })),
196
+ });
193
197
  const results = [];
194
198
  for (const entry of commands) {
195
199
  try {
@@ -208,6 +212,15 @@ const createPipeline = (settings) => {
208
212
  }
209
213
  return results;
210
214
  },
215
+ runCommand(name, args) {
216
+ Logger.debug('[redis][proxy][pipeline] runCommand called in pipeline', {
217
+ commandName: name,
218
+ argsCount: args.length,
219
+ hasRunCommandFunction: _runCommand !== undefined,
220
+ });
221
+ commands.push({ command: name, args });
222
+ return pipeline;
223
+ },
211
224
  };
212
225
  const pipeline = new Proxy(target, {
213
226
  get(obj, prop) {
@@ -215,6 +228,10 @@ const createPipeline = (settings) => {
215
228
  return Reflect.get(obj, prop);
216
229
  if (prop in obj)
217
230
  return Reflect.get(obj, prop);
231
+ Logger.debug('[redis][proxy][pipeline] Property access in pipeline', {
232
+ property: prop,
233
+ currentCommandCount: commands.length,
234
+ });
218
235
  return (...args) => {
219
236
  commands.push({ command: prop.toUpperCase(), args });
220
237
  return pipeline;
@@ -228,46 +245,151 @@ export const resolveRedisTransportMode = () => {
228
245
  ? 'proxy'
229
246
  : 'direct';
230
247
  };
231
- export const createRedisProxyConnection = (config, options) => {
232
- const settings = resolveProxySettings();
233
- logTransportSelection('proxy', config, options);
248
+ const logDefineCommandCall = (name, definition) => {
249
+ Logger.debug('[redis][proxy][bullmq] defineCommand called', {
250
+ commandName: name,
251
+ numberOfKeys: definition.numberOfKeys,
252
+ luaLength: definition.lua.length,
253
+ luaPreview: definition.lua.substring(0, 100) + '...',
254
+ });
255
+ };
256
+ const storeScript = (scripts, name, definition) => {
257
+ scripts.set(name, {
258
+ numberOfKeys: definition.numberOfKeys,
259
+ lua: definition.lua,
260
+ });
261
+ Logger.debug('[redis][proxy][bullmq] Script stored', {
262
+ commandName: name,
263
+ totalScripts: scripts.size,
264
+ allScriptNames: Array.from(scripts.keys()),
265
+ });
266
+ };
267
+ const executeScriptViaEval = async (settings, name, script, args) => {
268
+ Logger.debug('[redis][proxy][bullmq] Executing script via EVAL', {
269
+ commandName: name,
270
+ numberOfKeys: script.numberOfKeys,
271
+ luaLength: script.lua.length,
272
+ args: args.slice(0, 3), // Log first 3 args to avoid huge logs
273
+ });
274
+ return requestProxyCommand(settings, 'EVAL', [script.lua, script.numberOfKeys, ...args]);
275
+ };
276
+ const createCommandFunction = (settings, prop) => {
277
+ return async (...args) => {
278
+ Logger.debug('[redis][proxy][trap] Executing unknown property as command', {
279
+ property: prop,
280
+ argsCount: args.length,
281
+ args: args.slice(0, 3),
282
+ });
283
+ return requestProxyCommand(settings, typeof prop === 'string' ? prop.toUpperCase() : String(prop), args);
284
+ };
285
+ };
286
+ const handlePropertyAccess = (obj, prop, scripts, client, settings) => {
287
+ if (typeof prop !== 'string')
288
+ return Reflect.get(obj, prop);
289
+ if (prop === 'then')
290
+ return undefined;
291
+ if (prop === 'setMaxListeners') {
292
+ return function (_count) {
293
+ return client;
294
+ };
295
+ }
296
+ if (prop === 'getMaxListeners') {
297
+ return function () {
298
+ return Infinity;
299
+ };
300
+ }
301
+ if (prop in obj) {
302
+ Logger.debug('[redis][proxy][trap] Property access on target object', {
303
+ property: prop,
304
+ hasScript: scripts.has(prop),
305
+ });
306
+ return Reflect.get(obj, prop);
307
+ }
308
+ // Log when BullMQ accesses unknown properties (potential versioned commands)
309
+ Logger.debug('[redis][proxy][trap] Unknown property access - potential BullMQ command', {
310
+ property: prop,
311
+ propertyType: typeof prop,
312
+ hasScript: typeof prop === 'string' ? scripts.has(prop) : false,
313
+ availableScripts: Array.from(scripts.keys()),
314
+ isVersionedCommand: typeof prop === 'string' ? prop.includes(':') : false,
315
+ });
316
+ if (typeof prop !== 'string') {
317
+ return Reflect.get(obj, prop);
318
+ }
319
+ return createCommandFunction(settings, prop);
320
+ };
321
+ const createProxyTarget = (config, options, scripts, runDefinedCommand, settings, client) => {
234
322
  const target = {
323
+ __bullmq_iredis: true,
324
+ isCluster: false,
325
+ options: Object.freeze({}),
235
326
  status: 'ready',
236
327
  connect: async () => { },
237
328
  // eslint-disable-next-line @typescript-eslint/require-await
238
329
  quit: async () => 'OK',
239
330
  disconnect: () => undefined,
240
- on: (_event, _handler) => client,
241
- once: (_event, _handler) => client,
242
- off: (_event, _handler) => client,
243
- removeListener: (_event, _handler) => client,
244
- setMaxListeners: (_count) => client,
331
+ duplicate: () => createRedisProxyConnection(config, options),
332
+ defineCommand: (name, definition) => {
333
+ logDefineCommandCall(name, definition);
334
+ storeScript(scripts, name, definition);
335
+ },
336
+ runCommand: async (name, args) => runDefinedCommand(name, args),
337
+ on: (_event, _handler) => client ?? target,
338
+ once: (_event, _handler) => client ?? target,
339
+ off: (_event, _handler) => client ?? target,
340
+ removeListener: (_event, _handler) => client ?? target,
341
+ setMaxListeners: (_count) => client ?? target,
245
342
  getMaxListeners: () => Infinity,
246
343
  call: async (command, ...args) => {
344
+ Logger.debug('[redis][proxy][call] Direct call method invoked', {
345
+ command,
346
+ argsCount: args.length,
347
+ hasScript: scripts.has(command),
348
+ isVersionedCommand: command.includes(':'),
349
+ args: args.slice(0, 3),
350
+ });
247
351
  return requestProxyCommand(settings, command, args);
248
352
  },
249
- pipeline: () => createPipeline(settings),
353
+ pipeline: () => createPipeline(settings, runDefinedCommand),
354
+ multi: () => createPipeline(settings, runDefinedCommand),
250
355
  scanStream: (scanOptions) => createScanStream(settings, scanOptions),
251
356
  };
252
- const client = new Proxy(target, {
357
+ return target;
358
+ };
359
+ export const createRedisProxyConnection = (config, options) => {
360
+ const settings = resolveProxySettings();
361
+ const scripts = new Map();
362
+ const runDefinedCommand = async (name, args) => {
363
+ Logger.debug('[redis][proxy][bullmq] runDefinedCommand called', {
364
+ commandName: name,
365
+ argsCount: args.length,
366
+ hasScript: scripts.has(name),
367
+ scriptKeys: Array.from(scripts.keys()),
368
+ });
369
+ const script = scripts.get(name);
370
+ if (script === undefined) {
371
+ Logger.warn('[redis][proxy][bullmq] Script not found, falling back to direct proxy call', {
372
+ commandName: name,
373
+ availableScripts: Array.from(scripts.keys()),
374
+ });
375
+ return requestProxyCommand(settings, name, args);
376
+ }
377
+ return executeScriptViaEval(settings, name, script, args);
378
+ };
379
+ logTransportSelection('proxy', config, options);
380
+ Logger.info('[redis][proxy][bullmq] Creating BullMQ-compatible proxy connection', {
381
+ hasBullMQFlag: true,
382
+ hasIsClusterFlag: true,
383
+ hasOptionsFlag: true,
384
+ hasDuplicateMethod: true,
385
+ hasDefineCommandMethod: true,
386
+ hasRunCommandMethod: true,
387
+ hasMultiMethod: true,
388
+ });
389
+ const proxyTarget = createProxyTarget(config, options, scripts, runDefinedCommand, settings, null);
390
+ const client = new Proxy(proxyTarget, {
253
391
  get(obj, prop) {
254
- if (typeof prop !== 'string')
255
- return Reflect.get(obj, prop);
256
- if (prop === 'then')
257
- return undefined;
258
- if (prop === 'setMaxListeners') {
259
- return function (_count) {
260
- return client;
261
- };
262
- }
263
- if (prop === 'getMaxListeners') {
264
- return function () {
265
- return Infinity;
266
- };
267
- }
268
- if (prop in obj)
269
- return Reflect.get(obj, prop);
270
- return async (...args) => requestProxyCommand(settings, prop.toUpperCase(), args);
392
+ return handlePropertyAccess(obj, prop, scripts, client, settings);
271
393
  },
272
394
  });
273
395
  return client;