@zintrust/core 0.4.39 → 0.4.40
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 +148 -0
- package/src/cli/commands/DeployCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployCommand.js +25 -3
- package/src/cli/commands/DeployContainersProxyCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployContainersProxyCommand.js +25 -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/index.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.40",
|
|
4
4
|
"description": "Production-grade TypeScript backend framework for JavaScript",
|
|
5
5
|
"homepage": "https://zintrust.com",
|
|
6
6
|
"repository": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@cloudflare/containers": "^0.2.0",
|
|
61
|
-
"@zintrust/workers": "^0.4.
|
|
61
|
+
"@zintrust/workers": "^0.4.40",
|
|
62
62
|
"bcryptjs": "^3.0.3",
|
|
63
63
|
"bullmq": "^5.71.1",
|
|
64
64
|
"chalk": "^5.6.2",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type ZintrustConfig = Record<string, unknown>;
|
|
2
|
+
export interface CloudflareEnvTargetConfig {
|
|
3
|
+
sharedEnv: string[];
|
|
4
|
+
wranglerEnvs: Record<string, string[]>;
|
|
5
|
+
targets: Record<string, string[]>;
|
|
6
|
+
}
|
|
7
|
+
type ResolveTargetArgs = {
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
cwd: string;
|
|
10
|
+
configPath?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const readZintrustConfig: (cwd: string) => ZintrustConfig;
|
|
13
|
+
export declare const resolveCloudflareEnvTargetConfig: (config: ZintrustConfig) => CloudflareEnvTargetConfig;
|
|
14
|
+
export declare const inferCloudflareTarget: ({ projectRoot, cwd, configPath, }: ResolveTargetArgs) => string;
|
|
15
|
+
export declare const resolveCloudflareEnvKeys: (args: {
|
|
16
|
+
config: ZintrustConfig;
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
cwd: string;
|
|
19
|
+
configPath?: string;
|
|
20
|
+
wranglerEnv?: string;
|
|
21
|
+
target?: string;
|
|
22
|
+
}) => string[];
|
|
23
|
+
declare const _default: Readonly<{
|
|
24
|
+
readZintrustConfig: (cwd: string) => ZintrustConfig;
|
|
25
|
+
resolveCloudflareEnvTargetConfig: (config: ZintrustConfig) => CloudflareEnvTargetConfig;
|
|
26
|
+
inferCloudflareTarget: ({ projectRoot, cwd, configPath, }: ResolveTargetArgs) => string;
|
|
27
|
+
resolveCloudflareEnvKeys: (args: {
|
|
28
|
+
config: ZintrustConfig;
|
|
29
|
+
projectRoot: string;
|
|
30
|
+
cwd: string;
|
|
31
|
+
configPath?: string;
|
|
32
|
+
wranglerEnv?: string;
|
|
33
|
+
target?: string;
|
|
34
|
+
}) => string[];
|
|
35
|
+
}>;
|
|
36
|
+
export default _default;
|
|
37
|
+
//# sourceMappingURL=CloudflareEnvTargetConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloudflareEnvTargetConfig.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloudflare/CloudflareEnvTargetConfig.ts"],"names":[],"mappings":"AAKA,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAED,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAkCF,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,cAahD,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC3C,QAAQ,cAAc,KACrB,yBAQF,CAAC;AAqBF,eAAO,MAAM,qBAAqB,GAAI,mCAInC,iBAAiB,KAAG,MActB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,MAAM;IAC7C,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,KAAG,MAAM,EAiBT,CAAC;;8BA1FsC,MAAM,KAAG,cAAc;+CAgBrD,cAAc,KACrB,yBAAyB;+DAiCzB,iBAAiB,KAAG,MAAM;qCAgBkB;QAC7C,MAAM,EAAE,cAAc,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAG,MAAM,EAAE;;AAmBZ,wBAKG"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
|
+
import { isArray, isNonEmptyString, isObject } from '../../helper/index.js';
|
|
3
|
+
import { existsSync, readFileSync } from '../../node-singletons/fs.js';
|
|
4
|
+
import * as path from '../../node-singletons/path.js';
|
|
5
|
+
const uniq = (items) => {
|
|
6
|
+
const seen = new Set();
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const item of items) {
|
|
9
|
+
const normalized = item.trim();
|
|
10
|
+
if (normalized === '' || seen.has(normalized))
|
|
11
|
+
continue;
|
|
12
|
+
seen.add(normalized);
|
|
13
|
+
out.push(normalized);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
};
|
|
17
|
+
const toStringArray = (value) => {
|
|
18
|
+
if (!isArray(value))
|
|
19
|
+
return [];
|
|
20
|
+
return uniq(value.filter(isNonEmptyString).map((item) => item.trim()));
|
|
21
|
+
};
|
|
22
|
+
const toStringArrayRecord = (value) => {
|
|
23
|
+
if (!isObject(value))
|
|
24
|
+
return {};
|
|
25
|
+
return Object.fromEntries(Object.entries(value)
|
|
26
|
+
.filter(([key]) => isNonEmptyString(key))
|
|
27
|
+
.map(([key, entry]) => [key.trim(), toStringArray(entry)]));
|
|
28
|
+
};
|
|
29
|
+
const isAbsolutePath = (value) => value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
|
|
30
|
+
export const readZintrustConfig = (cwd) => {
|
|
31
|
+
const filePath = path.join(cwd, '.zintrust.json');
|
|
32
|
+
if (!existsSync(filePath)) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
37
|
+
const parsed = JSON.parse(raw);
|
|
38
|
+
return isObject(parsed) ? parsed : {};
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
throw ErrorFactory.createCliError('Failed to parse .zintrust.json', error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export const resolveCloudflareEnvTargetConfig = (config) => {
|
|
45
|
+
const raw = isObject(config['cloudflare']) ? config['cloudflare'] : {};
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
sharedEnv: toStringArray(raw['shared_env']),
|
|
48
|
+
wranglerEnvs: toStringArrayRecord(raw['wrangler_envs']),
|
|
49
|
+
targets: toStringArrayRecord(raw['targets']),
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const normalizeConfigPath = (cwd, configPath) => {
|
|
53
|
+
if (!isNonEmptyString(configPath))
|
|
54
|
+
return undefined;
|
|
55
|
+
return isAbsolutePath(configPath) ? configPath : path.join(cwd, configPath);
|
|
56
|
+
};
|
|
57
|
+
const inferServiceTarget = (projectRoot, candidateDir) => {
|
|
58
|
+
const servicesRoot = path.join(projectRoot, 'src', 'services');
|
|
59
|
+
const relative = path.relative(servicesRoot, candidateDir);
|
|
60
|
+
if (relative === '' || relative.startsWith('..'))
|
|
61
|
+
return undefined;
|
|
62
|
+
const segments = relative
|
|
63
|
+
.split(path.sep)
|
|
64
|
+
.map((segment) => segment.trim())
|
|
65
|
+
.filter((segment) => segment !== '');
|
|
66
|
+
if (segments.length < 2)
|
|
67
|
+
return undefined;
|
|
68
|
+
return `${segments[0]}/${segments[1]}`;
|
|
69
|
+
};
|
|
70
|
+
export const inferCloudflareTarget = ({ projectRoot, cwd, configPath, }) => {
|
|
71
|
+
const normalizedConfigPath = normalizeConfigPath(cwd, configPath);
|
|
72
|
+
const configBase = normalizedConfigPath === undefined ? '' : path.basename(normalizedConfigPath);
|
|
73
|
+
if (configBase.startsWith('wrangler.containers-proxy.')) {
|
|
74
|
+
return 'containers-proxy';
|
|
75
|
+
}
|
|
76
|
+
const candidateDir = normalizedConfigPath === undefined ? cwd : path.dirname(normalizedConfigPath);
|
|
77
|
+
const serviceTarget = inferServiceTarget(projectRoot, candidateDir);
|
|
78
|
+
if (serviceTarget !== undefined)
|
|
79
|
+
return serviceTarget;
|
|
80
|
+
return 'worker';
|
|
81
|
+
};
|
|
82
|
+
export const resolveCloudflareEnvKeys = (args) => {
|
|
83
|
+
const cloudflare = resolveCloudflareEnvTargetConfig(args.config);
|
|
84
|
+
const target = isNonEmptyString(args.target)
|
|
85
|
+
? args.target.trim()
|
|
86
|
+
: inferCloudflareTarget({
|
|
87
|
+
projectRoot: args.projectRoot,
|
|
88
|
+
cwd: args.cwd,
|
|
89
|
+
configPath: args.configPath,
|
|
90
|
+
});
|
|
91
|
+
const wranglerEnv = isNonEmptyString(args.wranglerEnv) ? args.wranglerEnv.trim() : undefined;
|
|
92
|
+
return uniq([
|
|
93
|
+
...cloudflare.sharedEnv,
|
|
94
|
+
...(cloudflare.targets['default'] ?? []),
|
|
95
|
+
...(cloudflare.targets[target] ?? []),
|
|
96
|
+
...(wranglerEnv === undefined ? [] : (cloudflare.wranglerEnvs[wranglerEnv] ?? [])),
|
|
97
|
+
]);
|
|
98
|
+
};
|
|
99
|
+
export default Object.freeze({
|
|
100
|
+
readZintrustConfig,
|
|
101
|
+
resolveCloudflareEnvTargetConfig,
|
|
102
|
+
inferCloudflareTarget,
|
|
103
|
+
resolveCloudflareEnvKeys,
|
|
104
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type CloudflareSecretLog = {
|
|
2
|
+
info: (message: string) => void;
|
|
3
|
+
warn: (message: string) => void;
|
|
4
|
+
success?: (message: string) => void;
|
|
5
|
+
};
|
|
6
|
+
export type CloudflareSecretSyncFailure = {
|
|
7
|
+
wranglerEnv: string;
|
|
8
|
+
key: string;
|
|
9
|
+
reason: string;
|
|
10
|
+
};
|
|
11
|
+
type CloudflareSecretSyncArgs = {
|
|
12
|
+
log: CloudflareSecretLog;
|
|
13
|
+
cwd: string;
|
|
14
|
+
wranglerEnvs: string[];
|
|
15
|
+
envPath: string;
|
|
16
|
+
dryRun?: boolean;
|
|
17
|
+
configGroups?: string[];
|
|
18
|
+
configPath?: string;
|
|
19
|
+
target?: string;
|
|
20
|
+
requireSelection?: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type CloudflareSecretSyncResult = {
|
|
23
|
+
pushed: number;
|
|
24
|
+
failures: CloudflareSecretSyncFailure[];
|
|
25
|
+
selectedKeys: string[];
|
|
26
|
+
};
|
|
27
|
+
export declare const reportCloudflareSecretSync: (log: CloudflareSecretLog, result: Pick<CloudflareSecretSyncResult, "pushed" | "failures">) => void;
|
|
28
|
+
export declare const syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, configPath, target, requireSelection, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
29
|
+
declare const _default: Readonly<{
|
|
30
|
+
syncCloudflareSecrets: ({ log, cwd, wranglerEnvs, envPath, dryRun, configGroups, configPath, target, requireSelection, }: CloudflareSecretSyncArgs) => Promise<CloudflareSecretSyncResult>;
|
|
31
|
+
reportCloudflareSecretSync: (log: CloudflareSecretLog, result: Pick<CloudflareSecretSyncResult, "pushed" | "failures">) => void;
|
|
32
|
+
}>;
|
|
33
|
+
export default _default;
|
|
34
|
+
//# sourceMappingURL=CloudflareSecretSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloudflareSecretSync.d.ts","sourceRoot":"","sources":["../../../../src/cli/cloudflare/CloudflareSecretSync.ts"],"names":[],"mappings":"AAYA,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;AAaF,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,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,2BAA2B,EAAE,CAAC;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAiJF,eAAO,MAAM,0BAA0B,GACrC,KAAK,mBAAmB,EACxB,QAAQ,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,UAAU,CAAC,KAC9D,IAYF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAU,kGAUzC,wBAAwB,KAAG,OAAO,CAAC,0BAA0B,CAwC/D,CAAC;;8HAxCC,wBAAwB,KAAG,OAAO,CAAC,0BAA0B,CAAC;sCA1B1D,mBAAmB,UAChB,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,UAAU,CAAC,KAC9D,IAAI;;AAkEP,wBAGG"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { readZintrustConfig, resolveCloudflareEnvKeys, } from '../cloudflare/CloudflareEnvTargetConfig.js';
|
|
2
|
+
import { resolveNpmPath } from '../../common/index.js';
|
|
3
|
+
import { appConfig } from '../../config/app.js';
|
|
4
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
5
|
+
import { execFileSync } from '../../node-singletons/child-process.js';
|
|
6
|
+
import { existsSync } from '../../node-singletons/fs.js';
|
|
7
|
+
import * as path from '../../node-singletons/path.js';
|
|
8
|
+
import { EnvFile } from '../../toolkit/Secrets/EnvFile.js';
|
|
9
|
+
const uniq = (items) => {
|
|
10
|
+
const seen = new Set();
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
const normalized = item.trim();
|
|
14
|
+
if (normalized === '' || seen.has(normalized))
|
|
15
|
+
continue;
|
|
16
|
+
seen.add(normalized);
|
|
17
|
+
out.push(normalized);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
};
|
|
21
|
+
const getConfigArray = (config, key) => {
|
|
22
|
+
const raw = config[key];
|
|
23
|
+
if (!Array.isArray(raw))
|
|
24
|
+
return [];
|
|
25
|
+
return uniq(raw.filter((item) => typeof item === 'string'));
|
|
26
|
+
};
|
|
27
|
+
const resolveValue = (key, envMap) => {
|
|
28
|
+
const fromFile = envMap[key];
|
|
29
|
+
const fromProcess = process.env[key];
|
|
30
|
+
return fromFile ?? fromProcess ?? '';
|
|
31
|
+
};
|
|
32
|
+
const getPutTimeoutMs = () => {
|
|
33
|
+
const raw = process.env['ZT_PUT_TIMEOUT_MS'];
|
|
34
|
+
if (typeof raw !== 'string')
|
|
35
|
+
return 120000;
|
|
36
|
+
const parsed = Number.parseInt(raw, 10);
|
|
37
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
38
|
+
return 120000;
|
|
39
|
+
return parsed;
|
|
40
|
+
};
|
|
41
|
+
const putSecret = (wranglerEnv, key, value, configPath) => {
|
|
42
|
+
const npmPath = resolveNpmPath();
|
|
43
|
+
const args = ['exec', '--yes', '--', 'wrangler'];
|
|
44
|
+
if (typeof configPath === 'string' && configPath.trim() !== '') {
|
|
45
|
+
args.push('--config', configPath.trim());
|
|
46
|
+
}
|
|
47
|
+
args.push('secret', 'put', key, '--env', wranglerEnv);
|
|
48
|
+
execFileSync(npmPath, args, {
|
|
49
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
50
|
+
input: value,
|
|
51
|
+
encoding: 'utf8',
|
|
52
|
+
timeout: getPutTimeoutMs(),
|
|
53
|
+
killSignal: 'SIGTERM',
|
|
54
|
+
env: appConfig.getSafeEnv(),
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const getFailureReason = (error) => error instanceof Error ? error.message : String(error);
|
|
58
|
+
const resolveSelectedKeys = ({ log, config, cwd, wranglerEnvs, configGroups = [], configPath, target, requireSelection, }) => {
|
|
59
|
+
const explicitKeys = uniq(configGroups.flatMap((groupKey) => {
|
|
60
|
+
const keys = getConfigArray(config, groupKey);
|
|
61
|
+
if (keys.length === 0) {
|
|
62
|
+
log.warn(`Group \`${groupKey}\` is missing or empty in .zintrust.json`);
|
|
63
|
+
}
|
|
64
|
+
return keys;
|
|
65
|
+
}));
|
|
66
|
+
const manifestKeys = uniq(wranglerEnvs.flatMap((wranglerEnv) => resolveCloudflareEnvKeys({
|
|
67
|
+
config,
|
|
68
|
+
projectRoot: cwd,
|
|
69
|
+
cwd,
|
|
70
|
+
...(configPath === undefined ? {} : { configPath }),
|
|
71
|
+
wranglerEnv,
|
|
72
|
+
...(typeof target === 'string' && target.trim() !== '' ? { target: target.trim() } : {}),
|
|
73
|
+
})));
|
|
74
|
+
const selectedKeys = uniq([...explicitKeys, ...manifestKeys]);
|
|
75
|
+
if (selectedKeys.length > 0 || !requireSelection) {
|
|
76
|
+
return selectedKeys;
|
|
77
|
+
}
|
|
78
|
+
throw ErrorFactory.createCliError(configGroups.length === 0
|
|
79
|
+
? 'No secret keys resolved from .zintrust.json cloudflare.shared_env/cloudflare.targets/cloudflare.wrangler_envs. Use --var <group> or add a Cloudflare env manifest.'
|
|
80
|
+
: 'No secret keys resolved from selected groups.');
|
|
81
|
+
};
|
|
82
|
+
const processSecretSync = (log, wranglerEnvs, selectedKeys, envMap, dryRun, configPath) => {
|
|
83
|
+
let pushed = 0;
|
|
84
|
+
const failures = [];
|
|
85
|
+
for (const wranglerEnv of wranglerEnvs) {
|
|
86
|
+
for (const key of selectedKeys) {
|
|
87
|
+
const value = resolveValue(key, envMap);
|
|
88
|
+
if (value.trim() === '') {
|
|
89
|
+
failures.push({ wranglerEnv, key, reason: 'empty value' });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
if (!dryRun) {
|
|
94
|
+
log.info(`putting ${key} -> ${wranglerEnv}...`);
|
|
95
|
+
putSecret(wranglerEnv, key, value, configPath);
|
|
96
|
+
}
|
|
97
|
+
pushed += 1;
|
|
98
|
+
log.info(`${dryRun ? '[dry-run] ' : ''}put ${key} -> ${wranglerEnv}`);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
failures.push({ wranglerEnv, key, reason: getFailureReason(error) });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { pushed, failures };
|
|
106
|
+
};
|
|
107
|
+
export const reportCloudflareSecretSync = (log, result) => {
|
|
108
|
+
if (typeof log.success === 'function') {
|
|
109
|
+
log.success(`Cloudflare secrets report: pushed=${result.pushed}, failed=${result.failures.length}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
log.info(`Cloudflare secrets report: pushed=${result.pushed}, failed=${result.failures.length}`);
|
|
113
|
+
}
|
|
114
|
+
for (const item of result.failures) {
|
|
115
|
+
log.warn(`${item.key} -> ${item.wranglerEnv}: ${item.reason}`);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
export const syncCloudflareSecrets = async ({ log, cwd, wranglerEnvs, envPath, dryRun = false, configGroups = [], configPath, target, requireSelection = true, }) => {
|
|
119
|
+
const normalizedConfigPath = typeof configPath === 'string' && configPath.trim() !== '' ? configPath.trim() : undefined;
|
|
120
|
+
if (normalizedConfigPath !== undefined &&
|
|
121
|
+
!existsSync(path.join(cwd, normalizedConfigPath))) {
|
|
122
|
+
throw ErrorFactory.createCliError(`Wrangler config not found: ${normalizedConfigPath}`);
|
|
123
|
+
}
|
|
124
|
+
const config = readZintrustConfig(cwd);
|
|
125
|
+
const selectedKeys = resolveSelectedKeys({
|
|
126
|
+
log,
|
|
127
|
+
config,
|
|
128
|
+
cwd,
|
|
129
|
+
wranglerEnvs,
|
|
130
|
+
configGroups,
|
|
131
|
+
configPath: normalizedConfigPath,
|
|
132
|
+
target,
|
|
133
|
+
requireSelection,
|
|
134
|
+
});
|
|
135
|
+
if (selectedKeys.length === 0) {
|
|
136
|
+
return { pushed: 0, failures: [], selectedKeys: [] };
|
|
137
|
+
}
|
|
138
|
+
const envMap = await EnvFile.read({ cwd, path: envPath });
|
|
139
|
+
const syncResult = processSecretSync(log, wranglerEnvs, selectedKeys, envMap, dryRun, normalizedConfigPath);
|
|
140
|
+
return {
|
|
141
|
+
...syncResult,
|
|
142
|
+
selectedKeys,
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
export default Object.freeze({
|
|
146
|
+
syncCloudflareSecrets,
|
|
147
|
+
reportCloudflareSecretSync,
|
|
148
|
+
});
|
|
@@ -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;AAuLrE;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;cACO,YAAY;EAGtB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../BaseCommand.js';
|
|
2
|
+
import { reportCloudflareSecretSync, syncCloudflareSecrets, } from '../cloudflare/CloudflareSecretSync.js';
|
|
2
3
|
import { SpawnUtil } from '../utils/spawn.js';
|
|
3
4
|
import { Logger } from '../../config/logger.js';
|
|
4
5
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
@@ -44,7 +45,23 @@ const deployProxyStack = async (label) => {
|
|
|
44
45
|
await runCompose(['compose', '-f', composePath, 'up', '-d', '--build']);
|
|
45
46
|
Logger.info(`✅ ${label} deployed.`);
|
|
46
47
|
};
|
|
47
|
-
const
|
|
48
|
+
const syncWranglerSecrets = async (cmd, cwd, wranglerEnv, options) => {
|
|
49
|
+
if (options.syncSecrets === false)
|
|
50
|
+
return;
|
|
51
|
+
const result = await syncCloudflareSecrets({
|
|
52
|
+
log: cmd,
|
|
53
|
+
cwd,
|
|
54
|
+
wranglerEnvs: [wranglerEnv],
|
|
55
|
+
envPath: typeof options.envPath === 'string' && options.envPath.trim() !== '' ? options.envPath : '.env',
|
|
56
|
+
configPath: typeof options.config === 'string' ? options.config.trim() : undefined,
|
|
57
|
+
target: typeof options.target === 'string' ? options.target : undefined,
|
|
58
|
+
requireSelection: false,
|
|
59
|
+
});
|
|
60
|
+
if (result.selectedKeys.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
reportCloudflareSecretSync(cmd, result);
|
|
63
|
+
};
|
|
64
|
+
const runDeploy = async (cmd, target, options) => {
|
|
48
65
|
const normalizedTarget = target.trim().toLowerCase();
|
|
49
66
|
if (normalizedTarget === 'cw' || normalizedTarget === 'cwr') {
|
|
50
67
|
const label = normalizedTarget === 'cwr'
|
|
@@ -70,6 +87,7 @@ const runDeploy = async (target, options) => {
|
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
Logger.info(`Deploying to Cloudflare environment: ${environment}`);
|
|
90
|
+
await syncWranglerSecrets(cmd, process.cwd(), environment, options);
|
|
73
91
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
74
92
|
command: 'wrangler',
|
|
75
93
|
args: ['deploy', ...(config.length > 0 ? ['--config', config] : []), '--env', environment],
|
|
@@ -79,7 +97,7 @@ const runDeploy = async (target, options) => {
|
|
|
79
97
|
}
|
|
80
98
|
};
|
|
81
99
|
const createDeployCommand = () => {
|
|
82
|
-
|
|
100
|
+
const cmd = BaseCommand.create({
|
|
83
101
|
name: 'deploy',
|
|
84
102
|
description: 'Deploy ZinTrust to Cloudflare Workers',
|
|
85
103
|
addOptions: (command) => {
|
|
@@ -87,6 +105,9 @@ const createDeployCommand = () => {
|
|
|
87
105
|
.argument('[target]', 'Deployment target (worker, d1-proxy, kv-proxy, production, cw, cp)', 'worker')
|
|
88
106
|
.option('-e, --env <env>', 'Wrangler environment (overrides target)');
|
|
89
107
|
command.option('-c, --config <path>', 'Wrangler config file (e.g. wrangler.containers-proxy.jsonc)');
|
|
108
|
+
command.option('--env-path <path>', 'Path to env file used when syncing Cloudflare secrets', '.env');
|
|
109
|
+
command.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets');
|
|
110
|
+
command.option('--no-sync-secrets', 'Skip Cloudflare secret sync before wrangler deploy');
|
|
90
111
|
},
|
|
91
112
|
execute: async (options) => {
|
|
92
113
|
// Note: BaseCommand.create sets up action handler that calls execute(options).
|
|
@@ -103,9 +124,10 @@ const createDeployCommand = () => {
|
|
|
103
124
|
//
|
|
104
125
|
// So 'target' will be available in options.args[0]
|
|
105
126
|
const target = options.args?.[0] ?? 'worker';
|
|
106
|
-
await runDeploy(target, options);
|
|
127
|
+
await runDeploy(cmd, target, options);
|
|
107
128
|
},
|
|
108
129
|
});
|
|
130
|
+
return cmd;
|
|
109
131
|
};
|
|
110
132
|
/**
|
|
111
133
|
* Deploy Command Factory
|
|
@@ -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;AA6ErE,eAAO,MAAM,4BAA4B;cAC7B,YAAY;EAkBtB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../BaseCommand.js';
|
|
2
|
+
import { reportCloudflareSecretSync, syncCloudflareSecrets, } from '../cloudflare/CloudflareSecretSync.js';
|
|
2
3
|
import { SpawnUtil } from '../utils/spawn.js';
|
|
3
4
|
import { Logger } from '../../config/logger.js';
|
|
4
5
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
@@ -17,11 +18,28 @@ const resolveEnv = (raw) => {
|
|
|
17
18
|
const normalized = typeof raw === 'string' ? raw.trim() : '';
|
|
18
19
|
return normalized.length > 0 ? normalized : 'production';
|
|
19
20
|
};
|
|
20
|
-
const
|
|
21
|
+
const syncDeploySecrets = async (cmd, cwd, config, env, options) => {
|
|
22
|
+
if (options.syncSecrets === false)
|
|
23
|
+
return;
|
|
24
|
+
const result = await syncCloudflareSecrets({
|
|
25
|
+
log: cmd,
|
|
26
|
+
cwd,
|
|
27
|
+
wranglerEnvs: [env],
|
|
28
|
+
envPath: typeof options.envPath === 'string' && options.envPath.trim() !== '' ? options.envPath : '.env',
|
|
29
|
+
configPath: config,
|
|
30
|
+
target: typeof options.target === 'string' ? options.target : undefined,
|
|
31
|
+
requireSelection: false,
|
|
32
|
+
});
|
|
33
|
+
if (result.selectedKeys.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
reportCloudflareSecretSync(cmd, result);
|
|
36
|
+
};
|
|
37
|
+
const execute = async (cmd, options) => {
|
|
21
38
|
const cwd = process.cwd();
|
|
22
39
|
const config = resolveConfig(cwd, options.config);
|
|
23
40
|
const env = resolveEnv(options.env);
|
|
24
41
|
Logger.info(`Deploying Containers proxy via Wrangler (env=${env})...`);
|
|
42
|
+
await syncDeploySecrets(cmd, cwd, config, env, options);
|
|
25
43
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
26
44
|
command: 'wrangler',
|
|
27
45
|
args: ['deploy', '--config', config, '--env', env],
|
|
@@ -31,15 +49,19 @@ const execute = async (options) => {
|
|
|
31
49
|
};
|
|
32
50
|
export const DeployContainersProxyCommand = Object.freeze({
|
|
33
51
|
create() {
|
|
34
|
-
|
|
52
|
+
const cmd = BaseCommand.create({
|
|
35
53
|
name: 'deploy:ccp',
|
|
36
54
|
aliases: ['deploy:containers-proxy', 'deploy:cf-containers-proxy', 'd:ccp', 'ccp:deploy'],
|
|
37
55
|
description: 'Deploy Cloudflare Containers proxy Worker (wrangler.containers-proxy.jsonc)',
|
|
38
56
|
addOptions: (command) => {
|
|
39
57
|
command.option('-e, --env <name>', 'Wrangler environment name', 'production');
|
|
40
58
|
command.option('-c, --config <path>', 'Wrangler config file', DEFAULT_CONFIG);
|
|
59
|
+
command.option('--env-path <path>', 'Path to env file used when syncing Cloudflare secrets', '.env');
|
|
60
|
+
command.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets');
|
|
61
|
+
command.option('--no-sync-secrets', 'Skip Cloudflare secret sync before wrangler deploy');
|
|
41
62
|
},
|
|
42
|
-
execute: async (options) => execute(options),
|
|
63
|
+
execute: async (options) => execute(cmd, options),
|
|
43
64
|
});
|
|
65
|
+
return cmd;
|
|
44
66
|
},
|
|
45
67
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProxyScaffoldUtils.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/ProxyScaffoldUtils.ts"],"names":[],"mappings":"AAKA,KAAK,4BAA4B,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,2BAA2B,CAAC,OAAO,EAAE,QAAQ,IAAI;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC;IAC3E,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5C,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,KAAK,0BAA0B,CAAC,OAAO,IAAI;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAIvE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,iBAA2B,KAAG,MAExF,CAAC;AAmBF,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,EAAE,KAAK,MAAM,KAAG,MAAM,GAAG,SAQvE,CAAC;AAmBF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,MAuBhF,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,UAAU,MAAM,EAChB,mBAAmB,MAAM,KACxB,MAaF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,4BAA4B,KACpC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"ProxyScaffoldUtils.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/ProxyScaffoldUtils.ts"],"names":[],"mappings":"AAKA,KAAK,4BAA4B,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,2BAA2B,CAAC,OAAO,EAAE,QAAQ,IAAI;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC;IAC3E,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;IAC5C,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,KAAK,0BAA0B,CAAC,OAAO,IAAI;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAIvE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,iBAA2B,KAAG,MAExF,CAAC;AAmBF,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,EAAE,KAAK,MAAM,KAAG,MAAM,GAAG,SAQvE,CAAC;AAmBF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,MAuBhF,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,UAAU,MAAM,EAChB,mBAAmB,MAAM,KACxB,MAaF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,4BAA4B,KACpC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAmB3C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,OAAO,EAAE,QAAQ,EACpD,SAAS,2BAA2B,CAAC,OAAO,EAAE,QAAQ,CAAC,KACtD,0BAA0B,CAAC,OAAO,CAqBpC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
2
|
import { isNonEmptyString } from '../../helper/index.js';
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from '../../node-singletons/fs.js';
|
|
4
|
-
import { join } from '../../node-singletons/path.js';
|
|
4
|
+
import { dirname, join } from '../../node-singletons/path.js';
|
|
5
5
|
export const trimNonEmptyOption = (value) => {
|
|
6
6
|
if (!isNonEmptyString(value))
|
|
7
7
|
return undefined;
|
|
@@ -93,8 +93,7 @@ export const ensureProxyEntrypoint = (options) => {
|
|
|
93
93
|
if (existsSync(entryFilePath)) {
|
|
94
94
|
return { created: false, entryFilePath };
|
|
95
95
|
}
|
|
96
|
-
const
|
|
97
|
-
const entryDir = lastSlashIndex > 0 ? entryFilePath.slice(0, lastSlashIndex) : options.cwd;
|
|
96
|
+
const entryDir = dirname(entryFilePath);
|
|
98
97
|
mkdirSync(entryDir, { recursive: true });
|
|
99
98
|
writeFileSync(entryFilePath, [
|
|
100
99
|
`export { ${options.exportName} } from '${options.moduleSpecifier}';`,
|
|
@@ -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;AAqFvF,eAAO,MAAM,UAAU;cACX,YAAY;EAWtB,CAAC;AAEH,eAAe,UAAU,CAAC"}
|
|
@@ -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
|
*/
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.40
|
|
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-03-
|
|
8
|
+
* Built: 2026-03-31T13:31:43.681Z
|
|
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-03-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-03-31T13:31:43.643Z'; // 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';
|