@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 +1 -1
- package/src/index.js +3 -3
- package/src/proxy/redis/RedisProxyServer.d.ts.map +1 -1
- package/src/proxy/redis/RedisProxyServer.js +32 -11
- package/src/runtime/PluginAutoImports.d.ts.map +1 -1
- package/src/runtime/PluginAutoImports.js +8 -2
- package/src/tools/redis/RedisTransport.d.ts +9 -1
- package/src/tools/redis/RedisTransport.d.ts.map +1 -1
- package/src/tools/redis/RedisTransport.js +64 -13
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v2.2.
|
|
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-
|
|
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-
|
|
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;
|
|
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
|
|
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
|
|
171
|
-
if (typeof
|
|
171
|
+
const directCandidate = client[command];
|
|
172
|
+
if (typeof directCandidate === 'function') {
|
|
172
173
|
return {
|
|
173
174
|
status: 200,
|
|
174
175
|
body: {
|
|
175
|
-
result: await
|
|
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(
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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;
|
|
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
|
|
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
|
|
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 = (
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 '${
|
|
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);
|