@zintrust/core 2.2.4 → 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/RedisProxyActions.d.ts +3 -3
- package/src/proxy/redis/RedisProxyActions.d.ts.map +1 -1
- package/src/proxy/redis/RedisProxyActions.js +42 -18
- package/src/proxy/redis/RedisProxyServer.d.ts.map +1 -1
- package/src/proxy/redis/RedisProxyServer.js +35 -14
- package/src/runtime/PluginAutoImports.d.ts.map +1 -1
- package/src/runtime/PluginAutoImports.js +58 -9
- 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,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { QueueDriver } from '@zintrust/queue-monitor/driver';
|
|
2
|
+
import type { Metrics } from '@zintrust/queue-monitor/metrics';
|
|
3
3
|
export type QueueMonitorContext = Readonly<{
|
|
4
4
|
driver: QueueDriver;
|
|
5
5
|
metrics: Metrics;
|
|
@@ -10,6 +10,6 @@ export type RedisProxyRedisConfig = Readonly<{
|
|
|
10
10
|
password: string;
|
|
11
11
|
db: number;
|
|
12
12
|
}>;
|
|
13
|
-
export declare const createQueueMonitorContext: (redis: RedisProxyRedisConfig) => QueueMonitorContext
|
|
13
|
+
export declare const createQueueMonitorContext: (redis: RedisProxyRedisConfig) => Promise<QueueMonitorContext>;
|
|
14
14
|
export declare const dispatchServiceCommand: (service: string, action: string, payload: Record<string, unknown>, queueMonitor: QueueMonitorContext) => Promise<unknown>;
|
|
15
15
|
//# sourceMappingURL=RedisProxyActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisProxyActions.d.ts","sourceRoot":"","sources":["../../../../src/proxy/redis/RedisProxyActions.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"RedisProxyActions.d.ts","sourceRoot":"","sources":["../../../../src/proxy/redis/RedisProxyActions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAG/D,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC,CAAC;AA4BH,eAAO,MAAM,yBAAyB,GACpC,OAAO,qBAAqB,KAC3B,OAAO,CAAC,mBAAmB,CAU7B,CAAC;AAuIF,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EACf,QAAQ,MAAM,EACd,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,cAAc,mBAAmB,KAChC,OAAO,CAAC,OAAO,CAUjB,CAAC"}
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
2
|
+
const loadQueueMonitorDriverModule = async () => {
|
|
3
|
+
return import('@zintrust/queue-monitor/driver');
|
|
4
|
+
};
|
|
5
|
+
const loadQueueMonitorMetricsModule = async () => {
|
|
6
|
+
return import('@zintrust/queue-monitor/metrics');
|
|
7
|
+
};
|
|
8
|
+
const loadQueueMonitoringServiceModule = async () => {
|
|
9
|
+
return import('../../../packages/queue-monitor/src/QueueMonitoringService.js');
|
|
10
|
+
};
|
|
11
|
+
const loadWorkersApiModule = async () => {
|
|
12
|
+
return import('../../../packages/workers/src/dashboard/workers-api.js');
|
|
13
|
+
};
|
|
14
|
+
const loadWorkerFactoryModule = async () => {
|
|
15
|
+
return import('../../../packages/workers/src/WorkerFactory.js');
|
|
16
|
+
};
|
|
17
|
+
export const createQueueMonitorContext = async (redis) => {
|
|
18
|
+
const [driverModule, metricsModule] = await Promise.all([
|
|
19
|
+
loadQueueMonitorDriverModule(),
|
|
20
|
+
loadQueueMonitorMetricsModule(),
|
|
21
|
+
]);
|
|
8
22
|
return {
|
|
9
|
-
driver: createBullMQDriver(redis),
|
|
10
|
-
metrics: createMetrics(redis),
|
|
23
|
+
driver: driverModule.createBullMQDriver(redis),
|
|
24
|
+
metrics: metricsModule.createMetrics(redis),
|
|
11
25
|
};
|
|
12
26
|
};
|
|
13
27
|
const readString = (value) => {
|
|
@@ -38,16 +52,20 @@ const resolveWorkerPersistenceOverride = (payload) => {
|
|
|
38
52
|
};
|
|
39
53
|
const workerActionHandlers = {
|
|
40
54
|
getWorkers: async (payload) => {
|
|
41
|
-
|
|
55
|
+
const module = await loadWorkersApiModule();
|
|
56
|
+
return module.getWorkers(payload);
|
|
42
57
|
},
|
|
43
58
|
getWorkerDetails: async (payload) => {
|
|
44
|
-
|
|
59
|
+
const module = await loadWorkersApiModule();
|
|
60
|
+
return module.getWorkerDetails(readString(payload['name'] ?? payload['workerName']) ?? '', readString(payload['driver']));
|
|
45
61
|
},
|
|
46
62
|
toggleAutoStart: async (payload) => {
|
|
47
|
-
|
|
63
|
+
const module = await loadWorkersApiModule();
|
|
64
|
+
return module.toggleAutoStart(readString(payload['name'] ?? payload['workerName']) ?? '', readBoolean(payload['enabled']));
|
|
48
65
|
},
|
|
49
66
|
listPersistedRecords: async (payload) => {
|
|
50
|
-
|
|
67
|
+
const module = await loadWorkerFactoryModule();
|
|
68
|
+
return module.WorkerFactory.listPersistedRecords(resolveWorkerPersistenceOverride(payload), {
|
|
51
69
|
offset: readNumber(payload['offset']),
|
|
52
70
|
limit: readNumber(payload['limit']),
|
|
53
71
|
search: readString(payload['search']),
|
|
@@ -55,24 +73,30 @@ const workerActionHandlers = {
|
|
|
55
73
|
});
|
|
56
74
|
},
|
|
57
75
|
listFileBackedRecords: async () => {
|
|
58
|
-
|
|
76
|
+
const module = await loadWorkerFactoryModule();
|
|
77
|
+
return module.WorkerFactory.listFileBackedRecords();
|
|
59
78
|
},
|
|
60
79
|
getPersisted: async (payload) => {
|
|
61
|
-
|
|
80
|
+
const module = await loadWorkerFactoryModule();
|
|
81
|
+
return module.WorkerFactory.getPersisted(readString(payload['name'] ?? payload['workerName']) ?? '', resolveWorkerPersistenceOverride(payload));
|
|
62
82
|
},
|
|
63
83
|
getHealth: async (payload) => {
|
|
64
|
-
|
|
84
|
+
const module = await loadWorkerFactoryModule();
|
|
85
|
+
return module.WorkerFactory.getHealth(readString(payload['name'] ?? payload['workerName']) ?? '');
|
|
65
86
|
},
|
|
66
87
|
getMetrics: async (payload) => {
|
|
67
|
-
|
|
88
|
+
const module = await loadWorkerFactoryModule();
|
|
89
|
+
return module.WorkerFactory.getMetrics(readString(payload['name'] ?? payload['workerName']) ?? '');
|
|
68
90
|
},
|
|
69
91
|
};
|
|
70
92
|
const queueMonitorActionHandlers = {
|
|
71
93
|
getRecentJobsForQueue: async (payload, queueMonitor) => {
|
|
72
|
-
|
|
94
|
+
const module = await loadQueueMonitoringServiceModule();
|
|
95
|
+
return module.getRecentJobsForQueue(readString(payload['queue'] ?? payload['queueName']) ?? '', queueMonitor.metrics, queueMonitor.driver);
|
|
73
96
|
},
|
|
74
97
|
getRecentJobsForSelection: async (payload, queueMonitor) => {
|
|
75
|
-
|
|
98
|
+
const module = await loadQueueMonitoringServiceModule();
|
|
99
|
+
return module.getRecentJobsForSelection(readString(payload['queue'] ?? payload['queueName']) ?? '', queueMonitor.metrics, queueMonitor.driver, readQueueNames(payload['queueNames']));
|
|
76
100
|
},
|
|
77
101
|
};
|
|
78
102
|
const dispatchWorkerAction = async (action, payload) => {
|
|
@@ -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') {
|
|
@@ -254,8 +275,8 @@ const handleRedisHealth = async (config) => {
|
|
|
254
275
|
return { status: 503, body: { status: 'unhealthy', error: String(error) } };
|
|
255
276
|
}
|
|
256
277
|
};
|
|
257
|
-
const createBackend = (config) => {
|
|
258
|
-
const queueMonitor = createQueueMonitorContext(config.redis);
|
|
278
|
+
const createBackend = async (config) => {
|
|
279
|
+
const queueMonitor = await createQueueMonitorContext(config.redis);
|
|
259
280
|
return {
|
|
260
281
|
name: 'redis',
|
|
261
282
|
handle: async (request) => handleRedisRequest(request, config, queueMonitor),
|
|
@@ -307,7 +328,7 @@ const getScriptCacheClient = async (config) => {
|
|
|
307
328
|
export const RedisProxyServer = Object.freeze({
|
|
308
329
|
async start(overrides = {}) {
|
|
309
330
|
const config = resolveConfig(overrides);
|
|
310
|
-
const backend = createBackend(config);
|
|
331
|
+
const backend = await createBackend(config);
|
|
311
332
|
Logger.info('[RedisProxyServer] Starting Redis proxy', {
|
|
312
333
|
host: config.host,
|
|
313
334
|
port: config.port,
|
|
@@ -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"}
|
|
@@ -145,21 +145,58 @@ const importFromLocalFallback = async (specifier, fallback) => {
|
|
|
145
145
|
return getMissingPackageStatus(fallbackError, specifier);
|
|
146
146
|
}
|
|
147
147
|
};
|
|
148
|
+
const importFromFileContents = async (filePath, specifier) => {
|
|
149
|
+
try {
|
|
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 })));
|
|
156
|
+
if (summary.loaded > 0) {
|
|
157
|
+
Logger.debug('[plugins] Loaded auto-import specifiers from file contents', {
|
|
158
|
+
specifier,
|
|
159
|
+
filePath,
|
|
160
|
+
loadedCount: summary.loaded,
|
|
161
|
+
});
|
|
162
|
+
return 'loaded';
|
|
163
|
+
}
|
|
164
|
+
if (summary.missing > 0 && summary.failed === 0) {
|
|
165
|
+
return 'missing';
|
|
166
|
+
}
|
|
167
|
+
return 'failed';
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
return getMissingPackageStatus(error, specifier);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
148
173
|
const importSingleSpecifier = async (entry) => {
|
|
149
174
|
const target = entry.specifier.startsWith('.')
|
|
150
175
|
? resolveRelativeSpecifier(entry)
|
|
151
176
|
: entry.specifier;
|
|
152
|
-
|
|
153
|
-
await
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
if (target.endsWith('.ts')) {
|
|
178
|
+
const sourceLoad = await importFromFileContents(entry.filePath, entry.specifier);
|
|
179
|
+
if (sourceLoad !== 'failed') {
|
|
180
|
+
return sourceLoad;
|
|
181
|
+
}
|
|
156
182
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
183
|
+
else {
|
|
184
|
+
try {
|
|
185
|
+
await import(target);
|
|
186
|
+
Logger.debug('[plugins] Loaded auto-import specifier', { specifier: entry.specifier });
|
|
187
|
+
return 'loaded';
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const fallback = resolveLocalPackageSpecifier(entry.specifier);
|
|
191
|
+
if (fallback !== null)
|
|
192
|
+
return importFromLocalFallback(entry.specifier, fallback);
|
|
193
|
+
return getMissingPackageStatus(error, entry.specifier);
|
|
194
|
+
}
|
|
162
195
|
}
|
|
196
|
+
const fallback = resolveLocalPackageSpecifier(entry.specifier);
|
|
197
|
+
if (fallback !== null)
|
|
198
|
+
return importFromLocalFallback(entry.specifier, fallback);
|
|
199
|
+
return 'failed';
|
|
163
200
|
};
|
|
164
201
|
const importSpecifiers = async (specifiers) => {
|
|
165
202
|
// Import all specifiers in parallel
|
|
@@ -225,6 +262,18 @@ export const PluginAutoImports = Object.freeze({
|
|
|
225
262
|
return { ok: false, reason: 'not-found' };
|
|
226
263
|
}
|
|
227
264
|
const tryImportCandidate = async (candidate) => {
|
|
265
|
+
if (candidate.endsWith('.ts')) {
|
|
266
|
+
const fallbackResult = await this.tryImportFromFileContents([candidate]);
|
|
267
|
+
if (fallbackResult.ok) {
|
|
268
|
+
return { ok: true, loadedPath: candidate };
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
ok: false,
|
|
272
|
+
loadedPath: candidate,
|
|
273
|
+
reason: fallbackResult.reason,
|
|
274
|
+
errorMessage: fallbackResult.errorMessage,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
228
277
|
try {
|
|
229
278
|
const url = pathToFileURL(candidate).href;
|
|
230
279
|
await import(url);
|
|
@@ -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":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAUhD,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;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC,CAAC;AAWH,KAAK,oBAAoB,GAAG;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,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,SAAS,EAAE,MAAM,oBAAoB,CAAC;IACtC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACzF,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,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,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC;IACzD,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACzD,CAAC;IACF,QAAQ,EAAE,MAAM;QACd,IAAI,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACpD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;QACxD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,KAAK,EAAE,MAAM;QACX,IAAI,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACpD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;QACxD,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;
|
|
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);
|