@geekmidas/cli 0.40.0 → 0.42.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-DsXfFSCU.cjs → bundler-BB-kETMd.cjs} +19 -48
- package/dist/bundler-BB-kETMd.cjs.map +1 -0
- package/dist/{bundler-Db83tLti.mjs → bundler-DGry2vaR.mjs} +21 -50
- package/dist/bundler-DGry2vaR.mjs.map +1 -0
- package/dist/index.cjs +34 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +34 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/build/bundler.ts +27 -79
- package/src/docker/index.ts +7 -3
- package/src/docker/templates.ts +16 -0
- package/src/init/generators/models.ts +1 -3
- package/src/init/generators/monorepo.ts +4 -0
- package/src/init/generators/package.ts +4 -7
- package/src/init/templates/api.ts +6 -4
- package/dist/bundler-Db83tLti.mjs.map +0 -1
- package/dist/bundler-DsXfFSCU.cjs.map +0 -1
|
@@ -1,38 +1,15 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
3
2
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
4
3
|
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
5
4
|
const node_child_process = require_chunk.__toESM(require("node:child_process"));
|
|
6
5
|
|
|
7
6
|
//#region src/build/bundler.ts
|
|
8
|
-
const MIN_TSDOWN_VERSION = "0.11.0";
|
|
9
7
|
/**
|
|
10
|
-
*
|
|
8
|
+
* Banner to inject into ESM bundle for CJS compatibility.
|
|
9
|
+
* Creates a `require` function using Node's createRequire for packages
|
|
10
|
+
* that internally use CommonJS require() for Node builtins.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
const result = (0, node_child_process.execSync)("npx tsdown --version", {
|
|
15
|
-
encoding: "utf-8",
|
|
16
|
-
stdio: [
|
|
17
|
-
"pipe",
|
|
18
|
-
"pipe",
|
|
19
|
-
"pipe"
|
|
20
|
-
]
|
|
21
|
-
});
|
|
22
|
-
const match = result.match(/tsdown\/(\d+\.\d+\.\d+)/);
|
|
23
|
-
if (match) {
|
|
24
|
-
const version = match[1];
|
|
25
|
-
const [major, minor] = version.split(".").map(Number);
|
|
26
|
-
const [minMajor, minMinor] = MIN_TSDOWN_VERSION.split(".").map(Number);
|
|
27
|
-
if (major < minMajor || major === minMajor && minor < minMinor) throw new Error(`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\n npm install -D tsdown@latest
|
|
28
|
-
# or
|
|
29
|
-
pnpm add -D tsdown@latest`);
|
|
30
|
-
}
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (error instanceof Error && error.message.includes("too old")) throw error;
|
|
33
|
-
throw new Error("tsdown is required for bundling. Please install it:\n npm install -D tsdown@latest\n # or\n pnpm add -D tsdown@latest");
|
|
34
|
-
}
|
|
35
|
-
}
|
|
12
|
+
const ESM_CJS_COMPAT_BANNER = "import { createRequire } from \"module\"; const require = createRequire(import.meta.url);";
|
|
36
13
|
/**
|
|
37
14
|
* Collect all required environment variables from constructs.
|
|
38
15
|
* Uses the SnifferEnvironmentParser to detect which env vars each service needs.
|
|
@@ -49,7 +26,8 @@ async function collectRequiredEnvVars(constructs) {
|
|
|
49
26
|
return Array.from(allEnvVars).sort();
|
|
50
27
|
}
|
|
51
28
|
/**
|
|
52
|
-
* Bundle the server application using
|
|
29
|
+
* Bundle the server application using esbuild.
|
|
30
|
+
* Creates a fully standalone bundle with all dependencies included.
|
|
53
31
|
*
|
|
54
32
|
* @param options - Bundle configuration options
|
|
55
33
|
* @returns Bundle result with output path and optional master key
|
|
@@ -62,27 +40,23 @@ const DOCKER_SERVICE_ENV_VARS = {
|
|
|
62
40
|
};
|
|
63
41
|
async function bundleServer(options) {
|
|
64
42
|
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs, dockerServices } = options;
|
|
65
|
-
checkTsdownVersion();
|
|
66
43
|
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
44
|
+
const mjsOutput = (0, node_path.join)(outputDir, "server.mjs");
|
|
67
45
|
const args = [
|
|
68
46
|
"npx",
|
|
69
|
-
"
|
|
47
|
+
"esbuild",
|
|
70
48
|
entryPoint,
|
|
71
|
-
"--
|
|
72
|
-
"--
|
|
73
|
-
|
|
74
|
-
"--format",
|
|
75
|
-
|
|
76
|
-
"--
|
|
77
|
-
|
|
78
|
-
"--target",
|
|
79
|
-
"node22",
|
|
80
|
-
"--clean"
|
|
49
|
+
"--bundle",
|
|
50
|
+
"--platform=node",
|
|
51
|
+
"--target=node22",
|
|
52
|
+
"--format=esm",
|
|
53
|
+
`--outfile=${mjsOutput}`,
|
|
54
|
+
"--packages=bundle",
|
|
55
|
+
`--banner:js=${ESM_CJS_COMPAT_BANNER}`
|
|
81
56
|
];
|
|
82
57
|
if (minify) args.push("--minify");
|
|
83
58
|
if (sourcemap) args.push("--sourcemap");
|
|
84
|
-
for (const ext of external) args.push(
|
|
85
|
-
args.push("--external", "node:*");
|
|
59
|
+
for (const ext of external) args.push(`--external:${ext}`);
|
|
86
60
|
let masterKey;
|
|
87
61
|
if (stage) {
|
|
88
62
|
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await Promise.resolve().then(() => require("./storage-fOR8dMu5.cjs"));
|
|
@@ -133,10 +107,9 @@ async function bundleServer(options) {
|
|
|
133
107
|
const encrypted = encryptSecrets(embeddable);
|
|
134
108
|
masterKey = encrypted.masterKey;
|
|
135
109
|
const defines = generateDefineOptions(encrypted);
|
|
136
|
-
for (const [key, value] of Object.entries(defines)) args.push(`--
|
|
110
|
+
for (const [key, value] of Object.entries(defines)) args.push(`--define:${key}=${JSON.stringify(value)}`);
|
|
137
111
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
138
112
|
}
|
|
139
|
-
const mjsOutput = (0, node_path.join)(outputDir, "server.mjs");
|
|
140
113
|
try {
|
|
141
114
|
const [cmd, ...cmdArgs] = args;
|
|
142
115
|
const result = (0, node_child_process.spawnSync)(cmd, cmdArgs, {
|
|
@@ -145,9 +118,7 @@ async function bundleServer(options) {
|
|
|
145
118
|
shell: process.platform === "win32"
|
|
146
119
|
});
|
|
147
120
|
if (result.error) throw result.error;
|
|
148
|
-
if (result.status !== 0) throw new Error(`
|
|
149
|
-
const jsOutput = (0, node_path.join)(outputDir, "server.js");
|
|
150
|
-
if ((0, node_fs.existsSync)(jsOutput)) await (0, node_fs_promises.rename)(jsOutput, mjsOutput);
|
|
121
|
+
if (result.status !== 0) throw new Error(`esbuild exited with code ${result.status}`);
|
|
151
122
|
const { readFile } = await import("node:fs/promises");
|
|
152
123
|
const content = await readFile(mjsOutput, "utf-8");
|
|
153
124
|
if (!content.startsWith("#!")) await (0, node_fs_promises.writeFile)(mjsOutput, `#!/usr/bin/env node\n${content}`);
|
|
@@ -162,4 +133,4 @@ async function bundleServer(options) {
|
|
|
162
133
|
|
|
163
134
|
//#endregion
|
|
164
135
|
exports.bundleServer = bundleServer;
|
|
165
|
-
//# sourceMappingURL=bundler-
|
|
136
|
+
//# sourceMappingURL=bundler-BB-kETMd.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-BB-kETMd.cjs","names":["constructs: Construct[]","DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>>","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\n/**\n * Banner to inject into ESM bundle for CJS compatibility.\n * Creates a `require` function using Node's createRequire for packages\n * that internally use CommonJS require() for Node builtins.\n */\nconst ESM_CJS_COMPAT_BANNER =\n\t'import { createRequire } from \"module\"; const require = createRequire(import.meta.url);';\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\t/** Docker compose services configured (for auto-populating env vars) */\n\tdockerServices?: {\n\t\tpostgres?: boolean;\n\t\tredis?: boolean;\n\t\trabbitmq?: boolean;\n\t};\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 esbuild.\n * Creates a fully standalone bundle with all dependencies included.\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\n\n/** Default env var values for docker compose services */\nconst DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {\n\tpostgres: {\n\t\tDATABASE_URL: 'postgresql://postgres:postgres@postgres:5432/app',\n\t},\n\tredis: {\n\t\tREDIS_URL: 'redis://redis:6379',\n\t},\n\trabbitmq: {\n\t\tRABBITMQ_URL: 'amqp://rabbitmq:5672',\n\t},\n};\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\tdockerServices,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\t// Build command-line arguments for esbuild\n\tconst args = [\n\t\t'npx',\n\t\t'esbuild',\n\t\tentryPoint,\n\t\t'--bundle',\n\t\t'--platform=node',\n\t\t'--target=node22',\n\t\t'--format=esm',\n\t\t`--outfile=${mjsOutput}`,\n\t\t'--packages=bundle', // Bundle all dependencies for standalone output\n\t\t`--banner:js=${ESM_CJS_COMPAT_BANNER}`, // CJS compatibility for packages like pino\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 (user-specified)\n\tfor (const ext of external) {\n\t\targs.push(`--external:${ext}`);\n\t}\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\tinitStageSecrets,\n\t\t\twriteStageSecrets,\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\tlet secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\t// Auto-initialize secrets for the stage\n\t\t\tconsole.log(` Initializing secrets for stage \"${stage}\"...`);\n\t\t\tsecrets = initStageSecrets(stage);\n\t\t\tawait writeStageSecrets(secrets);\n\t\t\tconsole.log(` ✓ Created .gkm/secrets/${stage}.json`);\n\t\t}\n\n\t\t// Auto-populate env vars from docker compose services\n\t\tif (dockerServices) {\n\t\t\tfor (const [service, enabled] of Object.entries(dockerServices)) {\n\t\t\t\tif (enabled && DOCKER_SERVICE_ENV_VARS[service]) {\n\t\t\t\t\tfor (const [envVar, defaultValue] of Object.entries(\n\t\t\t\t\t\tDOCKER_SERVICE_ENV_VARS[service],\n\t\t\t\t\t)) {\n\t\t\t\t\t\t// Check if not already in urls or custom\n\t\t\t\t\t\tconst urlKey = envVar as keyof typeof secrets.urls;\n\t\t\t\t\t\tif (!secrets.urls[urlKey] && !secrets.custom[envVar]) {\n\t\t\t\t\t\t\tsecrets.urls[urlKey] = defaultValue;\n\t\t\t\t\t\t\tconsole.log(` Auto-populated ${envVar} from docker compose`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\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 using esbuild's --define:KEY=VALUE format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--define:${key}=${JSON.stringify(value)}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\ttry {\n\t\t// Run esbuild with command-line arguments\n\t\tconst [cmd, ...cmdArgs] = args as [string, ...string[]];\n\t\tconst result = spawnSync(cmd, cmdArgs, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t\tshell: process.platform === 'win32', // Only use shell on Windows for npx resolution\n\t\t});\n\n\t\tif (result.error) {\n\t\t\tthrow result.error;\n\t\t}\n\t\tif (result.status !== 0) {\n\t\t\tthrow new Error(`esbuild exited with code ${result.status}`);\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":"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"}
|
|
@@ -1,37 +1,14 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import { join } from "node:path";
|
|
3
|
-
import { mkdir,
|
|
4
|
-
import {
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
5
4
|
|
|
6
5
|
//#region src/build/bundler.ts
|
|
7
|
-
const MIN_TSDOWN_VERSION = "0.11.0";
|
|
8
6
|
/**
|
|
9
|
-
*
|
|
7
|
+
* Banner to inject into ESM bundle for CJS compatibility.
|
|
8
|
+
* Creates a `require` function using Node's createRequire for packages
|
|
9
|
+
* that internally use CommonJS require() for Node builtins.
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const result = execSync("npx tsdown --version", {
|
|
14
|
-
encoding: "utf-8",
|
|
15
|
-
stdio: [
|
|
16
|
-
"pipe",
|
|
17
|
-
"pipe",
|
|
18
|
-
"pipe"
|
|
19
|
-
]
|
|
20
|
-
});
|
|
21
|
-
const match = result.match(/tsdown\/(\d+\.\d+\.\d+)/);
|
|
22
|
-
if (match) {
|
|
23
|
-
const version = match[1];
|
|
24
|
-
const [major, minor] = version.split(".").map(Number);
|
|
25
|
-
const [minMajor, minMinor] = MIN_TSDOWN_VERSION.split(".").map(Number);
|
|
26
|
-
if (major < minMajor || major === minMajor && minor < minMinor) throw new Error(`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\n npm install -D tsdown@latest
|
|
27
|
-
# or
|
|
28
|
-
pnpm add -D tsdown@latest`);
|
|
29
|
-
}
|
|
30
|
-
} catch (error) {
|
|
31
|
-
if (error instanceof Error && error.message.includes("too old")) throw error;
|
|
32
|
-
throw new Error("tsdown is required for bundling. Please install it:\n npm install -D tsdown@latest\n # or\n pnpm add -D tsdown@latest");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
11
|
+
const ESM_CJS_COMPAT_BANNER = "import { createRequire } from \"module\"; const require = createRequire(import.meta.url);";
|
|
35
12
|
/**
|
|
36
13
|
* Collect all required environment variables from constructs.
|
|
37
14
|
* Uses the SnifferEnvironmentParser to detect which env vars each service needs.
|
|
@@ -48,7 +25,8 @@ async function collectRequiredEnvVars(constructs) {
|
|
|
48
25
|
return Array.from(allEnvVars).sort();
|
|
49
26
|
}
|
|
50
27
|
/**
|
|
51
|
-
* Bundle the server application using
|
|
28
|
+
* Bundle the server application using esbuild.
|
|
29
|
+
* Creates a fully standalone bundle with all dependencies included.
|
|
52
30
|
*
|
|
53
31
|
* @param options - Bundle configuration options
|
|
54
32
|
* @returns Bundle result with output path and optional master key
|
|
@@ -61,27 +39,23 @@ const DOCKER_SERVICE_ENV_VARS = {
|
|
|
61
39
|
};
|
|
62
40
|
async function bundleServer(options) {
|
|
63
41
|
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs, dockerServices } = options;
|
|
64
|
-
checkTsdownVersion();
|
|
65
42
|
await mkdir(outputDir, { recursive: true });
|
|
43
|
+
const mjsOutput = join(outputDir, "server.mjs");
|
|
66
44
|
const args = [
|
|
67
45
|
"npx",
|
|
68
|
-
"
|
|
46
|
+
"esbuild",
|
|
69
47
|
entryPoint,
|
|
70
|
-
"--
|
|
71
|
-
"--
|
|
72
|
-
|
|
73
|
-
"--format",
|
|
74
|
-
|
|
75
|
-
"--
|
|
76
|
-
|
|
77
|
-
"--target",
|
|
78
|
-
"node22",
|
|
79
|
-
"--clean"
|
|
48
|
+
"--bundle",
|
|
49
|
+
"--platform=node",
|
|
50
|
+
"--target=node22",
|
|
51
|
+
"--format=esm",
|
|
52
|
+
`--outfile=${mjsOutput}`,
|
|
53
|
+
"--packages=bundle",
|
|
54
|
+
`--banner:js=${ESM_CJS_COMPAT_BANNER}`
|
|
80
55
|
];
|
|
81
56
|
if (minify) args.push("--minify");
|
|
82
57
|
if (sourcemap) args.push("--sourcemap");
|
|
83
|
-
for (const ext of external) args.push(
|
|
84
|
-
args.push("--external", "node:*");
|
|
58
|
+
for (const ext of external) args.push(`--external:${ext}`);
|
|
85
59
|
let masterKey;
|
|
86
60
|
if (stage) {
|
|
87
61
|
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await import("./storage-DNj_I11J.mjs");
|
|
@@ -132,10 +106,9 @@ async function bundleServer(options) {
|
|
|
132
106
|
const encrypted = encryptSecrets(embeddable);
|
|
133
107
|
masterKey = encrypted.masterKey;
|
|
134
108
|
const defines = generateDefineOptions(encrypted);
|
|
135
|
-
for (const [key, value] of Object.entries(defines)) args.push(`--
|
|
109
|
+
for (const [key, value] of Object.entries(defines)) args.push(`--define:${key}=${JSON.stringify(value)}`);
|
|
136
110
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
137
111
|
}
|
|
138
|
-
const mjsOutput = join(outputDir, "server.mjs");
|
|
139
112
|
try {
|
|
140
113
|
const [cmd, ...cmdArgs] = args;
|
|
141
114
|
const result = spawnSync(cmd, cmdArgs, {
|
|
@@ -144,9 +117,7 @@ async function bundleServer(options) {
|
|
|
144
117
|
shell: process.platform === "win32"
|
|
145
118
|
});
|
|
146
119
|
if (result.error) throw result.error;
|
|
147
|
-
if (result.status !== 0) throw new Error(`
|
|
148
|
-
const jsOutput = join(outputDir, "server.js");
|
|
149
|
-
if (existsSync(jsOutput)) await rename(jsOutput, mjsOutput);
|
|
120
|
+
if (result.status !== 0) throw new Error(`esbuild exited with code ${result.status}`);
|
|
150
121
|
const { readFile: readFile$1 } = await import("node:fs/promises");
|
|
151
122
|
const content = await readFile$1(mjsOutput, "utf-8");
|
|
152
123
|
if (!content.startsWith("#!")) await writeFile(mjsOutput, `#!/usr/bin/env node\n${content}`);
|
|
@@ -161,4 +132,4 @@ async function bundleServer(options) {
|
|
|
161
132
|
|
|
162
133
|
//#endregion
|
|
163
134
|
export { bundleServer };
|
|
164
|
-
//# sourceMappingURL=bundler-
|
|
135
|
+
//# sourceMappingURL=bundler-DGry2vaR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-DGry2vaR.mjs","names":["constructs: Construct[]","DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>>","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\n/**\n * Banner to inject into ESM bundle for CJS compatibility.\n * Creates a `require` function using Node's createRequire for packages\n * that internally use CommonJS require() for Node builtins.\n */\nconst ESM_CJS_COMPAT_BANNER =\n\t'import { createRequire } from \"module\"; const require = createRequire(import.meta.url);';\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\t/** Docker compose services configured (for auto-populating env vars) */\n\tdockerServices?: {\n\t\tpostgres?: boolean;\n\t\tredis?: boolean;\n\t\trabbitmq?: boolean;\n\t};\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 esbuild.\n * Creates a fully standalone bundle with all dependencies included.\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\n\n/** Default env var values for docker compose services */\nconst DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {\n\tpostgres: {\n\t\tDATABASE_URL: 'postgresql://postgres:postgres@postgres:5432/app',\n\t},\n\tredis: {\n\t\tREDIS_URL: 'redis://redis:6379',\n\t},\n\trabbitmq: {\n\t\tRABBITMQ_URL: 'amqp://rabbitmq:5672',\n\t},\n};\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\tdockerServices,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\t// Build command-line arguments for esbuild\n\tconst args = [\n\t\t'npx',\n\t\t'esbuild',\n\t\tentryPoint,\n\t\t'--bundle',\n\t\t'--platform=node',\n\t\t'--target=node22',\n\t\t'--format=esm',\n\t\t`--outfile=${mjsOutput}`,\n\t\t'--packages=bundle', // Bundle all dependencies for standalone output\n\t\t`--banner:js=${ESM_CJS_COMPAT_BANNER}`, // CJS compatibility for packages like pino\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 (user-specified)\n\tfor (const ext of external) {\n\t\targs.push(`--external:${ext}`);\n\t}\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\tinitStageSecrets,\n\t\t\twriteStageSecrets,\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\tlet secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\t// Auto-initialize secrets for the stage\n\t\t\tconsole.log(` Initializing secrets for stage \"${stage}\"...`);\n\t\t\tsecrets = initStageSecrets(stage);\n\t\t\tawait writeStageSecrets(secrets);\n\t\t\tconsole.log(` ✓ Created .gkm/secrets/${stage}.json`);\n\t\t}\n\n\t\t// Auto-populate env vars from docker compose services\n\t\tif (dockerServices) {\n\t\t\tfor (const [service, enabled] of Object.entries(dockerServices)) {\n\t\t\t\tif (enabled && DOCKER_SERVICE_ENV_VARS[service]) {\n\t\t\t\t\tfor (const [envVar, defaultValue] of Object.entries(\n\t\t\t\t\t\tDOCKER_SERVICE_ENV_VARS[service],\n\t\t\t\t\t)) {\n\t\t\t\t\t\t// Check if not already in urls or custom\n\t\t\t\t\t\tconst urlKey = envVar as keyof typeof secrets.urls;\n\t\t\t\t\t\tif (!secrets.urls[urlKey] && !secrets.custom[envVar]) {\n\t\t\t\t\t\t\tsecrets.urls[urlKey] = defaultValue;\n\t\t\t\t\t\t\tconsole.log(` Auto-populated ${envVar} from docker compose`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\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 using esbuild's --define:KEY=VALUE format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--define:${key}=${JSON.stringify(value)}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\ttry {\n\t\t// Run esbuild with command-line arguments\n\t\tconst [cmd, ...cmdArgs] = args as [string, ...string[]];\n\t\tconst result = spawnSync(cmd, cmdArgs, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t\tshell: process.platform === 'win32', // Only use shell on Windows for npx resolution\n\t\t});\n\n\t\tif (result.error) {\n\t\t\tthrow result.error;\n\t\t}\n\t\tif (result.status !== 0) {\n\t\t\tthrow new Error(`esbuild exited with code ${result.status}`);\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":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ const node_module = require_chunk.__toESM(require("node:module"));
|
|
|
29
29
|
|
|
30
30
|
//#region package.json
|
|
31
31
|
var name = "@geekmidas/cli";
|
|
32
|
-
var version = "0.
|
|
32
|
+
var version = "0.41.0";
|
|
33
33
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
34
34
|
var private$1 = false;
|
|
35
35
|
var type = "module";
|
|
@@ -2122,7 +2122,7 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
|
|
|
2122
2122
|
let masterKey;
|
|
2123
2123
|
if (context.production?.bundle && !skipBundle) {
|
|
2124
2124
|
logger$6.log(`\n📦 Bundling production server...`);
|
|
2125
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
2125
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-BB-kETMd.cjs"));
|
|
2126
2126
|
const allConstructs = [
|
|
2127
2127
|
...endpoints.map((e) => e.construct),
|
|
2128
2128
|
...functions.map((f) => f.construct),
|
|
@@ -3079,6 +3079,13 @@ ${publicUrlEnvDeclarations}
|
|
|
3079
3079
|
# Copy pruned source
|
|
3080
3080
|
COPY --from=pruner /app/out/full/ ./
|
|
3081
3081
|
|
|
3082
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
3083
|
+
# Using wildcard to make it optional for single-app projects
|
|
3084
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
3085
|
+
|
|
3086
|
+
# Ensure public directory exists (may be empty for scaffolded projects)
|
|
3087
|
+
RUN mkdir -p ${appPath}/public
|
|
3088
|
+
|
|
3082
3089
|
# Set Next.js to produce standalone output
|
|
3083
3090
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
3084
3091
|
|
|
@@ -3173,6 +3180,11 @@ ARG GKM_CREDENTIALS_IV=""
|
|
|
3173
3180
|
# Copy pruned source
|
|
3174
3181
|
COPY --from=pruner /app/out/full/ ./
|
|
3175
3182
|
|
|
3183
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
3184
|
+
# Using wildcard to make it optional for single-app projects
|
|
3185
|
+
COPY --from=pruner /app/gkm.config.* ./
|
|
3186
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
3187
|
+
|
|
3176
3188
|
# Write encrypted credentials for gkm build to embed
|
|
3177
3189
|
RUN if [ -n "$GKM_ENCRYPTED_CREDENTIALS" ]; then \
|
|
3178
3190
|
mkdir -p ${appPath}/.gkm && \
|
|
@@ -3264,6 +3276,10 @@ ARG GKM_CREDENTIALS_IV=""
|
|
|
3264
3276
|
# Copy pruned source
|
|
3265
3277
|
COPY --from=pruner /app/out/full/ ./
|
|
3266
3278
|
|
|
3279
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
3280
|
+
# Using wildcard to make it optional for single-app projects
|
|
3281
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
3282
|
+
|
|
3267
3283
|
# Write encrypted credentials for tsdown to embed via define
|
|
3268
3284
|
RUN if [ -n "$GKM_ENCRYPTED_CREDENTIALS" ]; then \
|
|
3269
3285
|
mkdir -p ${appPath}/.gkm && \
|
|
@@ -3474,7 +3490,10 @@ async function pushDockerImage(imageName, options) {
|
|
|
3474
3490
|
*/
|
|
3475
3491
|
function getAppPackageName(appPath) {
|
|
3476
3492
|
try {
|
|
3477
|
-
const
|
|
3493
|
+
const pkgPath = (0, node_path.join)(appPath, "package.json");
|
|
3494
|
+
if (!(0, node_fs.existsSync)(pkgPath)) return void 0;
|
|
3495
|
+
const content = (0, node_fs.readFileSync)(pkgPath, "utf-8");
|
|
3496
|
+
const pkg$1 = JSON.parse(content);
|
|
3478
3497
|
return pkg$1.name;
|
|
3479
3498
|
} catch {
|
|
3480
3499
|
return void 0;
|
|
@@ -5819,7 +5838,7 @@ function generateModelsPackage(options) {
|
|
|
5819
5838
|
type: "module",
|
|
5820
5839
|
exports: { "./*": "./src/*.ts" },
|
|
5821
5840
|
scripts: { typecheck: "tsc --noEmit" },
|
|
5822
|
-
dependencies: {
|
|
5841
|
+
dependencies: {},
|
|
5823
5842
|
devDependencies: { typescript: "~5.8.2" }
|
|
5824
5843
|
};
|
|
5825
5844
|
const tsConfig = {
|
|
@@ -5959,9 +5978,11 @@ function generateMonorepoFiles(options, _template) {
|
|
|
5959
5978
|
"fmt:check": "biome format .",
|
|
5960
5979
|
...options.deployTarget === "dokploy" ? { deploy: "gkm deploy --provider dokploy --stage production" } : {}
|
|
5961
5980
|
},
|
|
5981
|
+
dependencies: { zod: "~4.1.0" },
|
|
5962
5982
|
devDependencies: {
|
|
5963
5983
|
"@biomejs/biome": "~2.3.0",
|
|
5964
5984
|
"@geekmidas/cli": GEEKMIDAS_VERSIONS["@geekmidas/cli"],
|
|
5985
|
+
esbuild: "~0.27.0",
|
|
5965
5986
|
turbo: "~2.3.0",
|
|
5966
5987
|
typescript: "~5.8.2",
|
|
5967
5988
|
vitest: "~4.0.0"
|
|
@@ -6284,12 +6305,14 @@ const apiTemplate = {
|
|
|
6284
6305
|
"@geekmidas/auth": GEEKMIDAS_VERSIONS["@geekmidas/auth"],
|
|
6285
6306
|
"@hono/node-server": "~1.14.1",
|
|
6286
6307
|
hono: "~4.8.2",
|
|
6287
|
-
pino: "~9.6.0"
|
|
6308
|
+
pino: "~9.6.0",
|
|
6309
|
+
zod: "~4.1.0"
|
|
6288
6310
|
},
|
|
6289
6311
|
devDependencies: {
|
|
6290
6312
|
"@biomejs/biome": "~2.3.0",
|
|
6291
6313
|
"@geekmidas/cli": GEEKMIDAS_VERSIONS["@geekmidas/cli"],
|
|
6292
6314
|
"@types/node": "~22.0.0",
|
|
6315
|
+
esbuild: "~0.27.0",
|
|
6293
6316
|
tsx: "~4.20.0",
|
|
6294
6317
|
turbo: "~2.3.0",
|
|
6295
6318
|
typescript: "~5.8.2",
|
|
@@ -6372,8 +6395,8 @@ export const listUsersEndpoint = e
|
|
|
6372
6395
|
.output(ListUsersResponseSchema)
|
|
6373
6396
|
.handle(async () => ({
|
|
6374
6397
|
users: [
|
|
6375
|
-
{ id: '
|
|
6376
|
-
{ id: '
|
|
6398
|
+
{ id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },
|
|
6399
|
+
{ id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },
|
|
6377
6400
|
],
|
|
6378
6401
|
}));
|
|
6379
6402
|
` : `import { e } from '@geekmidas/constructs/endpoints';
|
|
@@ -6400,12 +6423,12 @@ export const listUsersEndpoint = e
|
|
|
6400
6423
|
{
|
|
6401
6424
|
path: getRoutePath("users/get.ts"),
|
|
6402
6425
|
content: modelsImport ? `import { e } from '@geekmidas/constructs/endpoints';
|
|
6403
|
-
import {
|
|
6426
|
+
import { IdSchema } from '${modelsImport}/common';
|
|
6404
6427
|
import { UserResponseSchema } from '${modelsImport}/user';
|
|
6405
6428
|
|
|
6406
6429
|
export const getUserEndpoint = e
|
|
6407
6430
|
.get('/users/:id')
|
|
6408
|
-
.params(
|
|
6431
|
+
.params({ id: IdSchema })
|
|
6409
6432
|
.output(UserResponseSchema)
|
|
6410
6433
|
.handle(async ({ params }) => ({
|
|
6411
6434
|
id: params.id,
|
|
@@ -7146,15 +7169,15 @@ function generatePackageJson(options, template) {
|
|
|
7146
7169
|
dependencies$1.pg = "~8.16.0";
|
|
7147
7170
|
devDependencies$1["@types/pg"] = "~8.15.0";
|
|
7148
7171
|
}
|
|
7149
|
-
dependencies$1.zod = "~4.1.0";
|
|
7150
7172
|
if (monorepo) {
|
|
7151
7173
|
delete devDependencies$1["@biomejs/biome"];
|
|
7152
7174
|
delete devDependencies$1.turbo;
|
|
7175
|
+
delete devDependencies$1.esbuild;
|
|
7176
|
+
delete dependencies$1.zod;
|
|
7153
7177
|
delete scripts$1.lint;
|
|
7154
7178
|
delete scripts$1.fmt;
|
|
7155
7179
|
delete scripts$1["fmt:check"];
|
|
7156
7180
|
dependencies$1[`@${name$1}/models`] = "workspace:*";
|
|
7157
|
-
delete dependencies$1.zod;
|
|
7158
7181
|
}
|
|
7159
7182
|
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
|
|
7160
7183
|
let packageName = name$1;
|