@geekmidas/cli 0.40.0 → 0.41.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 +26 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +26 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/build/bundler.ts +27 -79
- package/src/docker/index.ts +7 -3
- package/src/docker/templates.ts +16 -0
- package/src/init/templates/api.ts +4 -4
- package/dist/bundler-Db83tLti.mjs.map +0 -1
- package/dist/bundler-DsXfFSCU.cjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"lodash.kebabcase": "^4.1.1",
|
|
49
49
|
"openapi-typescript": "^7.4.2",
|
|
50
50
|
"prompts": "~2.4.2",
|
|
51
|
-
"@geekmidas/errors": "~0.1.0",
|
|
52
51
|
"@geekmidas/logger": "~0.4.0",
|
|
53
|
-
"@geekmidas/envkit": "~0.6.0",
|
|
54
52
|
"@geekmidas/constructs": "~0.7.0",
|
|
55
|
-
"@geekmidas/
|
|
53
|
+
"@geekmidas/errors": "~0.1.0",
|
|
54
|
+
"@geekmidas/schema": "~0.1.0",
|
|
55
|
+
"@geekmidas/envkit": "~0.6.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/lodash.kebabcase": "^4.1.9",
|
package/src/build/bundler.ts
CHANGED
|
@@ -1,50 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { mkdir, rename, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import type { Construct } from '@geekmidas/constructs';
|
|
6
5
|
|
|
7
|
-
const MIN_TSDOWN_VERSION = '0.11.0';
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
|
-
*
|
|
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.
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const result = execSync('npx tsdown --version', {
|
|
15
|
-
encoding: 'utf-8',
|
|
16
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
17
|
-
});
|
|
18
|
-
// Output format: "tsdown/0.12.8 darwin-arm64 node-v22.21.1"
|
|
19
|
-
const match = result.match(/tsdown\/(\d+\.\d+\.\d+)/);
|
|
20
|
-
if (match) {
|
|
21
|
-
const version = match[1]!;
|
|
22
|
-
const [major, minor] = version.split('.').map(Number) as [number, number];
|
|
23
|
-
const [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(
|
|
24
|
-
Number,
|
|
25
|
-
) as [number, number];
|
|
26
|
-
|
|
27
|
-
if (major < minMajor || (major === minMajor && minor < minMinor)) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\n` +
|
|
30
|
-
' npm install -D tsdown@latest\n' +
|
|
31
|
-
' # or\n' +
|
|
32
|
-
' pnpm add -D tsdown@latest',
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (error instanceof Error && error.message.includes('too old')) {
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
throw new Error(
|
|
41
|
-
'tsdown is required for bundling. Please install it:\n' +
|
|
42
|
-
' npm install -D tsdown@latest\n' +
|
|
43
|
-
' # or\n' +
|
|
44
|
-
' pnpm add -D tsdown@latest',
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
11
|
+
const ESM_CJS_COMPAT_BANNER =
|
|
12
|
+
'import { createRequire } from "module"; const require = createRequire(import.meta.url);';
|
|
48
13
|
|
|
49
14
|
export interface BundleOptions {
|
|
50
15
|
/** Entry point file (e.g., .gkm/server/server.ts) */
|
|
@@ -97,11 +62,13 @@ async function collectRequiredEnvVars(
|
|
|
97
62
|
}
|
|
98
63
|
|
|
99
64
|
/**
|
|
100
|
-
* Bundle the server application using
|
|
65
|
+
* Bundle the server application using esbuild.
|
|
66
|
+
* Creates a fully standalone bundle with all dependencies included.
|
|
101
67
|
*
|
|
102
68
|
* @param options - Bundle configuration options
|
|
103
69
|
* @returns Bundle result with output path and optional master key
|
|
104
70
|
*/
|
|
71
|
+
|
|
105
72
|
/** Default env var values for docker compose services */
|
|
106
73
|
const DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {
|
|
107
74
|
postgres: {
|
|
@@ -129,27 +96,23 @@ export async function bundleServer(
|
|
|
129
96
|
dockerServices,
|
|
130
97
|
} = options;
|
|
131
98
|
|
|
132
|
-
// Check tsdown version first
|
|
133
|
-
checkTsdownVersion();
|
|
134
|
-
|
|
135
99
|
// Ensure output directory exists
|
|
136
100
|
await mkdir(outputDir, { recursive: true });
|
|
137
101
|
|
|
138
|
-
|
|
102
|
+
const mjsOutput = join(outputDir, 'server.mjs');
|
|
103
|
+
|
|
104
|
+
// Build command-line arguments for esbuild
|
|
139
105
|
const args = [
|
|
140
106
|
'npx',
|
|
141
|
-
'
|
|
107
|
+
'esbuild',
|
|
142
108
|
entryPoint,
|
|
143
|
-
'--
|
|
144
|
-
'--
|
|
145
|
-
|
|
146
|
-
'--format',
|
|
147
|
-
|
|
148
|
-
'--
|
|
149
|
-
|
|
150
|
-
'--target',
|
|
151
|
-
'node22',
|
|
152
|
-
'--clean',
|
|
109
|
+
'--bundle',
|
|
110
|
+
'--platform=node',
|
|
111
|
+
'--target=node22',
|
|
112
|
+
'--format=esm',
|
|
113
|
+
`--outfile=${mjsOutput}`,
|
|
114
|
+
'--packages=bundle', // Bundle all dependencies for standalone output
|
|
115
|
+
`--banner:js=${ESM_CJS_COMPAT_BANNER}`, // CJS compatibility for packages like pino
|
|
153
116
|
];
|
|
154
117
|
|
|
155
118
|
if (minify) {
|
|
@@ -160,14 +123,11 @@ export async function bundleServer(
|
|
|
160
123
|
args.push('--sourcemap');
|
|
161
124
|
}
|
|
162
125
|
|
|
163
|
-
// Add external packages
|
|
126
|
+
// Add external packages (user-specified)
|
|
164
127
|
for (const ext of external) {
|
|
165
|
-
args.push(
|
|
128
|
+
args.push(`--external:${ext}`);
|
|
166
129
|
}
|
|
167
130
|
|
|
168
|
-
// Always exclude node: builtins
|
|
169
|
-
args.push('--external', 'node:*');
|
|
170
|
-
|
|
171
131
|
// Handle secrets injection if stage is provided
|
|
172
132
|
let masterKey: string | undefined;
|
|
173
133
|
|
|
@@ -252,21 +212,17 @@ export async function bundleServer(
|
|
|
252
212
|
const encrypted = encryptSecrets(embeddable);
|
|
253
213
|
masterKey = encrypted.masterKey;
|
|
254
214
|
|
|
255
|
-
// Add define options for build-time injection using
|
|
215
|
+
// Add define options for build-time injection using esbuild's --define:KEY=VALUE format
|
|
256
216
|
const defines = generateDefineOptions(encrypted);
|
|
257
217
|
for (const [key, value] of Object.entries(defines)) {
|
|
258
|
-
args.push(`--
|
|
218
|
+
args.push(`--define:${key}=${JSON.stringify(value)}`);
|
|
259
219
|
}
|
|
260
220
|
|
|
261
221
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
262
222
|
}
|
|
263
223
|
|
|
264
|
-
const mjsOutput = join(outputDir, 'server.mjs');
|
|
265
|
-
|
|
266
224
|
try {
|
|
267
|
-
// Run
|
|
268
|
-
// Use spawnSync with args array to avoid shell escaping issues with --define values
|
|
269
|
-
// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined
|
|
225
|
+
// Run esbuild with command-line arguments
|
|
270
226
|
const [cmd, ...cmdArgs] = args as [string, ...string[]];
|
|
271
227
|
const result = spawnSync(cmd, cmdArgs, {
|
|
272
228
|
cwd: process.cwd(),
|
|
@@ -278,15 +234,7 @@ export async function bundleServer(
|
|
|
278
234
|
throw result.error;
|
|
279
235
|
}
|
|
280
236
|
if (result.status !== 0) {
|
|
281
|
-
throw new Error(`
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Rename output to .mjs for explicit ESM
|
|
285
|
-
// tsdown outputs as server.js for ESM format
|
|
286
|
-
const jsOutput = join(outputDir, 'server.js');
|
|
287
|
-
|
|
288
|
-
if (existsSync(jsOutput)) {
|
|
289
|
-
await rename(jsOutput, mjsOutput);
|
|
237
|
+
throw new Error(`esbuild exited with code ${result.status}`);
|
|
290
238
|
}
|
|
291
239
|
|
|
292
240
|
// Add shebang to the bundled file
|
package/src/docker/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
-
import { copyFileSync, existsSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import { copyFileSync, existsSync, readFileSync, unlinkSync } from 'node:fs';
|
|
3
3
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { basename, join } from 'node:path';
|
|
5
5
|
import { loadConfig, loadWorkspaceConfig } from '../config';
|
|
@@ -361,8 +361,12 @@ export interface WorkspaceDockerResult {
|
|
|
361
361
|
*/
|
|
362
362
|
function getAppPackageName(appPath: string): string | undefined {
|
|
363
363
|
try {
|
|
364
|
-
|
|
365
|
-
|
|
364
|
+
const pkgPath = join(appPath, 'package.json');
|
|
365
|
+
if (!existsSync(pkgPath)) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
const content = readFileSync(pkgPath, 'utf-8');
|
|
369
|
+
const pkg = JSON.parse(content);
|
|
366
370
|
return pkg.name;
|
|
367
371
|
} catch {
|
|
368
372
|
return undefined;
|
package/src/docker/templates.ts
CHANGED
|
@@ -646,6 +646,13 @@ ${publicUrlEnvDeclarations}
|
|
|
646
646
|
# Copy pruned source
|
|
647
647
|
COPY --from=pruner /app/out/full/ ./
|
|
648
648
|
|
|
649
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
650
|
+
# Using wildcard to make it optional for single-app projects
|
|
651
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
652
|
+
|
|
653
|
+
# Ensure public directory exists (may be empty for scaffolded projects)
|
|
654
|
+
RUN mkdir -p ${appPath}/public
|
|
655
|
+
|
|
649
656
|
# Set Next.js to produce standalone output
|
|
650
657
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
651
658
|
|
|
@@ -752,6 +759,11 @@ ARG GKM_CREDENTIALS_IV=""
|
|
|
752
759
|
# Copy pruned source
|
|
753
760
|
COPY --from=pruner /app/out/full/ ./
|
|
754
761
|
|
|
762
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
763
|
+
# Using wildcard to make it optional for single-app projects
|
|
764
|
+
COPY --from=pruner /app/gkm.config.* ./
|
|
765
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
766
|
+
|
|
755
767
|
# Write encrypted credentials for gkm build to embed
|
|
756
768
|
RUN if [ -n "$GKM_ENCRYPTED_CREDENTIALS" ]; then \
|
|
757
769
|
mkdir -p ${appPath}/.gkm && \
|
|
@@ -873,6 +885,10 @@ ARG GKM_CREDENTIALS_IV=""
|
|
|
873
885
|
# Copy pruned source
|
|
874
886
|
COPY --from=pruner /app/out/full/ ./
|
|
875
887
|
|
|
888
|
+
# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)
|
|
889
|
+
# Using wildcard to make it optional for single-app projects
|
|
890
|
+
COPY --from=pruner /app/tsconfig.* ./
|
|
891
|
+
|
|
876
892
|
# Write encrypted credentials for tsdown to embed via define
|
|
877
893
|
RUN if [ -n "$GKM_ENCRYPTED_CREDENTIALS" ]; then \
|
|
878
894
|
mkdir -p ${appPath}/.gkm && \
|
|
@@ -131,8 +131,8 @@ export const listUsersEndpoint = e
|
|
|
131
131
|
.output(ListUsersResponseSchema)
|
|
132
132
|
.handle(async () => ({
|
|
133
133
|
users: [
|
|
134
|
-
{ id: '
|
|
135
|
-
{ id: '
|
|
134
|
+
{ id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },
|
|
135
|
+
{ id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },
|
|
136
136
|
],
|
|
137
137
|
}));
|
|
138
138
|
`
|
|
@@ -161,12 +161,12 @@ export const listUsersEndpoint = e
|
|
|
161
161
|
path: getRoutePath('users/get.ts'),
|
|
162
162
|
content: modelsImport
|
|
163
163
|
? `import { e } from '@geekmidas/constructs/endpoints';
|
|
164
|
-
import {
|
|
164
|
+
import { IdSchema } from '${modelsImport}/common';
|
|
165
165
|
import { UserResponseSchema } from '${modelsImport}/user';
|
|
166
166
|
|
|
167
167
|
export const getUserEndpoint = e
|
|
168
168
|
.get('/users/:id')
|
|
169
|
-
.params(
|
|
169
|
+
.params({ id: IdSchema })
|
|
170
170
|
.output(UserResponseSchema)
|
|
171
171
|
.handle(async ({ params }) => ({
|
|
172
172
|
id: params.id,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-Db83tLti.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 { execSync, spawnSync } 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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 tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\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// Check tsdown version first\n\tcheckTsdownVersion();\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\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 tsdown's --env.* format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--env.${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\t// Use spawnSync with args array to avoid shell escaping issues with --define values\n\t\t// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined\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(`tsdown exited with code ${result.status}`);\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":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-DsXfFSCU.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 { execSync, spawnSync } 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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 tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\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// Check tsdown version first\n\tcheckTsdownVersion();\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\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 tsdown's --env.* format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--env.${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\t// Use spawnSync with args array to avoid shell escaping issues with --define values\n\t\t// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined\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(`tsdown exited with code ${result.status}`);\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":"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"}
|