@zintrust/core 2.2.5 → 2.2.7
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/cli/cloudflare/CloudflareSecretSync.d.ts +3 -2
- package/src/cli/cloudflare/CloudflareSecretSync.d.ts.map +1 -1
- package/src/cli/cloudflare/CloudflareSecretSync.js +40 -12
- package/src/cli/commands/DeployCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployCommand.js +2 -0
- package/src/cli/commands/DeployContainersProxyCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployContainersProxyCommand.js +2 -0
- package/src/cli/commands/PutCommand.d.ts.map +1 -1
- package/src/cli/commands/PutCommand.js +2 -0
- 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
|
@@ -21,6 +21,7 @@ type CloudflareSecretSyncArgs = {
|
|
|
21
21
|
target?: string;
|
|
22
22
|
bulk?: boolean;
|
|
23
23
|
requireSelection?: boolean;
|
|
24
|
+
all?: boolean;
|
|
24
25
|
};
|
|
25
26
|
export type CloudflareSecretSyncResult = {
|
|
26
27
|
pushed: number;
|
|
@@ -31,9 +32,9 @@ export type CloudflareSecretSyncResult = {
|
|
|
31
32
|
};
|
|
32
33
|
export declare const uniq: (items: string[]) => string[];
|
|
33
34
|
export declare const reportCloudflareSecretSync: (log: CloudflareSecretLog, result: Pick<CloudflareSecretSyncResult, "pushed" | "skippedEmptyKeys" | "failures">) => void;
|
|
34
|
-
export declare const syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, directKeys, inlineValues, configPath, target, bulk, requireSelection, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
35
|
+
export declare const syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, directKeys, inlineValues, configPath, target, bulk, requireSelection, all, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
35
36
|
declare const _default: Readonly<{
|
|
36
|
-
syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, directKeys, inlineValues, configPath, target, bulk, requireSelection, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
37
|
+
syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, directKeys, inlineValues, configPath, target, bulk, requireSelection, all, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
37
38
|
reportCloudflareSecretSync: (log: CloudflareSecretLog, result: Pick<CloudflareSecretSyncResult, "pushed" | "skippedEmptyKeys" | "failures">) => void;
|
|
38
39
|
}>;
|
|
39
40
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudflareSecretSync.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloudflare/CloudflareSecretSync.ts"],"names":[],"mappings":"AAaA,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAcF,KAAK,wBAAwB,GAAG;IAC9B,GAAG,EAAE,mBAAmB,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"CloudflareSecretSync.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloudflare/CloudflareSecretSync.ts"],"names":[],"mappings":"AAaA,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAcF,KAAK,wBAAwB,GAAG;IAC9B,GAAG,EAAE,mBAAmB,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAcF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,2BAA2B,EAAE,CAAC;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AASF,eAAO,MAAM,IAAI,GAAI,OAAO,MAAM,EAAE,KAAG,MAAM,EAY5C,CAAC;AA+TF,eAAO,MAAM,0BAA0B,GACrC,KAAK,mBAAmB,EACxB,QAAQ,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,kBAAkB,GAAG,UAAU,CAAC,KACnF,IAcF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAU,uIAczC,wBAAwB,KAAG,OAAO,CAAC,0BAA0B,CAqD/D,CAAC;;mKArDC,wBAAwB,KAAG,OAAO,CAAC,0BAA0B,CAAC;sCAhC1D,mBAAmB,UAChB,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,kBAAkB,GAAG,UAAU,CAAC,KACnF,IAAI;;AAqFP,wBAGG"}
|
|
@@ -38,16 +38,22 @@ const getConfigArray = (config, key) => {
|
|
|
38
38
|
return [];
|
|
39
39
|
return uniq(raw.filter((item) => typeof item === 'string'));
|
|
40
40
|
};
|
|
41
|
-
const resolveValue = (key, envMap) => {
|
|
41
|
+
const resolveValue = (key, envMap, envPath, all = false) => {
|
|
42
42
|
const fromFile = envMap[key];
|
|
43
43
|
const fromProcess = process.env[key];
|
|
44
|
+
const isCustomEnvFile = envPath !== '.env' && envPath.trim() !== '';
|
|
45
|
+
// If custom env file is provided and all is false, only use values from the custom file
|
|
46
|
+
if (isCustomEnvFile && !all) {
|
|
47
|
+
return fromFile ?? '';
|
|
48
|
+
}
|
|
49
|
+
// Default behavior: fallback to process.env
|
|
44
50
|
return fromFile ?? fromProcess ?? '';
|
|
45
51
|
};
|
|
46
|
-
const resolveValueWithOverrides = (key, envMap, inlineValues) => {
|
|
52
|
+
const resolveValueWithOverrides = (key, envMap, inlineValues, envPath, all = false) => {
|
|
47
53
|
const inlineValue = inlineValues[key];
|
|
48
54
|
if (typeof inlineValue === 'string')
|
|
49
55
|
return inlineValue;
|
|
50
|
-
return resolveValue(key, envMap);
|
|
56
|
+
return resolveValue(key, envMap, envPath, all);
|
|
51
57
|
};
|
|
52
58
|
const getPutTimeoutMs = () => {
|
|
53
59
|
const raw = process.env['ZT_PUT_TIMEOUT_MS'];
|
|
@@ -131,13 +137,13 @@ const resolveSelectedKeys = ({ log, config, cwd, wranglerEnvs, configGroups = []
|
|
|
131
137
|
? 'No secret keys resolved from explicit keys or .zintrust.json cloudflare.shared_env/cloudflare.targets/cloudflare.wrangler_envs. Use --key/--keys, --var <group>, or add a Cloudflare env manifest.'
|
|
132
138
|
: 'No secret keys resolved from selected groups.');
|
|
133
139
|
};
|
|
134
|
-
const resolveBulkPayload = (log, wranglerEnv, selectedKeys, envMap, inlineValues) => {
|
|
140
|
+
const resolveBulkPayload = (log, wranglerEnv, selectedKeys, envMap, inlineValues, envPath, all = false) => {
|
|
135
141
|
const payload = {};
|
|
136
142
|
const includedKeys = [];
|
|
137
143
|
const skippedEmptyKeys = [];
|
|
138
144
|
const wranglerEnvLabel = describeWranglerEnv(wranglerEnv);
|
|
139
145
|
for (const key of selectedKeys) {
|
|
140
|
-
const value = resolveValueWithOverrides(key, envMap, inlineValues);
|
|
146
|
+
const value = resolveValueWithOverrides(key, envMap, inlineValues, envPath, all);
|
|
141
147
|
if (value.trim() === '') {
|
|
142
148
|
log.warn(`skip ${key} -> ${wranglerEnvLabel}: empty value`);
|
|
143
149
|
skippedEmptyKeys.push(key);
|
|
@@ -148,11 +154,12 @@ const resolveBulkPayload = (log, wranglerEnv, selectedKeys, envMap, inlineValues
|
|
|
148
154
|
}
|
|
149
155
|
return { payload, includedKeys, skippedEmptyKeys };
|
|
150
156
|
};
|
|
151
|
-
const processSecretSync = (
|
|
157
|
+
const processSecretSync = (args) => {
|
|
158
|
+
const { log, wranglerEnvs, selectedKeys, envMap, dryRun, configPath, inlineValues, envPath, all, } = args;
|
|
152
159
|
const progress = createSyncProgress();
|
|
153
160
|
forEachWranglerEnv(wranglerEnvs, (wranglerEnv, wranglerEnvLabel) => {
|
|
154
161
|
for (const key of selectedKeys) {
|
|
155
|
-
const value = resolveValueWithOverrides(key, envMap, inlineValues);
|
|
162
|
+
const value = resolveValueWithOverrides(key, envMap, inlineValues, envPath, all);
|
|
156
163
|
if (value.trim() === '') {
|
|
157
164
|
log.warn(`skip ${key} -> ${wranglerEnvLabel}: empty value`);
|
|
158
165
|
progress.skippedEmptyKeys.push(key);
|
|
@@ -174,10 +181,11 @@ const processSecretSync = (log, wranglerEnvs, selectedKeys, envMap, dryRun, conf
|
|
|
174
181
|
});
|
|
175
182
|
return progress;
|
|
176
183
|
};
|
|
177
|
-
const processSecretBulkSync = (
|
|
184
|
+
const processSecretBulkSync = (args) => {
|
|
185
|
+
const { log, wranglerEnvs, selectedKeys, envMap, dryRun, configPath, inlineValues, envPath, all, } = args;
|
|
178
186
|
const progress = createSyncProgress();
|
|
179
187
|
forEachWranglerEnv(wranglerEnvs, (wranglerEnv, wranglerEnvLabel) => {
|
|
180
|
-
const { payload, includedKeys, skippedEmptyKeys: skippedForEnv, } = resolveBulkPayload(log, wranglerEnv, selectedKeys, envMap, inlineValues);
|
|
188
|
+
const { payload, includedKeys, skippedEmptyKeys: skippedForEnv, } = resolveBulkPayload(log, wranglerEnv, selectedKeys, envMap, inlineValues, envPath, all);
|
|
181
189
|
progress.skippedEmptyKeys.push(...skippedForEnv);
|
|
182
190
|
if (includedKeys.length === 0) {
|
|
183
191
|
log.info(`skip bulk upload -> ${wranglerEnvLabel}: no non-empty keys`);
|
|
@@ -222,7 +230,7 @@ export const reportCloudflareSecretSync = (log, result) => {
|
|
|
222
230
|
log.warn(`${item.key} -> ${describeWranglerEnv(item.wranglerEnv)}: ${item.reason}`);
|
|
223
231
|
}
|
|
224
232
|
};
|
|
225
|
-
export const syncCloudflareSecrets = async ({ log, cwd, wranglerEnvs, envPath, dryRun = false, configGroups = [], directKeys = [], inlineValues = {}, configPath, target, bulk = false, requireSelection = true, }) => {
|
|
233
|
+
export const syncCloudflareSecrets = async ({ log, cwd, wranglerEnvs, envPath, dryRun = false, configGroups = [], directKeys = [], inlineValues = {}, configPath, target, bulk = false, requireSelection = true, all = false, }) => {
|
|
226
234
|
const normalizedConfigPath = typeof configPath === 'string' && configPath.trim() !== '' ? configPath.trim() : undefined;
|
|
227
235
|
if (normalizedConfigPath !== undefined && !existsSync(path.join(cwd, normalizedConfigPath))) {
|
|
228
236
|
throw ErrorFactory.createCliError(`Wrangler config not found: ${normalizedConfigPath}`);
|
|
@@ -244,8 +252,28 @@ export const syncCloudflareSecrets = async ({ log, cwd, wranglerEnvs, envPath, d
|
|
|
244
252
|
}
|
|
245
253
|
const envMap = await EnvFile.read({ cwd, path: envPath });
|
|
246
254
|
const syncResult = bulk
|
|
247
|
-
? processSecretBulkSync(
|
|
248
|
-
|
|
255
|
+
? processSecretBulkSync({
|
|
256
|
+
log,
|
|
257
|
+
wranglerEnvs,
|
|
258
|
+
selectedKeys,
|
|
259
|
+
envMap,
|
|
260
|
+
dryRun,
|
|
261
|
+
configPath: normalizedConfigPath,
|
|
262
|
+
inlineValues,
|
|
263
|
+
envPath,
|
|
264
|
+
all,
|
|
265
|
+
})
|
|
266
|
+
: processSecretSync({
|
|
267
|
+
log,
|
|
268
|
+
wranglerEnvs,
|
|
269
|
+
selectedKeys,
|
|
270
|
+
envMap,
|
|
271
|
+
dryRun,
|
|
272
|
+
configPath: normalizedConfigPath,
|
|
273
|
+
inlineValues,
|
|
274
|
+
envPath,
|
|
275
|
+
all,
|
|
276
|
+
});
|
|
249
277
|
return {
|
|
250
278
|
...syncResult,
|
|
251
279
|
selectedKeys,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeployCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/DeployCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"DeployCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/DeployCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgMrE;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;cACO,YAAY;EAGtB,CAAC"}
|
|
@@ -58,6 +58,7 @@ const syncWranglerSecrets = async (cmd, cwd, wranglerEnv, options) => {
|
|
|
58
58
|
configPath: typeof options.config === 'string' ? options.config.trim() : undefined,
|
|
59
59
|
target: typeof options.target === 'string' ? options.target : undefined,
|
|
60
60
|
requireSelection: false,
|
|
61
|
+
all: options.all === true,
|
|
61
62
|
});
|
|
62
63
|
if (result.selectedKeys.length === 0)
|
|
63
64
|
return;
|
|
@@ -109,6 +110,7 @@ const createDeployCommand = () => {
|
|
|
109
110
|
command.option('-c, --config <path>', 'Wrangler config file (e.g. wrangler.containers-proxy.jsonc)');
|
|
110
111
|
command.option('--env-path <path>', 'Path to env file used when syncing Cloudflare secrets', '.env');
|
|
111
112
|
command.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets');
|
|
113
|
+
command.option('--all', 'Sync both custom env file and process.env (only applies when custom env file is provided)');
|
|
112
114
|
command.option('--no-sync-secrets', 'Skip Cloudflare secret sync before wrangler deploy');
|
|
113
115
|
},
|
|
114
116
|
execute: async (options) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeployContainersProxyCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/DeployContainersProxyCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"DeployContainersProxyCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/DeployContainersProxyCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA+ErE,eAAO,MAAM,4BAA4B;cAC7B,YAAY;EA6BtB,CAAC"}
|
|
@@ -31,6 +31,7 @@ const syncDeploySecrets = async (cmd, cwd, config, env, options) => {
|
|
|
31
31
|
configPath: config,
|
|
32
32
|
target: typeof options.target === 'string' ? options.target : undefined,
|
|
33
33
|
requireSelection: false,
|
|
34
|
+
all: options.all === true,
|
|
34
35
|
});
|
|
35
36
|
if (result.selectedKeys.length === 0)
|
|
36
37
|
return;
|
|
@@ -60,6 +61,7 @@ export const DeployContainersProxyCommand = Object.freeze({
|
|
|
60
61
|
command.option('-c, --config <path>', 'Wrangler config file', DEFAULT_CONFIG);
|
|
61
62
|
command.option('--env-path <path>', 'Path to env file used when syncing Cloudflare secrets', '.env');
|
|
62
63
|
command.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets');
|
|
64
|
+
command.option('--all', 'Sync both custom env file and process.env (only applies when custom env file is provided)');
|
|
63
65
|
command.option('--no-sync-secrets', 'Skip Cloudflare secret sync before wrangler deploy');
|
|
64
66
|
},
|
|
65
67
|
execute: async (options) => execute(cmd, options),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PutCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/PutCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"PutCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/PutCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAmHvF,eAAO,MAAM,UAAU;cACX,YAAY;EAWtB,CAAC;AAEH,eAAe,UAAU,CAAC"}
|
|
@@ -50,6 +50,7 @@ const addOptions = (command) => {
|
|
|
50
50
|
.option('--env_path <path>', 'Path to env file used as source values', '.env')
|
|
51
51
|
.option('-c, --config <path>', 'Wrangler config file to target (optional)')
|
|
52
52
|
.option('--bulk', 'Upload the final key set with one wrangler secret bulk call per target')
|
|
53
|
+
.option('--all', 'Sync both custom env file and process.env (only applies when custom env file is provided)')
|
|
53
54
|
.option('--dry-run', 'Show what would be uploaded without calling wrangler');
|
|
54
55
|
};
|
|
55
56
|
const ensureCloudflareProvider = (providerRaw) => {
|
|
@@ -75,6 +76,7 @@ const execute = async (cmd, options) => {
|
|
|
75
76
|
target: typeof options.target === 'string' ? options.target : undefined,
|
|
76
77
|
bulk: options.bulk === true,
|
|
77
78
|
requireSelection: true,
|
|
79
|
+
all: options.all === true,
|
|
78
80
|
});
|
|
79
81
|
reportCloudflareSecretSync(cmd, result);
|
|
80
82
|
};
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v2.2.
|
|
2
|
+
* @zintrust/core v2.2.7
|
|
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-29T08:10:13.516Z
|
|
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-29T08:10:13.484Z'; // 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);
|