@zintrust/core 0.4.39 → 0.4.41
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 +2 -2
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.d.ts +37 -0
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.d.ts.map +1 -0
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.js +104 -0
- package/src/cli/cloudflare/CloudflareSecretSync.d.ts +34 -0
- package/src/cli/cloudflare/CloudflareSecretSync.d.ts.map +1 -0
- package/src/cli/cloudflare/CloudflareSecretSync.js +147 -0
- package/src/cli/commands/DeployCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployCommand.js +27 -3
- package/src/cli/commands/DeployContainersProxyCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployContainersProxyCommand.js +27 -3
- package/src/cli/commands/ProxyScaffoldUtils.d.ts.map +1 -1
- package/src/cli/commands/ProxyScaffoldUtils.js +2 -3
- package/src/cli/commands/PutCommand.d.ts.map +1 -1
- package/src/cli/commands/PutCommand.js +14 -117
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +68 -25
- package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +24 -0
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +32 -2
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/cli/utils/EnvFileLoader.js +21 -4
- package/src/config/env.d.ts +16 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +126 -2
- package/src/index.js +3 -3
- package/src/runtime/RuntimeServices.d.ts.map +1 -1
- package/src/runtime/RuntimeServices.js +4 -34
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '../BaseCommand.js';
|
|
2
|
-
import {
|
|
3
|
-
import { appConfig } from '../../config/app.js';
|
|
2
|
+
import { reportCloudflareSecretSync, syncCloudflareSecrets, } from '../cloudflare/CloudflareSecretSync.js';
|
|
4
3
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
5
|
-
import { execFileSync } from '../../node-singletons/child-process.js';
|
|
6
|
-
import { existsSync, readFileSync } from '../../node-singletons/fs.js';
|
|
7
|
-
import * as path from '../../node-singletons/path.js';
|
|
8
|
-
import { EnvFile } from '../../toolkit/Secrets/EnvFile.js';
|
|
9
4
|
const toStringArray = (value) => {
|
|
10
5
|
if (typeof value === 'string')
|
|
11
6
|
return [value];
|
|
@@ -25,26 +20,6 @@ const uniq = (items) => {
|
|
|
25
20
|
}
|
|
26
21
|
return out;
|
|
27
22
|
};
|
|
28
|
-
const readZintrustConfig = (cwd) => {
|
|
29
|
-
const filePath = path.join(cwd, '.zintrust.json');
|
|
30
|
-
if (!existsSync(filePath)) {
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
const raw = readFileSync(filePath, 'utf8');
|
|
35
|
-
const parsed = JSON.parse(raw);
|
|
36
|
-
return typeof parsed === 'object' && parsed !== null ? parsed : {};
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
throw ErrorFactory.createCliError('Failed to parse .zintrust.json', error);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const getConfigArray = (config, key) => {
|
|
43
|
-
const raw = config[key];
|
|
44
|
-
if (!Array.isArray(raw))
|
|
45
|
-
return [];
|
|
46
|
-
return uniq(raw.filter((item) => typeof item === 'string'));
|
|
47
|
-
};
|
|
48
23
|
const resolveConfigGroups = (options) => {
|
|
49
24
|
return uniq(toStringArray(options.var));
|
|
50
25
|
};
|
|
@@ -60,41 +35,12 @@ const parseEnvPath = (options) => {
|
|
|
60
35
|
return direct;
|
|
61
36
|
return '.env';
|
|
62
37
|
};
|
|
63
|
-
const resolveValue = (key, envMap) => {
|
|
64
|
-
const fromFile = envMap[key];
|
|
65
|
-
const fromProcess = process.env[key];
|
|
66
|
-
return fromFile ?? fromProcess ?? '';
|
|
67
|
-
};
|
|
68
|
-
const getPutTimeoutMs = () => {
|
|
69
|
-
const raw = process.env['ZT_PUT_TIMEOUT_MS'];
|
|
70
|
-
if (typeof raw !== 'string')
|
|
71
|
-
return 120000;
|
|
72
|
-
const parsed = Number.parseInt(raw, 10);
|
|
73
|
-
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
74
|
-
return 120000;
|
|
75
|
-
return parsed;
|
|
76
|
-
};
|
|
77
|
-
const putSecret = (wranglerEnv, key, value, configPath) => {
|
|
78
|
-
const npmPath = resolveNpmPath();
|
|
79
|
-
const args = ['exec', '--yes', '--', 'wrangler'];
|
|
80
|
-
if (typeof configPath === 'string' && configPath.trim().length > 0) {
|
|
81
|
-
args.push('--config', configPath.trim());
|
|
82
|
-
}
|
|
83
|
-
args.push('secret', 'put', key, '--env', wranglerEnv);
|
|
84
|
-
execFileSync(npmPath, args, {
|
|
85
|
-
stdio: ['pipe', 'inherit', 'inherit'],
|
|
86
|
-
input: value,
|
|
87
|
-
encoding: 'utf8',
|
|
88
|
-
timeout: getPutTimeoutMs(),
|
|
89
|
-
killSignal: 'SIGTERM',
|
|
90
|
-
env: appConfig.getSafeEnv(),
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
38
|
const addOptions = (command) => {
|
|
94
39
|
command
|
|
95
40
|
.argument('[provider]', 'Secret provider (cloudflare)', 'cloudflare')
|
|
96
41
|
.option('--wg <env...>', 'Wrangler environment target(s), e.g. d1-proxy kv-proxy')
|
|
97
42
|
.option('--var <configKey...>', 'Config array key(s) from .zintrust.json (e.g. d1_env kv_env)')
|
|
43
|
+
.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets')
|
|
98
44
|
.option('--env_path <path>', 'Path to env file used as source values', '.env')
|
|
99
45
|
.option('-c, --config <path>', 'Wrangler config file to target (optional)')
|
|
100
46
|
.option('--dry-run', 'Show what would be uploaded without calling wrangler');
|
|
@@ -104,70 +50,21 @@ const ensureCloudflareProvider = (providerRaw) => {
|
|
|
104
50
|
return;
|
|
105
51
|
throw ErrorFactory.createCliError('Only cloudflare provider is supported for `zin put`');
|
|
106
52
|
};
|
|
107
|
-
const resolveSelectedKeys = (cmd, config, options) => {
|
|
108
|
-
const configGroups = resolveConfigGroups(options);
|
|
109
|
-
if (configGroups.length === 0) {
|
|
110
|
-
throw ErrorFactory.createCliError('No config groups selected. Use --var <group>.');
|
|
111
|
-
}
|
|
112
|
-
const selectedKeys = uniq(configGroups.flatMap((groupKey) => {
|
|
113
|
-
const keys = getConfigArray(config, groupKey);
|
|
114
|
-
if (keys.length === 0) {
|
|
115
|
-
cmd.warn(`Group \`${groupKey}\` is missing or empty in .zintrust.json`);
|
|
116
|
-
}
|
|
117
|
-
return keys;
|
|
118
|
-
}));
|
|
119
|
-
if (selectedKeys.length === 0) {
|
|
120
|
-
throw ErrorFactory.createCliError('No secret keys resolved from selected groups.');
|
|
121
|
-
}
|
|
122
|
-
return selectedKeys;
|
|
123
|
-
};
|
|
124
|
-
const getFailureReason = (error) => error instanceof Error ? error.message : String(error);
|
|
125
|
-
const reportResult = (cmd, pushed, failures) => {
|
|
126
|
-
cmd.success(`Cloudflare secrets report: pushed=${pushed}, failed=${failures.length}`);
|
|
127
|
-
for (const item of failures) {
|
|
128
|
-
cmd.warn(`${item.key} -> ${item.wranglerEnv}: ${item.reason}`);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
const processPut = (cmd, wranglerEnvs, selectedKeys, envMap, dryRun, configPath) => {
|
|
132
|
-
let pushed = 0;
|
|
133
|
-
const failures = [];
|
|
134
|
-
for (const wranglerEnv of wranglerEnvs) {
|
|
135
|
-
for (const key of selectedKeys) {
|
|
136
|
-
const value = resolveValue(key, envMap);
|
|
137
|
-
if (value.trim() === '') {
|
|
138
|
-
failures.push({ wranglerEnv, key, reason: 'empty value' });
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
if (!dryRun) {
|
|
143
|
-
cmd.info(`putting ${key} -> ${wranglerEnv}...`);
|
|
144
|
-
putSecret(wranglerEnv, key, value, configPath);
|
|
145
|
-
}
|
|
146
|
-
pushed += 1;
|
|
147
|
-
cmd.info(`${dryRun ? '[dry-run] ' : ''}put ${key} -> ${wranglerEnv}`);
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
failures.push({ wranglerEnv, key, reason: getFailureReason(error) });
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return { pushed, failures };
|
|
155
|
-
};
|
|
156
53
|
const execute = async (cmd, options) => {
|
|
157
54
|
ensureCloudflareProvider(String(options.args?.[0] ?? 'cloudflare'));
|
|
158
55
|
const cwd = process.cwd();
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
56
|
+
const result = await syncCloudflareSecrets({
|
|
57
|
+
log: cmd,
|
|
58
|
+
cwd,
|
|
59
|
+
wranglerEnvs: resolveWranglerEnvs(options),
|
|
60
|
+
envPath: parseEnvPath(options),
|
|
61
|
+
dryRun: options.dryRun === true,
|
|
62
|
+
configGroups: resolveConfigGroups(options),
|
|
63
|
+
configPath: typeof options.config === 'string' ? options.config.trim() : undefined,
|
|
64
|
+
target: typeof options.target === 'string' ? options.target : undefined,
|
|
65
|
+
requireSelection: true,
|
|
66
|
+
});
|
|
67
|
+
reportCloudflareSecretSync(cmd, result);
|
|
171
68
|
};
|
|
172
69
|
export const PutCommand = Object.freeze({
|
|
173
70
|
create() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA6lCvF,eAAO,MAAM,YAAY;cACb,YAAY;;mCA3hCU,MAAM,KAAG,OAAO;4CAaP,MAAM,KAAG,MAAM;4CA4Bf,MAAM,KAAG,OAAO;sCAetB,MAAM,WAAW,MAAM,KAAG,OAAO;oCAmBnC,MAAM,KAAG,OAAO;;EA2/BjD,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../BaseCommand.js';
|
|
2
|
+
import { readZintrustConfig, resolveCloudflareEnvKeys, } from '../cloudflare/CloudflareEnvTargetConfig.js';
|
|
2
3
|
import { createDenoRunnerSource, createLambdaRunnerSource } from '../commands/runner/index.js';
|
|
3
4
|
import { EnvFileLoader } from '../utils/EnvFileLoader.js';
|
|
4
5
|
import { SpawnUtil } from '../utils/spawn.js';
|
|
@@ -336,11 +337,31 @@ const buildStartEnv = (projectRoot) => ({
|
|
|
336
337
|
...process.env,
|
|
337
338
|
ZINTRUST_PROJECT_ROOT: projectRoot,
|
|
338
339
|
});
|
|
339
|
-
const
|
|
340
|
+
const WRANGLER_RUNTIME_ENV_KEYS = Object.freeze([
|
|
341
|
+
'APP_PORT',
|
|
342
|
+
'CLOUDFLARE_WORKER',
|
|
343
|
+
'DOCKER_WORKER',
|
|
344
|
+
'ENVIRONMENT',
|
|
345
|
+
'HOST',
|
|
346
|
+
'NODE_ENV',
|
|
347
|
+
'PORT',
|
|
348
|
+
'RUNTIME',
|
|
349
|
+
'SERVICE_DOMAIN',
|
|
350
|
+
'SERVICE_NAME',
|
|
351
|
+
'SERVICE_PORT',
|
|
352
|
+
'WORKER_ENABLED',
|
|
353
|
+
'ZINTRUST_PROJECT_ROOT',
|
|
354
|
+
]);
|
|
355
|
+
const buildWorkerDevVarsContent = (selectedKeys) => {
|
|
356
|
+
const allowedKeys = selectedKeys === undefined || selectedKeys.length === 0
|
|
357
|
+
? undefined
|
|
358
|
+
: new Set([...WRANGLER_RUNTIME_ENV_KEYS, ...selectedKeys]);
|
|
340
359
|
return (Object.entries(process.env)
|
|
341
360
|
.filter((entry) => {
|
|
342
361
|
const [key, value] = entry;
|
|
343
|
-
return isWranglerVarName(key) &&
|
|
362
|
+
return (isWranglerVarName(key) &&
|
|
363
|
+
typeof value === 'string' &&
|
|
364
|
+
(allowedKeys === undefined || allowedKeys.has(key)));
|
|
344
365
|
})
|
|
345
366
|
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
346
367
|
.join('\n') + '\n');
|
|
@@ -357,7 +378,7 @@ const reconcileWranglerEnvBackup = (targetPath, backupPath) => {
|
|
|
357
378
|
}
|
|
358
379
|
unlinkSync(backupPath);
|
|
359
380
|
};
|
|
360
|
-
async function withWranglerEnvSnapshot(cwd, envName, fn) {
|
|
381
|
+
async function withWranglerEnvSnapshot(cwd, envName, selectedKeys, fn) {
|
|
361
382
|
const normalizedEnv = typeof envName === 'string' ? envName.trim() : '';
|
|
362
383
|
const targetName = normalizedEnv === '' ? '.dev.vars' : `.dev.vars.${normalizedEnv}`;
|
|
363
384
|
const targetPath = path.join(cwd, targetName);
|
|
@@ -372,7 +393,7 @@ async function withWranglerEnvSnapshot(cwd, envName, fn) {
|
|
|
372
393
|
renameSync(targetPath, backupPath);
|
|
373
394
|
}
|
|
374
395
|
try {
|
|
375
|
-
writeFileSync(targetPath, buildWorkerDevVarsContent(), 'utf-8');
|
|
396
|
+
writeFileSync(targetPath, buildWorkerDevVarsContent(selectedKeys), 'utf-8');
|
|
376
397
|
return await fn();
|
|
377
398
|
}
|
|
378
399
|
finally {
|
|
@@ -514,42 +535,64 @@ const resolveNodeProdCommand = (cwd) => {
|
|
|
514
535
|
}
|
|
515
536
|
return { command: 'node', args: [compiled] };
|
|
516
537
|
};
|
|
517
|
-
const
|
|
518
|
-
if (runtime !== undefined) {
|
|
519
|
-
throw ErrorFactory.createCliError('Error: --runtime is not supported with --wrangler (Wrangler controls Workers runtime).');
|
|
520
|
-
}
|
|
538
|
+
const resolveWranglerDevConfig = (context, wranglerConfig) => {
|
|
521
539
|
const normalizedConfig = typeof wranglerConfig === 'string' ? wranglerConfig.trim() : '';
|
|
522
540
|
const explicitConfigFullPath = normalizedConfig.length > 0 ? path.join(context.cwd, normalizedConfig) : undefined;
|
|
523
541
|
const configPath = explicitConfigFullPath ?? findWranglerConfig(context.cwd);
|
|
524
542
|
const entry = resolveWranglerEntry(context.cwd);
|
|
525
|
-
if (explicitConfigFullPath !== undefined) {
|
|
526
|
-
|
|
527
|
-
// ok
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
throw ErrorFactory.createCliError(`Error: Wrangler config not found: ${normalizedConfig}`);
|
|
531
|
-
}
|
|
543
|
+
if (explicitConfigFullPath !== undefined && !existsSync(explicitConfigFullPath)) {
|
|
544
|
+
throw ErrorFactory.createCliError(`Error: Wrangler config not found: ${normalizedConfig}`);
|
|
532
545
|
}
|
|
533
546
|
if (configPath === undefined && entry === undefined) {
|
|
534
547
|
throw ErrorFactory.createCliError("Error: wrangler config not found (wrangler.toml/json). Run 'wrangler init' first.");
|
|
535
548
|
}
|
|
536
|
-
|
|
549
|
+
return { normalizedConfig, configPath, entry };
|
|
550
|
+
};
|
|
551
|
+
const buildWranglerDevArgs = (args) => {
|
|
537
552
|
const wranglerArgs = ['dev'];
|
|
538
|
-
if (normalizedConfig !== '') {
|
|
539
|
-
wranglerArgs.push('--config', normalizedConfig);
|
|
553
|
+
if (args.normalizedConfig !== '') {
|
|
554
|
+
wranglerArgs.push('--config', args.normalizedConfig);
|
|
540
555
|
}
|
|
541
|
-
if (configPath === undefined && entry !== undefined) {
|
|
542
|
-
wranglerArgs.push(entry);
|
|
556
|
+
if (args.configPath === undefined && args.entry !== undefined) {
|
|
557
|
+
wranglerArgs.push(args.entry);
|
|
543
558
|
}
|
|
544
|
-
if (typeof port === 'number') {
|
|
545
|
-
wranglerArgs.push('--port', String(port));
|
|
559
|
+
if (typeof args.port === 'number') {
|
|
560
|
+
wranglerArgs.push('--port', String(args.port));
|
|
546
561
|
}
|
|
547
|
-
if (envName !== undefined && envName.trim() !== '') {
|
|
548
|
-
wranglerArgs.push('--env', envName.trim());
|
|
562
|
+
if (args.envName !== undefined && args.envName.trim() !== '') {
|
|
563
|
+
wranglerArgs.push('--env', args.envName.trim());
|
|
564
|
+
}
|
|
565
|
+
return wranglerArgs;
|
|
566
|
+
};
|
|
567
|
+
const resolveWranglerSelectedEnvKeys = (context, configPath, envName) => {
|
|
568
|
+
const zintrustConfigPath = path.join(context.projectRoot, '.zintrust.json');
|
|
569
|
+
if (!existsSync(zintrustConfigPath))
|
|
570
|
+
return undefined;
|
|
571
|
+
return resolveCloudflareEnvKeys({
|
|
572
|
+
config: readZintrustConfig(context.projectRoot),
|
|
573
|
+
projectRoot: context.projectRoot,
|
|
574
|
+
cwd: context.cwd,
|
|
575
|
+
...(configPath === undefined ? {} : { configPath }),
|
|
576
|
+
...(envName === undefined ? {} : { wranglerEnv: envName }),
|
|
577
|
+
});
|
|
578
|
+
};
|
|
579
|
+
const executeWranglerStart = async (cmd, context, port, runtime, envName, wranglerConfig) => {
|
|
580
|
+
if (runtime !== undefined) {
|
|
581
|
+
throw ErrorFactory.createCliError('Error: --runtime is not supported with --wrangler (Wrangler controls Workers runtime).');
|
|
549
582
|
}
|
|
583
|
+
const { normalizedConfig, configPath, entry } = resolveWranglerDevConfig(context, wranglerConfig);
|
|
584
|
+
warnOnUnsafeWranglerBootstrap(cmd, context.cwd, entry);
|
|
585
|
+
const wranglerArgs = buildWranglerDevArgs({
|
|
586
|
+
normalizedConfig,
|
|
587
|
+
configPath,
|
|
588
|
+
entry,
|
|
589
|
+
port,
|
|
590
|
+
envName,
|
|
591
|
+
});
|
|
550
592
|
logMySqlProxyHint(cmd);
|
|
551
593
|
cmd.info('Starting in Wrangler dev mode...');
|
|
552
|
-
const
|
|
594
|
+
const selectedEnvKeys = resolveWranglerSelectedEnvKeys(context, configPath, envName);
|
|
595
|
+
const exitCode = await withWranglerEnvSnapshot(context.cwd, envName, selectedEnvKeys, async () => {
|
|
553
596
|
const startEnv = {
|
|
554
597
|
...buildStartEnv(context.projectRoot),
|
|
555
598
|
WORKER_ENABLED: 'false',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;
|
|
1
|
+
{"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AA4eD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsBrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAsBA;AA8ID;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAsB,GAAG,kBAAkB,CAsB/F;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
|
|
@@ -93,6 +93,30 @@ const createProjectConfigFile = (projectPath, variables) => {
|
|
|
93
93
|
server: {
|
|
94
94
|
port: variables['port'] ?? 7777,
|
|
95
95
|
},
|
|
96
|
+
cloudflare: {
|
|
97
|
+
shared_env: ['APP_KEY', 'JWT_SECRET', 'SESSION_SECRET'],
|
|
98
|
+
targets: {
|
|
99
|
+
worker: [],
|
|
100
|
+
'containers-proxy': [
|
|
101
|
+
'MYSQL_PROXY_KEY_ID',
|
|
102
|
+
'MYSQL_PROXY_SECRET',
|
|
103
|
+
'POSTGRES_PROXY_KEY_ID',
|
|
104
|
+
'POSTGRES_PROXY_SECRET',
|
|
105
|
+
'REDIS_PROXY_KEY_ID',
|
|
106
|
+
'REDIS_PROXY_SECRET',
|
|
107
|
+
'MONGODB_PROXY_KEY_ID',
|
|
108
|
+
'MONGODB_PROXY_SECRET',
|
|
109
|
+
'SQLSERVER_PROXY_KEY_ID',
|
|
110
|
+
'SQLSERVER_PROXY_SECRET',
|
|
111
|
+
'SMTP_PROXY_KEY_ID',
|
|
112
|
+
'SMTP_PROXY_SECRET',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
wrangler_envs: {
|
|
116
|
+
'd1-proxy': ['D1_REMOTE_KEY_ID', 'D1_REMOTE_SECRET'],
|
|
117
|
+
'kv-proxy': ['KV_REMOTE_KEY_ID', 'KV_REMOTE_SECRET'],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
96
120
|
};
|
|
97
121
|
fs.writeFileSync(fullPath, JSON.stringify(config, null, 2));
|
|
98
122
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ServiceScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"ServiceScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ServiceScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD;;GAEG;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAuB7F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAGnF;AAED;;GAEG;AAEH,wBAAgB,QAAQ,CACtB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,qBAAqB,CAAC,CAkDhC;AA8eD,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAC"}
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { FileGenerator } from '../scaffolding/FileGenerator.js';
|
|
6
6
|
import { Logger } from '../../config/logger.js';
|
|
7
|
+
import { isArray, isObject } from '../../helper/index.js';
|
|
7
8
|
import * as path from '../../node-singletons/path.js';
|
|
8
9
|
const coreModuleSpecifier = ['@zintrust', 'core'].join('/');
|
|
9
10
|
const coreStartModuleSpecifier = `${coreModuleSpecifier}/start`;
|
|
10
11
|
const serviceManifestImportExpression = "import('./bootstrap/service-manifest.ts').catch(() => import('./bootstrap/service-manifest.js'))";
|
|
11
12
|
const buildRouteImportExpression = (domain, serviceName) => `import('../services/${domain}/${serviceName}/routes/api.ts').catch(() => import('../services/${domain}/${serviceName}/routes/api.js'))`;
|
|
12
13
|
const getServiceConfigRoot = (domain, serviceName) => `src/services/${domain}/${serviceName}/config`;
|
|
14
|
+
const getServiceId = (domain, serviceName) => `${domain}/${serviceName}`;
|
|
13
15
|
/**
|
|
14
16
|
* ServiceScaffolder generates microservices with all necessary files
|
|
15
17
|
*/
|
|
@@ -74,6 +76,7 @@ export function scaffold(projectRoot, options) {
|
|
|
74
76
|
ensureProjectRuntimeFiles(projectRoot, options);
|
|
75
77
|
const filesCreated = createServiceFiles(servicePath, options);
|
|
76
78
|
updateServiceManifest(projectRoot, options);
|
|
79
|
+
ensureCloudflareServiceTarget(projectRoot, options);
|
|
77
80
|
return Promise.resolve({
|
|
78
81
|
success: true,
|
|
79
82
|
serviceName: options.name,
|
|
@@ -95,7 +98,7 @@ export function scaffold(projectRoot, options) {
|
|
|
95
98
|
}
|
|
96
99
|
function ensureProjectRuntimeFiles(projectRoot, options) {
|
|
97
100
|
const domain = options.domain ?? 'default';
|
|
98
|
-
const serviceId =
|
|
101
|
+
const serviceId = getServiceId(domain, options.name);
|
|
99
102
|
const routeImportExpression = buildRouteImportExpression(domain, options.name);
|
|
100
103
|
const bootstrapDir = path.join(projectRoot, 'src', 'bootstrap');
|
|
101
104
|
FileGenerator.createDirectory(bootstrapDir);
|
|
@@ -138,7 +141,7 @@ export default Object.freeze({ serviceManifest });
|
|
|
138
141
|
}
|
|
139
142
|
function updateServiceManifest(projectRoot, options) {
|
|
140
143
|
const domain = options.domain ?? 'default';
|
|
141
|
-
const serviceId =
|
|
144
|
+
const serviceId = getServiceId(domain, options.name);
|
|
142
145
|
const routeImportExpression = buildRouteImportExpression(domain, options.name);
|
|
143
146
|
const manifestPath = path.join(projectRoot, 'src', 'bootstrap', 'service-manifest.ts');
|
|
144
147
|
if (!FileGenerator.fileExists(manifestPath))
|
|
@@ -168,6 +171,33 @@ function updateServiceManifest(projectRoot, options) {
|
|
|
168
171
|
const next = `${current.slice(0, markerIndex)}${entry}${current.slice(markerIndex)}`;
|
|
169
172
|
FileGenerator.writeFile(manifestPath, next, { overwrite: true });
|
|
170
173
|
}
|
|
174
|
+
function ensureCloudflareServiceTarget(projectRoot, options) {
|
|
175
|
+
const configPath = path.join(projectRoot, '.zintrust.json');
|
|
176
|
+
if (!FileGenerator.fileExists(configPath))
|
|
177
|
+
return;
|
|
178
|
+
try {
|
|
179
|
+
const raw = FileGenerator.readFile(configPath);
|
|
180
|
+
const parsed = JSON.parse(raw);
|
|
181
|
+
if (!isObject(parsed))
|
|
182
|
+
return;
|
|
183
|
+
const config = { ...parsed };
|
|
184
|
+
const cloudflare = isObject(config['cloudflare']) ? { ...config['cloudflare'] } : {};
|
|
185
|
+
const targets = isObject(cloudflare['targets']) ? { ...cloudflare['targets'] } : {};
|
|
186
|
+
const domain = options.domain ?? 'default';
|
|
187
|
+
const serviceId = getServiceId(domain, options.name);
|
|
188
|
+
if (isArray(targets[serviceId]))
|
|
189
|
+
return;
|
|
190
|
+
targets[serviceId] = [];
|
|
191
|
+
cloudflare['targets'] = targets;
|
|
192
|
+
config['cloudflare'] = cloudflare;
|
|
193
|
+
FileGenerator.writeFile(`${configPath}`, `${JSON.stringify(config, null, 2)}\n`, {
|
|
194
|
+
overwrite: true,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
Logger.warn(`Unable to update .zintrust.json Cloudflare targets for ${options.domain ?? 'default'}/${options.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
171
201
|
/**
|
|
172
202
|
* Create service directory structure
|
|
173
203
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"AASA,KAAK,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"AASA,KAAK,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AA8IzD,KAAK,WAAW,GAAG;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAaF,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAwMF,eAAO,MAAM,aAAa;qBAjDH,WAAW,KAAQ,SAAS;6BAapB,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,KAAQ,SAAS;mCAG/C,YAAY,KAAG,IAAI;oBA+BpC,SAAS;EAO5B,CAAC"}
|
|
@@ -2,10 +2,8 @@ import { Env } from '../../config/env.js';
|
|
|
2
2
|
import { isArray, isNonEmptyString } from '../../helper/index.js';
|
|
3
3
|
import { existsSync, readFileSync } from '../../node-singletons/fs.js';
|
|
4
4
|
import * as path from '../../node-singletons/path.js';
|
|
5
|
+
const PACK_CONTROL_KEYS = new Set(['USE_PACK', 'PACK_KEYS']);
|
|
5
6
|
const safeEnvGet = (key, defaultValue = '') => {
|
|
6
|
-
const envAny = Env;
|
|
7
|
-
if (typeof envAny.get === 'function')
|
|
8
|
-
return envAny.get(key, defaultValue);
|
|
9
7
|
const fromProcess = typeof process === 'undefined' ? undefined : process.env?.[key];
|
|
10
8
|
if (typeof fromProcess === 'string' && fromProcess !== '')
|
|
11
9
|
return fromProcess;
|
|
@@ -109,6 +107,18 @@ const readEnvFileIfExists = (cwd, filename) => {
|
|
|
109
107
|
const raw = readFileSync(fullPath, 'utf-8');
|
|
110
108
|
return parseEnvFile(raw);
|
|
111
109
|
};
|
|
110
|
+
const readPackEnvFileIfExists = (cwd) => {
|
|
111
|
+
const parsed = readEnvFileIfExists(cwd, '.env.pack');
|
|
112
|
+
if (parsed === undefined)
|
|
113
|
+
return undefined;
|
|
114
|
+
const filtered = {};
|
|
115
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
116
|
+
if (PACK_CONTROL_KEYS.has(key))
|
|
117
|
+
continue;
|
|
118
|
+
filtered[key] = value;
|
|
119
|
+
}
|
|
120
|
+
return filtered;
|
|
121
|
+
};
|
|
112
122
|
const resolveAppMode = (cwd) => {
|
|
113
123
|
const existing = safeEnvGet('NODE_ENV', '');
|
|
114
124
|
if (existing.trim() !== '')
|
|
@@ -143,11 +153,13 @@ let cached;
|
|
|
143
153
|
const loadFromCwd = (cwd, overrideExisting) => {
|
|
144
154
|
const mode = resolveAppMode(cwd);
|
|
145
155
|
const files = filesLoader(cwd, mode);
|
|
156
|
+
const loadedFiles = [];
|
|
146
157
|
let baseApplied = false;
|
|
147
158
|
for (const file of files) {
|
|
148
159
|
const parsed = readEnvFileIfExists(cwd, file);
|
|
149
160
|
if (!parsed)
|
|
150
161
|
continue;
|
|
162
|
+
loadedFiles.push(file);
|
|
151
163
|
if (file === '.env') {
|
|
152
164
|
applyToProcessEnv(parsed, overrideExisting);
|
|
153
165
|
baseApplied = true;
|
|
@@ -156,11 +168,16 @@ const loadFromCwd = (cwd, overrideExisting) => {
|
|
|
156
168
|
// .env is primary: overlays only fill missing values and never override base.
|
|
157
169
|
applyToProcessEnv(parsed, baseApplied ? false : overrideExisting);
|
|
158
170
|
}
|
|
171
|
+
const packedEnv = readPackEnvFileIfExists(cwd);
|
|
172
|
+
if (packedEnv !== undefined) {
|
|
173
|
+
applyToProcessEnv(packedEnv, false);
|
|
174
|
+
loadedFiles.push('.env.pack');
|
|
175
|
+
}
|
|
159
176
|
// Set NODE_ENV to the normalized mode if we have one (after applying files)
|
|
160
177
|
if (mode !== undefined) {
|
|
161
178
|
safeEnvSet('NODE_ENV', mode);
|
|
162
179
|
}
|
|
163
|
-
return { loadedFiles
|
|
180
|
+
return { loadedFiles, mode };
|
|
164
181
|
};
|
|
165
182
|
const loadFromFile = (filePath, overrideExisting) => {
|
|
166
183
|
if (!existsSync(filePath))
|
package/src/config/env.d.ts
CHANGED
|
@@ -7,8 +7,19 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { ProcessLike } from './type';
|
|
9
9
|
export type EnvSource = Record<string, unknown> | (() => Record<string, unknown>);
|
|
10
|
+
export type ResolvedEnvState = {
|
|
11
|
+
values: Record<string, string>;
|
|
12
|
+
sources: Record<string, string>;
|
|
13
|
+
packedEnabled: boolean;
|
|
14
|
+
packedKeys: string[];
|
|
15
|
+
};
|
|
10
16
|
export declare const getProcessLike: () => ProcessLike | undefined;
|
|
11
17
|
export declare const dirnameFromExecPath: (execPath: string, platform?: string) => string;
|
|
18
|
+
export declare const getOptional: (key: string) => string | undefined;
|
|
19
|
+
export declare const has: (key: string) => boolean;
|
|
20
|
+
export declare const getSourceOf: (key: string) => string | undefined;
|
|
21
|
+
export declare const snapshotSources: () => Record<string, string>;
|
|
22
|
+
export declare const getResolvedState: () => ResolvedEnvState;
|
|
12
23
|
export declare const get: (key: string, defaultValue?: string) => string;
|
|
13
24
|
export declare const getInt: (key: string, defaultValue: number) => number;
|
|
14
25
|
export declare const getFloat: (key: string, defaultValue?: number) => number;
|
|
@@ -21,13 +32,18 @@ export declare const getDefaultLogLevel: () => "debug" | "info" | "warn" | "erro
|
|
|
21
32
|
export declare const ZT_PROXY_TIMEOUT_MS: number;
|
|
22
33
|
export declare const Env: Readonly<{
|
|
23
34
|
get: (key: string, defaultValue?: string) => string;
|
|
35
|
+
getOptional: (key: string) => string | undefined;
|
|
24
36
|
getInt: (key: string, defaultValue: number) => number;
|
|
25
37
|
getBool: (key: string, defaultValue?: boolean) => boolean;
|
|
26
38
|
getFloat: (key: string, defaultValue?: number) => number;
|
|
39
|
+
has: (key: string) => boolean;
|
|
27
40
|
set: (key: string, value: string) => void;
|
|
28
41
|
unset: (key: string) => void;
|
|
29
42
|
setSource: (source: EnvSource | null) => void;
|
|
30
43
|
snapshot: () => Record<string, string>;
|
|
44
|
+
getSourceOf: (key: string) => string | undefined;
|
|
45
|
+
snapshotSources: () => Record<string, string>;
|
|
46
|
+
getResolvedState: () => ResolvedEnvState;
|
|
31
47
|
NODE_ENV: NodeJS.ProcessEnv["NODE_ENV"];
|
|
32
48
|
PORT: number;
|
|
33
49
|
HOST: string;
|
package/src/config/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"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"}
|