@zintrust/core 2.2.5 → 2.2.6

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.5",
3
+ "version": "2.2.6",
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.5
2
+ * @zintrust/core v2.2.6
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-28T17:42:54.893Z
8
+ * Built: 2026-05-28T20:15:36.566Z
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-28T17:42:54.858Z'; // Replaced during build
24
+ export const ZINTRUST_BUILD_DATE = '2026-05-28T20:15:36.526Z'; // 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';
@@ -1 +1 @@
1
- {"version":3,"file":"RedisProxyServer.d.ts","sourceRoot":"","sources":["../../../../src/proxy/redis/RedisProxyServer.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAsBjC,KAAK,cAAc,GAAG,kBAAkB,GACtC,OAAO,CAAC;IACN,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAwZL,eAAO,MAAM,gBAAgB;sBACJ,cAAc,GAAQ,OAAO,CAAC,IAAI,CAAC;EAgC1D,CAAC;AAEH,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"RedisProxyServer.d.ts","sourceRoot":"","sources":["../../../../src/proxy/redis/RedisProxyServer.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAsBjC,KAAK,cAAc,GAAG,kBAAkB,GACtC,OAAO,CAAC;IACN,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAybL,eAAO,MAAM,gBAAgB;sBACJ,cAAc,GAAQ,OAAO,CAAC,IAAI,CAAC;EAgC1D,CAAC;AAEH,eAAe,gBAAgB,CAAC"}
@@ -149,7 +149,8 @@ const handleScriptCommand = async (args, config) => {
149
149
  return { status: 200, body: { result: sha } };
150
150
  };
151
151
  const handleStandardRedisCommand = async (client, action, args) => {
152
- const lower = action.trim().toLowerCase();
152
+ const command = action.trim();
153
+ const lower = command.toLowerCase();
153
154
  if (lower === 'evalsha' && args.length > 0) {
154
155
  const sha = String(args[0]);
155
156
  Logger.info('[RedisProxyServer] EVALSHA command received', {
@@ -167,25 +168,45 @@ const handleStandardRedisCommand = async (client, action, args) => {
167
168
  });
168
169
  }
169
170
  }
170
- const candidate = client[lower];
171
- if (typeof candidate === 'function') {
171
+ const directCandidate = client[command];
172
+ if (typeof directCandidate === 'function') {
172
173
  return {
173
174
  status: 200,
174
175
  body: {
175
- result: await candidate.apply(client, args),
176
+ result: await directCandidate.apply(client, args),
177
+ },
178
+ };
179
+ }
180
+ const lowerCandidate = client[lower];
181
+ if (typeof lowerCandidate === 'function') {
182
+ return {
183
+ status: 200,
184
+ body: {
185
+ result: await lowerCandidate.apply(client, args),
176
186
  },
177
187
  };
178
188
  }
179
189
  if (typeof client.call === 'function') {
180
- return { status: 200, body: { result: await client.call(action.trim(), ...args) } };
190
+ return { status: 200, body: { result: await client.call(command, ...args) } };
181
191
  }
182
192
  throw ErrorFactory.createValidationError(`Unsupported Redis command: ${action}`);
183
193
  };
184
- const handleServiceRpc = async (validated, queueMonitor) => {
194
+ const handleServiceRpc = async (client, validated, queueMonitor) => {
185
195
  const startedAt = Date.now();
186
- const result = await dispatchServiceCommand(validated.service, validated.action ?? '', validated.payload, queueMonitor);
187
- SystemTraceBridge.emitRedis(`${validated.service}:${validated.action ?? 'unknown'}`, Date.now() - startedAt);
188
- return { status: 200, body: { result } };
196
+ try {
197
+ const result = await dispatchServiceCommand(validated.service, validated.action ?? '', validated.payload, queueMonitor);
198
+ SystemTraceBridge.emitRedis(`${validated.service}:${validated.action ?? 'unknown'}`, Date.now() - startedAt);
199
+ return { status: 200, body: { result } };
200
+ }
201
+ catch (error) {
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ if (message.includes('Unsupported worker action:') ||
204
+ message.includes('Unsupported queue-monitor action:')) {
205
+ const parsedArgs = parseRedisCommandArgs(validated.payload);
206
+ return handleStandardRedisCommand(client, validated.action ?? '', parsedArgs);
207
+ }
208
+ throw error;
209
+ }
189
210
  };
190
211
  const handleRedisRequest = async (request, config, queueMonitor) => {
191
212
  Logger.info('[RedisProxyServer] Handling request', {
@@ -217,10 +238,10 @@ const handleRedisRequest = async (request, config, queueMonitor) => {
217
238
  },
218
239
  };
219
240
  }
241
+ const client = await createClient(config);
220
242
  if (validated.service === 'worker' || validated.service === 'queue-monitor') {
221
- return handleServiceRpc(validated, queueMonitor);
243
+ return handleServiceRpc(client, validated, queueMonitor);
222
244
  }
223
- const client = await createClient(config);
224
245
  try {
225
246
  const parsedArgs = parseRedisCommandArgs(validated.payload);
226
247
  if (validated.action?.toLowerCase() === 'script') {
@@ -1 +1 @@
1
- {"version":3,"file":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEzF,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAgRN,eAAO,MAAM,iBAAiB;uCACY,uBAAuB,GAAY,OAAO,CAAC,YAAY,CAAC;IAkBhG;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;qCAgFnB,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;EAavE,CAAC"}
1
+ {"version":3,"file":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEzF,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AA2RN,eAAO,MAAM,iBAAiB;uCACY,uBAAuB,GAAY,OAAO,CAAC,YAAY,CAAC;IAkBhG;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;qCAgFnB,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;EAavE,CAAC"}
@@ -147,11 +147,17 @@ const importFromLocalFallback = async (specifier, fallback) => {
147
147
  };
148
148
  const importFromFileContents = async (filePath, specifier) => {
149
149
  try {
150
- const summary = await importSpecifiers([{ filePath, specifier }]);
150
+ const raw = await readFile(filePath, 'utf-8');
151
+ const fileSpecifiers = extractImportSpecifiers(raw);
152
+ if (fileSpecifiers.length === 0) {
153
+ return 'missing';
154
+ }
155
+ const summary = await importSpecifiers(fileSpecifiers.map((importSpecifier) => ({ filePath, specifier: importSpecifier })));
151
156
  if (summary.loaded > 0) {
152
- Logger.debug('[plugins] Loaded auto-import specifier from file contents', {
157
+ Logger.debug('[plugins] Loaded auto-import specifiers from file contents', {
153
158
  specifier,
154
159
  filePath,
160
+ loadedCount: summary.loaded,
155
161
  });
156
162
  return 'loaded';
157
163
  }
@@ -49,8 +49,16 @@ type RedisProxyConnection = {
49
49
  off: (event: string, handler: (...args: unknown[]) => void) => unknown;
50
50
  };
51
51
  };
52
+ type ScriptDefinition = Readonly<{
53
+ numberOfKeys: number;
54
+ lua: string;
55
+ }>;
56
+ type ProxyScriptRegistry = {
57
+ definitions: Map<string, ScriptDefinition>;
58
+ shaByCommand: Map<string, string>;
59
+ };
52
60
  export declare const resolveRedisTransportMode: () => RedisTransportMode;
53
- export declare const createRedisProxyConnection: (config: RedisConfig, options?: RedisTransportOptions) => RedisProxyConnection;
61
+ export declare const createRedisProxyConnection: (config: RedisConfig, options?: RedisTransportOptions, registry?: ProxyScriptRegistry) => RedisProxyConnection;
54
62
  export declare const ensureRedisTransportMode: (config: RedisConfig, options?: RedisTransportOptions) => RedisTransportMode;
55
63
  export {};
56
64
  //# sourceMappingURL=RedisTransport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RedisTransport.d.ts","sourceRoot":"","sources":["../../../../src/tools/redis/RedisTransport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RedisTransport.d.ts","sourceRoot":"","sources":["../../../../src/tools/redis/RedisTransport.ts"],"names":[],"mappings":"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"}
@@ -62,12 +62,12 @@ const createRequestId = () => {
62
62
  return crypto.randomUUID();
63
63
  return `req_${Date.now()}_${Math.random().toString(16).slice(2)}`;
64
64
  };
65
- const resolveProxySettings = (options) => ({
65
+ const resolveProxySettings = (_options) => ({
66
66
  baseUrl: resolveProxyBaseUrl(),
67
- keyId: Env.REDIS_PROXY_KEY_ID.trim() === '' ? undefined : Env.REDIS_PROXY_KEY_ID,
68
- secret: Env.REDIS_PROXY_SECRET.trim() === '' ? undefined : Env.REDIS_PROXY_SECRET,
67
+ keyId: Env.get('REDIS_PROXY_KEY_ID').trim() === '' ? undefined : Env.get('REDIS_PROXY_KEY_ID'),
68
+ secret: Env.REDIS_PROXY_SECRET.trim() === '' ? undefined : Env.get('REDIS_PROXY_SECRET'),
69
69
  timeoutMs: Env.REDIS_PROXY_TIMEOUT_MS,
70
- service: resolveProxyRpcService(options?.subsystem),
70
+ service: resolveProxyRpcService('redis'),
71
71
  customHeaders: parseCustomHeadersFromEnv('REDIS'),
72
72
  });
73
73
  const buildHeaders = async (settings, requestUrl, body) => {
@@ -114,11 +114,34 @@ const requestProxyCommand = async (settings, action, payload) => {
114
114
  });
115
115
  if (!response.ok) {
116
116
  const text = await response.text();
117
- throw ErrorFactory.createTryCatchError(`Redis proxy request failed (${response.status})`, text);
117
+ // Don't log HTML responses (e.g., 502 Bad Gateway pages)
118
+ const isHtml = text.trim().toLowerCase().startsWith('<!doctype html') ||
119
+ text.trim().toLowerCase().startsWith('<html');
120
+ const errorMessage = isHtml ? 'Non-JSON response from proxy (proxy may be unavailable)' : text;
121
+ throw ErrorFactory.createTryCatchError(`Redis proxy request failed (${response.status})`, errorMessage);
118
122
  }
119
123
  const parsed = (await response.json());
120
124
  return parsed.result;
121
125
  };
126
+ const loadScriptDefinition = async (settings, definition) => {
127
+ const loaded = await requestProxyCommand(settings, 'SCRIPT', {
128
+ args: ['LOAD', definition.lua],
129
+ });
130
+ return loaded;
131
+ };
132
+ const getDefinedScriptSha = async (settings, registry, command) => {
133
+ const cached = registry.shaByCommand.get(command);
134
+ if (cached !== undefined) {
135
+ return cached;
136
+ }
137
+ const definition = registry.definitions.get(command);
138
+ if (definition === undefined) {
139
+ return undefined;
140
+ }
141
+ const sha = await loadScriptDefinition(settings, definition);
142
+ registry.shaByCommand.set(command, sha);
143
+ return sha;
144
+ };
122
145
  const logTransportSelection = (mode, config, options) => {
123
146
  const rawSubsystem = options?.subsystem?.trim();
124
147
  const subsystem = rawSubsystem === undefined || rawSubsystem === '' ? 'redis' : rawSubsystem;
@@ -253,6 +276,19 @@ export const resolveRedisTransportMode = () => {
253
276
  const createCommandFunction = (settings, command) => {
254
277
  return async (...args) => requestProxyCommand(settings, command, { args });
255
278
  };
279
+ const createDefinedScriptFunction = (settings, command, registry) => {
280
+ return async (...args) => {
281
+ const sha = await getDefinedScriptSha(settings, registry, command);
282
+ if (sha === undefined) {
283
+ return requestProxyCommand(settings, command, { args });
284
+ }
285
+ const definition = registry.definitions.get(command);
286
+ const numberOfKeys = definition?.numberOfKeys ?? 0;
287
+ return requestProxyCommand(settings, 'EVALSHA', {
288
+ args: [sha, numberOfKeys, ...args],
289
+ });
290
+ };
291
+ };
256
292
  const createScriptsHandler = (settings) => {
257
293
  return new Proxy({}, {
258
294
  get(_target, prop) {
@@ -262,7 +298,7 @@ const createScriptsHandler = (settings) => {
262
298
  },
263
299
  });
264
300
  };
265
- const handlePropertyAccess = (obj, prop, client, settings) => {
301
+ const handlePropertyAccess = (obj, prop, client, settings, registry) => {
266
302
  if (typeof prop !== 'string')
267
303
  return Reflect.get(obj, prop);
268
304
  if (prop === 'then')
@@ -277,12 +313,15 @@ const handlePropertyAccess = (obj, prop, client, settings) => {
277
313
  return Infinity;
278
314
  };
279
315
  }
316
+ if (registry.definitions.has(prop)) {
317
+ return createDefinedScriptFunction(settings, prop, registry);
318
+ }
280
319
  if (prop in obj) {
281
320
  return Reflect.get(obj, prop);
282
321
  }
283
322
  return createCommandFunction(settings, prop);
284
323
  };
285
- const createProxyTarget = (config, options, settings, client) => {
324
+ const createProxyTarget = (config, options, settings, client, registry) => {
286
325
  const target = {
287
326
  __bullmq_iredis: true,
288
327
  isCluster: false,
@@ -292,11 +331,14 @@ const createProxyTarget = (config, options, settings, client) => {
292
331
  // eslint-disable-next-line @typescript-eslint/require-await
293
332
  quit: async () => 'OK',
294
333
  disconnect: () => undefined,
295
- duplicate: () => createRedisProxyConnection(config, options),
334
+ duplicate: () => createRedisProxyConnection(config, options, registry),
296
335
  defineCommand: (name, definition) => {
297
- Logger.debug('[redis][proxy][bullmq] defineCommand ignored on frontend proxy', {
336
+ registry.definitions.set(name, definition);
337
+ registry.shaByCommand.delete(name);
338
+ Logger.debug('[redis][proxy][bullmq] registered defined command', {
298
339
  commandName: name,
299
340
  numberOfKeys: definition.numberOfKeys,
341
+ luaLength: definition.lua.length,
300
342
  });
301
343
  },
302
344
  runCommand: async (name, args) => requestProxyCommand(settings, name, { args }),
@@ -314,24 +356,33 @@ const createProxyTarget = (config, options, settings, client) => {
314
356
  };
315
357
  return target;
316
358
  };
317
- export const createRedisProxyConnection = (config, options) => {
359
+ export const createRedisProxyConnection = (config, options, registry) => {
318
360
  const settings = resolveProxySettings(options);
361
+ const scriptRegistry = registry ?? {
362
+ definitions: new Map(),
363
+ shaByCommand: new Map(),
364
+ };
319
365
  logTransportSelection('proxy', config, options);
320
366
  Logger.info('[redis][proxy] Creating opaque proxy connection', {
321
367
  transport: 'BullMQ',
322
368
  });
323
- const proxyTarget = createProxyTarget(config, options, settings, null);
369
+ const proxyTarget = createProxyTarget(config, options, settings, null, scriptRegistry);
324
370
  const client = new Proxy(proxyTarget, {
325
371
  get(obj, prop) {
326
- return handlePropertyAccess(obj, prop, client, settings);
372
+ return handlePropertyAccess(obj, prop, client, settings, scriptRegistry);
327
373
  },
328
374
  });
329
375
  return client;
330
376
  };
331
377
  export const ensureRedisTransportMode = (config, options) => {
332
378
  const mode = resolveRedisTransportMode();
379
+ const subsystem = options?.subsystem ?? 'redis';
380
+ const requireDirectForScripts = options?.requireDirectForScripts ?? Env.REDIS_REQUIRE_DIRECT_FOR_SCRIPTS;
333
381
  if (mode === 'proxy' && options?.requireDirect === true) {
334
- throw ErrorFactory.createConfigError(`Redis subsystem '${options.subsystem ?? 'redis'}' requires a direct Redis connection, but proxy mode is enabled.`);
382
+ throw ErrorFactory.createConfigError(`Redis subsystem '${subsystem}' requires a direct Redis connection, but proxy mode is enabled.`);
383
+ }
384
+ if (mode === 'proxy' && requireDirectForScripts) {
385
+ throw ErrorFactory.createConfigError(`Redis subsystem '${subsystem}' requires a direct Redis connection for scripts, but proxy mode is enabled.`);
335
386
  }
336
387
  if (mode === 'direct') {
337
388
  logTransportSelection(mode, config, options);