@geekmidas/cli 0.12.0 → 0.13.0
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/dist/{bundler-WsEvH_b2.cjs → bundler-B1qy9b-j.cjs} +44 -3
- package/dist/bundler-B1qy9b-j.cjs.map +1 -0
- package/dist/{bundler-DRXCw_YR.mjs → bundler-DskIqW2t.mjs} +44 -3
- package/dist/bundler-DskIqW2t.mjs.map +1 -0
- package/dist/index.cjs +11 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +11 -4
- package/dist/index.mjs.map +1 -1
- package/dist/storage-BOOpAF8N.cjs +5 -0
- package/dist/{storage-BXoJvmv2.cjs → storage-Bj1E26lU.cjs} +39 -1
- package/dist/storage-Bj1E26lU.cjs.map +1 -0
- package/dist/{storage-C9PU_30f.mjs → storage-kSxTjkNb.mjs} +34 -2
- package/dist/storage-kSxTjkNb.mjs.map +1 -0
- package/dist/storage-tgZSUnKl.mjs +3 -0
- package/package.json +2 -2
- package/src/build/__tests__/bundler.spec.ts +444 -0
- package/src/build/bundler.ts +73 -4
- package/src/build/index.ts +10 -0
- package/src/secrets/__tests__/storage.spec.ts +208 -0
- package/src/secrets/storage.ts +58 -0
- package/dist/bundler-DRXCw_YR.mjs.map +0 -1
- package/dist/bundler-WsEvH_b2.cjs.map +0 -1
- package/dist/storage-BUYQJgz7.cjs +0 -4
- package/dist/storage-BXoJvmv2.cjs.map +0 -1
- package/dist/storage-C9PU_30f.mjs.map +0 -1
- package/dist/storage-DLJAYxzJ.mjs +0 -3
|
@@ -6,13 +6,28 @@ const node_child_process = require_chunk.__toESM(require("node:child_process"));
|
|
|
6
6
|
|
|
7
7
|
//#region src/build/bundler.ts
|
|
8
8
|
/**
|
|
9
|
+
* Collect all required environment variables from constructs.
|
|
10
|
+
* Uses the SnifferEnvironmentParser to detect which env vars each service needs.
|
|
11
|
+
*
|
|
12
|
+
* @param constructs - Array of constructs to analyze
|
|
13
|
+
* @returns Deduplicated array of required environment variable names
|
|
14
|
+
*/
|
|
15
|
+
async function collectRequiredEnvVars(constructs) {
|
|
16
|
+
const allEnvVars = /* @__PURE__ */ new Set();
|
|
17
|
+
for (const construct of constructs) {
|
|
18
|
+
const envVars = await construct.getEnvironment();
|
|
19
|
+
envVars.forEach((v) => allEnvVars.add(v));
|
|
20
|
+
}
|
|
21
|
+
return Array.from(allEnvVars).sort();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
9
24
|
* Bundle the server application using tsdown
|
|
10
25
|
*
|
|
11
26
|
* @param options - Bundle configuration options
|
|
12
27
|
* @returns Bundle result with output path and optional master key
|
|
13
28
|
*/
|
|
14
29
|
async function bundleServer(options) {
|
|
15
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage } = options;
|
|
30
|
+
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs } = options;
|
|
16
31
|
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
17
32
|
const args = [
|
|
18
33
|
"npx",
|
|
@@ -35,10 +50,36 @@ async function bundleServer(options) {
|
|
|
35
50
|
args.push("--external", "node:*");
|
|
36
51
|
let masterKey;
|
|
37
52
|
if (stage) {
|
|
38
|
-
const { readStageSecrets, toEmbeddableSecrets } = await Promise.resolve().then(() => require("./storage-
|
|
53
|
+
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables } = await Promise.resolve().then(() => require("./storage-BOOpAF8N.cjs"));
|
|
39
54
|
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-Dyf_r1h-.cjs"));
|
|
40
55
|
const secrets = await readStageSecrets(stage);
|
|
41
56
|
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
57
|
+
if (constructs && constructs.length > 0) {
|
|
58
|
+
console.log(" Analyzing environment variable requirements...");
|
|
59
|
+
const requiredVars = await collectRequiredEnvVars(constructs);
|
|
60
|
+
if (requiredVars.length > 0) {
|
|
61
|
+
const validation = validateEnvironmentVariables(requiredVars, secrets);
|
|
62
|
+
if (!validation.valid) {
|
|
63
|
+
const errorMessage = [
|
|
64
|
+
`Missing environment variables for stage "${stage}":`,
|
|
65
|
+
"",
|
|
66
|
+
...validation.missing.map((v) => ` ❌ ${v}`),
|
|
67
|
+
"",
|
|
68
|
+
"To fix this, either:",
|
|
69
|
+
` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,
|
|
70
|
+
` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,
|
|
71
|
+
"",
|
|
72
|
+
` 2. Or import from a JSON file:`,
|
|
73
|
+
` gkm secrets:import secrets.json --stage ${stage}`,
|
|
74
|
+
"",
|
|
75
|
+
"Required variables:",
|
|
76
|
+
...validation.required.map((v) => validation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`)
|
|
77
|
+
].join("\n");
|
|
78
|
+
throw new Error(errorMessage);
|
|
79
|
+
}
|
|
80
|
+
console.log(` ✓ All ${requiredVars.length} required environment variables found`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
42
83
|
const embeddable = toEmbeddableSecrets(secrets);
|
|
43
84
|
const encrypted = encryptSecrets(embeddable);
|
|
44
85
|
masterKey = encrypted.masterKey;
|
|
@@ -68,4 +109,4 @@ async function bundleServer(options) {
|
|
|
68
109
|
|
|
69
110
|
//#endregion
|
|
70
111
|
exports.bundleServer = bundleServer;
|
|
71
|
-
//# sourceMappingURL=bundler-
|
|
112
|
+
//# sourceMappingURL=bundler-B1qy9b-j.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-B1qy9b-j.cjs","names":["constructs: Construct[]","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Collect all required environment variables from constructs.\n * Uses the SnifferEnvironmentParser to detect which env vars each service needs.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated array of required environment variable names\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\tconst allEnvVars = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tconst envVars = await construct.getEnvironment();\n\t\tenvVars.forEach((v) => allEnvVars.add(v));\n\t}\n\n\treturn Array.from(allEnvVars).sort();\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst {\n\t\t\treadStageSecrets,\n\t\t\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t} = await import('../secrets/storage');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tconst secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\tthrow new Error(\n\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t);\n\t\t}\n\n\t\t// Validate environment variables if constructs are provided\n\t\tif (constructs && constructs.length > 0) {\n\t\t\tconsole.log(' Analyzing environment variable requirements...');\n\t\t\tconst requiredVars = await collectRequiredEnvVars(constructs);\n\n\t\t\tif (requiredVars.length > 0) {\n\t\t\t\tconst validation = validateEnvironmentVariables(requiredVars, secrets);\n\n\t\t\t\tif (!validation.valid) {\n\t\t\t\t\tconst errorMessage = [\n\t\t\t\t\t\t`Missing environment variables for stage \"${stage}\":`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t...validation.missing.map((v) => ` ❌ ${v}`),\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'To fix this, either:',\n\t\t\t\t\t\t` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,\n\t\t\t\t\t\t` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t` 2. Or import from a JSON file:`,\n\t\t\t\t\t\t` gkm secrets:import secrets.json --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'Required variables:',\n\t\t\t\t\t\t...validation.required.map((v) =>\n\t\t\t\t\t\t\tvalidation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t].join('\\n');\n\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ✓ All ${requiredVars.length} required environment variables found`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push('--define', `${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\texecSync(args.join(' '), {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;AAqCA,eAAe,uBACdA,YACoB;CACpB,MAAM,6BAAa,IAAI;AAEvB,MAAK,MAAM,aAAa,YAAY;EACnC,MAAM,UAAU,MAAM,UAAU,gBAAgB;AAChD,UAAQ,QAAQ,CAAC,MAAM,WAAW,IAAI,EAAE,CAAC;CACzC;AAED,QAAO,MAAM,KAAK,WAAW,CAAC,MAAM;AACpC;;;;;;;AAQD,eAAsB,aACrBC,SACwB;CACxB,MAAM,EACL,YACA,WACA,QACA,WACA,UACA,OACA,YACA,GAAG;AAGJ,OAAM,4BAAM,WAAW,EAAE,WAAW,KAAM,EAAC;CAG3C,MAAM,OAAO;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACA;AAED,KAAI,OACH,MAAK,KAAK,WAAW;AAGtB,KAAI,UACH,MAAK,KAAK,cAAc;AAIzB,MAAK,MAAM,OAAO,SACjB,MAAK,KAAK,cAAc,IAAI;AAI7B,MAAK,KAAK,cAAc,SAAS;CAGjC,IAAIC;AAEJ,KAAI,OAAO;EACV,MAAM,EACL,kBACA,qBACA,8BACA,GAAG,2CAAM;EACV,MAAM,EAAE,gBAAgB,uBAAuB,GAAG,2CAAM;EAIxD,MAAM,UAAU,MAAM,iBAAiB,MAAM;AAE7C,OAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;AAKhF,MAAI,cAAc,WAAW,SAAS,GAAG;AACxC,WAAQ,IAAI,mDAAmD;GAC/D,MAAM,eAAe,MAAM,uBAAuB,WAAW;AAE7D,OAAI,aAAa,SAAS,GAAG;IAC5B,MAAM,aAAa,6BAA6B,cAAc,QAAQ;AAEtE,SAAK,WAAW,OAAO;KACtB,MAAM,eAAe;OACnB,2CAA2C,MAAM;MAClD;MACA,GAAG,WAAW,QAAQ,IAAI,CAAC,OAAO,MAAM,EAAE,EAAE;MAC5C;MACA;OACC,iDAAiD,MAAM;OACvD,6CAA6C,MAAM;MACpD;OACC;OACA,+CAA+C,MAAM;MACtD;MACA;MACA,GAAG,WAAW,SAAS,IAAI,CAAC,MAC3B,WAAW,QAAQ,SAAS,EAAE,IAAI,MAAM,EAAE,KAAK,MAAM,EAAE,EACvD;KACD,EAAC,KAAK,KAAK;AAEZ,WAAM,IAAI,MAAM;IAChB;AAED,YAAQ,KACN,UAAU,aAAa,OAAO,uCAC/B;GACD;EACD;EAGD,MAAM,aAAa,oBAAoB,QAAQ;EAC/C,MAAM,YAAY,eAAe,WAAW;AAC5C,cAAY,UAAU;EAGtB,MAAM,UAAU,sBAAsB,UAAU;AAChD,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,CACjD,MAAK,KAAK,aAAa,EAAE,IAAI,GAAG,MAAM,EAAE;AAGzC,UAAQ,KAAK,iCAAiC,MAAM,GAAG;CACvD;CAED,MAAM,YAAY,oBAAK,WAAW,aAAa;AAE/C,KAAI;AAEH,mCAAS,KAAK,KAAK,IAAI,EAAE;GACxB,KAAK,QAAQ,KAAK;GAClB,OAAO;EACP,EAAC;EAIF,MAAM,WAAW,oBAAK,WAAW,YAAY;AAE7C,MAAI,wBAAW,SAAS,CACvB,OAAM,6BAAO,UAAU,UAAU;EAIlC,MAAM,EAAE,UAAU,GAAG,MAAM,OAAO;EAClC,MAAM,UAAU,MAAM,SAAS,WAAW,QAAQ;AAClD,OAAK,QAAQ,WAAW,KAAK,CAC5B,OAAM,gCAAU,YAAY,uBAAuB,QAAQ,EAAE;CAE9D,SAAQ,OAAO;AACf,QAAM,IAAI,OACR,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB;CAEtF;AAED,QAAO;EACN,YAAY;EACZ;CACA;AACD"}
|
|
@@ -5,13 +5,28 @@ import { execSync } from "node:child_process";
|
|
|
5
5
|
|
|
6
6
|
//#region src/build/bundler.ts
|
|
7
7
|
/**
|
|
8
|
+
* Collect all required environment variables from constructs.
|
|
9
|
+
* Uses the SnifferEnvironmentParser to detect which env vars each service needs.
|
|
10
|
+
*
|
|
11
|
+
* @param constructs - Array of constructs to analyze
|
|
12
|
+
* @returns Deduplicated array of required environment variable names
|
|
13
|
+
*/
|
|
14
|
+
async function collectRequiredEnvVars(constructs) {
|
|
15
|
+
const allEnvVars = /* @__PURE__ */ new Set();
|
|
16
|
+
for (const construct of constructs) {
|
|
17
|
+
const envVars = await construct.getEnvironment();
|
|
18
|
+
envVars.forEach((v) => allEnvVars.add(v));
|
|
19
|
+
}
|
|
20
|
+
return Array.from(allEnvVars).sort();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
8
23
|
* Bundle the server application using tsdown
|
|
9
24
|
*
|
|
10
25
|
* @param options - Bundle configuration options
|
|
11
26
|
* @returns Bundle result with output path and optional master key
|
|
12
27
|
*/
|
|
13
28
|
async function bundleServer(options) {
|
|
14
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage } = options;
|
|
29
|
+
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs } = options;
|
|
15
30
|
await mkdir(outputDir, { recursive: true });
|
|
16
31
|
const args = [
|
|
17
32
|
"npx",
|
|
@@ -34,10 +49,36 @@ async function bundleServer(options) {
|
|
|
34
49
|
args.push("--external", "node:*");
|
|
35
50
|
let masterKey;
|
|
36
51
|
if (stage) {
|
|
37
|
-
const { readStageSecrets, toEmbeddableSecrets } = await import("./storage-
|
|
52
|
+
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables } = await import("./storage-tgZSUnKl.mjs");
|
|
38
53
|
const { encryptSecrets, generateDefineOptions } = await import("./encryption-C8H-38Yy.mjs");
|
|
39
54
|
const secrets = await readStageSecrets(stage);
|
|
40
55
|
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
56
|
+
if (constructs && constructs.length > 0) {
|
|
57
|
+
console.log(" Analyzing environment variable requirements...");
|
|
58
|
+
const requiredVars = await collectRequiredEnvVars(constructs);
|
|
59
|
+
if (requiredVars.length > 0) {
|
|
60
|
+
const validation = validateEnvironmentVariables(requiredVars, secrets);
|
|
61
|
+
if (!validation.valid) {
|
|
62
|
+
const errorMessage = [
|
|
63
|
+
`Missing environment variables for stage "${stage}":`,
|
|
64
|
+
"",
|
|
65
|
+
...validation.missing.map((v) => ` ❌ ${v}`),
|
|
66
|
+
"",
|
|
67
|
+
"To fix this, either:",
|
|
68
|
+
` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,
|
|
69
|
+
` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,
|
|
70
|
+
"",
|
|
71
|
+
` 2. Or import from a JSON file:`,
|
|
72
|
+
` gkm secrets:import secrets.json --stage ${stage}`,
|
|
73
|
+
"",
|
|
74
|
+
"Required variables:",
|
|
75
|
+
...validation.required.map((v) => validation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`)
|
|
76
|
+
].join("\n");
|
|
77
|
+
throw new Error(errorMessage);
|
|
78
|
+
}
|
|
79
|
+
console.log(` ✓ All ${requiredVars.length} required environment variables found`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
41
82
|
const embeddable = toEmbeddableSecrets(secrets);
|
|
42
83
|
const encrypted = encryptSecrets(embeddable);
|
|
43
84
|
masterKey = encrypted.masterKey;
|
|
@@ -67,4 +108,4 @@ async function bundleServer(options) {
|
|
|
67
108
|
|
|
68
109
|
//#endregion
|
|
69
110
|
export { bundleServer };
|
|
70
|
-
//# sourceMappingURL=bundler-
|
|
111
|
+
//# sourceMappingURL=bundler-DskIqW2t.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-DskIqW2t.mjs","names":["constructs: Construct[]","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Collect all required environment variables from constructs.\n * Uses the SnifferEnvironmentParser to detect which env vars each service needs.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated array of required environment variable names\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\tconst allEnvVars = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tconst envVars = await construct.getEnvironment();\n\t\tenvVars.forEach((v) => allEnvVars.add(v));\n\t}\n\n\treturn Array.from(allEnvVars).sort();\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst {\n\t\t\treadStageSecrets,\n\t\t\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t} = await import('../secrets/storage');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tconst secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\tthrow new Error(\n\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t);\n\t\t}\n\n\t\t// Validate environment variables if constructs are provided\n\t\tif (constructs && constructs.length > 0) {\n\t\t\tconsole.log(' Analyzing environment variable requirements...');\n\t\t\tconst requiredVars = await collectRequiredEnvVars(constructs);\n\n\t\t\tif (requiredVars.length > 0) {\n\t\t\t\tconst validation = validateEnvironmentVariables(requiredVars, secrets);\n\n\t\t\t\tif (!validation.valid) {\n\t\t\t\t\tconst errorMessage = [\n\t\t\t\t\t\t`Missing environment variables for stage \"${stage}\":`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t...validation.missing.map((v) => ` ❌ ${v}`),\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'To fix this, either:',\n\t\t\t\t\t\t` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,\n\t\t\t\t\t\t` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t` 2. Or import from a JSON file:`,\n\t\t\t\t\t\t` gkm secrets:import secrets.json --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'Required variables:',\n\t\t\t\t\t\t...validation.required.map((v) =>\n\t\t\t\t\t\t\tvalidation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t].join('\\n');\n\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ✓ All ${requiredVars.length} required environment variables found`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push('--define', `${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\texecSync(args.join(' '), {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;AAqCA,eAAe,uBACdA,YACoB;CACpB,MAAM,6BAAa,IAAI;AAEvB,MAAK,MAAM,aAAa,YAAY;EACnC,MAAM,UAAU,MAAM,UAAU,gBAAgB;AAChD,UAAQ,QAAQ,CAAC,MAAM,WAAW,IAAI,EAAE,CAAC;CACzC;AAED,QAAO,MAAM,KAAK,WAAW,CAAC,MAAM;AACpC;;;;;;;AAQD,eAAsB,aACrBC,SACwB;CACxB,MAAM,EACL,YACA,WACA,QACA,WACA,UACA,OACA,YACA,GAAG;AAGJ,OAAM,MAAM,WAAW,EAAE,WAAW,KAAM,EAAC;CAG3C,MAAM,OAAO;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACA;AAED,KAAI,OACH,MAAK,KAAK,WAAW;AAGtB,KAAI,UACH,MAAK,KAAK,cAAc;AAIzB,MAAK,MAAM,OAAO,SACjB,MAAK,KAAK,cAAc,IAAI;AAI7B,MAAK,KAAK,cAAc,SAAS;CAGjC,IAAIC;AAEJ,KAAI,OAAO;EACV,MAAM,EACL,kBACA,qBACA,8BACA,GAAG,MAAM,OAAO;EACjB,MAAM,EAAE,gBAAgB,uBAAuB,GAAG,MAAM,OACvD;EAGD,MAAM,UAAU,MAAM,iBAAiB,MAAM;AAE7C,OAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;AAKhF,MAAI,cAAc,WAAW,SAAS,GAAG;AACxC,WAAQ,IAAI,mDAAmD;GAC/D,MAAM,eAAe,MAAM,uBAAuB,WAAW;AAE7D,OAAI,aAAa,SAAS,GAAG;IAC5B,MAAM,aAAa,6BAA6B,cAAc,QAAQ;AAEtE,SAAK,WAAW,OAAO;KACtB,MAAM,eAAe;OACnB,2CAA2C,MAAM;MAClD;MACA,GAAG,WAAW,QAAQ,IAAI,CAAC,OAAO,MAAM,EAAE,EAAE;MAC5C;MACA;OACC,iDAAiD,MAAM;OACvD,6CAA6C,MAAM;MACpD;OACC;OACA,+CAA+C,MAAM;MACtD;MACA;MACA,GAAG,WAAW,SAAS,IAAI,CAAC,MAC3B,WAAW,QAAQ,SAAS,EAAE,IAAI,MAAM,EAAE,KAAK,MAAM,EAAE,EACvD;KACD,EAAC,KAAK,KAAK;AAEZ,WAAM,IAAI,MAAM;IAChB;AAED,YAAQ,KACN,UAAU,aAAa,OAAO,uCAC/B;GACD;EACD;EAGD,MAAM,aAAa,oBAAoB,QAAQ;EAC/C,MAAM,YAAY,eAAe,WAAW;AAC5C,cAAY,UAAU;EAGtB,MAAM,UAAU,sBAAsB,UAAU;AAChD,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,CACjD,MAAK,KAAK,aAAa,EAAE,IAAI,GAAG,MAAM,EAAE;AAGzC,UAAQ,KAAK,iCAAiC,MAAM,GAAG;CACvD;CAED,MAAM,YAAY,KAAK,WAAW,aAAa;AAE/C,KAAI;AAEH,WAAS,KAAK,KAAK,IAAI,EAAE;GACxB,KAAK,QAAQ,KAAK;GAClB,OAAO;EACP,EAAC;EAIF,MAAM,WAAW,KAAK,WAAW,YAAY;AAE7C,MAAI,WAAW,SAAS,CACvB,OAAM,OAAO,UAAU,UAAU;EAIlC,MAAM,EAAE,sBAAU,GAAG,MAAM,OAAO;EAClC,MAAM,UAAU,MAAM,WAAS,WAAW,QAAQ;AAClD,OAAK,QAAQ,WAAW,KAAK,CAC5B,OAAM,UAAU,YAAY,uBAAuB,QAAQ,EAAE;CAE9D,SAAQ,OAAO;AACf,QAAM,IAAI,OACR,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB;CAEtF;AAED,QAAO;EACN,YAAY;EACZ;CACA;AACD"}
|
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@ const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
|
3
3
|
const require_config = require('./config-AmInkU7k.cjs');
|
|
4
4
|
const require_openapi = require('./openapi-Bt_1FDpT.cjs');
|
|
5
5
|
const require_openapi_react_query = require('./openapi-react-query-B-sNWHFU.cjs');
|
|
6
|
-
const require_storage = require('./storage-
|
|
6
|
+
const require_storage = require('./storage-Bj1E26lU.cjs');
|
|
7
7
|
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
8
8
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
9
9
|
const commander = require_chunk.__toESM(require("commander"));
|
|
@@ -24,7 +24,7 @@ const node_crypto = require_chunk.__toESM(require("node:crypto"));
|
|
|
24
24
|
|
|
25
25
|
//#region package.json
|
|
26
26
|
var name = "@geekmidas/cli";
|
|
27
|
-
var version = "0.
|
|
27
|
+
var version = "0.13.0";
|
|
28
28
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
29
29
|
var private$1 = false;
|
|
30
30
|
var type = "module";
|
|
@@ -1255,14 +1255,21 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
|
|
|
1255
1255
|
let masterKey;
|
|
1256
1256
|
if (context.production?.bundle && !skipBundle) {
|
|
1257
1257
|
logger$6.log(`\n📦 Bundling production server...`);
|
|
1258
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
1258
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-B1qy9b-j.cjs"));
|
|
1259
|
+
const allConstructs = [
|
|
1260
|
+
...endpoints.map((e) => e.construct),
|
|
1261
|
+
...functions.map((f) => f.construct),
|
|
1262
|
+
...crons.map((c) => c.construct),
|
|
1263
|
+
...subscribers.map((s) => s.construct)
|
|
1264
|
+
];
|
|
1259
1265
|
const bundleResult = await bundleServer({
|
|
1260
1266
|
entryPoint: (0, node_path.join)(outputDir, "server.ts"),
|
|
1261
1267
|
outputDir: (0, node_path.join)(outputDir, "dist"),
|
|
1262
1268
|
minify: context.production.minify,
|
|
1263
1269
|
sourcemap: false,
|
|
1264
1270
|
external: context.production.external,
|
|
1265
|
-
stage
|
|
1271
|
+
stage,
|
|
1272
|
+
constructs: allConstructs
|
|
1266
1273
|
});
|
|
1267
1274
|
masterKey = bundleResult.masterKey;
|
|
1268
1275
|
logger$6.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
|