@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "0.40.0",
3
+ "version": "0.42.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,10 +48,10 @@
48
48
  "lodash.kebabcase": "^4.1.1",
49
49
  "openapi-typescript": "^7.4.2",
50
50
  "prompts": "~2.4.2",
51
+ "@geekmidas/constructs": "~0.7.0",
51
52
  "@geekmidas/errors": "~0.1.0",
52
53
  "@geekmidas/logger": "~0.4.0",
53
54
  "@geekmidas/envkit": "~0.6.0",
54
- "@geekmidas/constructs": "~0.7.0",
55
55
  "@geekmidas/schema": "~0.1.0"
56
56
  },
57
57
  "devDependencies": {
@@ -1,50 +1,15 @@
1
- import { execSync, spawnSync } from 'node:child_process';
2
- import { existsSync } from 'node:fs';
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
- * Check if tsdown is installed and meets minimum version requirement
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
- function checkTsdownVersion(): void {
13
- try {
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 tsdown
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
- // Build command-line arguments for tsdown
102
+ const mjsOutput = join(outputDir, 'server.mjs');
103
+
104
+ // Build command-line arguments for esbuild
139
105
  const args = [
140
106
  'npx',
141
- 'tsdown',
107
+ 'esbuild',
142
108
  entryPoint,
143
- '--no-config', // Don't use any config file from workspace
144
- '--out-dir',
145
- outputDir,
146
- '--format',
147
- 'esm',
148
- '--platform',
149
- 'node',
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('--external', ext);
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 tsdown's --env.* format
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(`--env.${key}`, value);
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 tsdown with command-line arguments
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(`tsdown exited with code ${result.status}`);
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
@@ -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
- // eslint-disable-next-line @typescript-eslint/no-require-imports
365
- const pkg = require(`${appPath}/package.json`);
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;
@@ -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 && \
@@ -25,9 +25,7 @@ export function generateModelsPackage(
25
25
  scripts: {
26
26
  typecheck: 'tsc --noEmit',
27
27
  },
28
- dependencies: {
29
- zod: '~4.1.0',
30
- },
28
+ dependencies: {},
31
29
  devDependencies: {
32
30
  typescript: '~5.8.2',
33
31
  },
@@ -38,9 +38,13 @@ export function generateMonorepoFiles(
38
38
  ? { deploy: 'gkm deploy --provider dokploy --stage production' }
39
39
  : {}),
40
40
  },
41
+ dependencies: {
42
+ zod: '~4.1.0',
43
+ },
41
44
  devDependencies: {
42
45
  '@biomejs/biome': '~2.3.0',
43
46
  '@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],
47
+ esbuild: '~0.27.0',
44
48
  turbo: '~2.3.0',
45
49
  typescript: '~5.8.2',
46
50
  vitest: '~4.0.0',
@@ -37,22 +37,19 @@ export function generatePackageJson(
37
37
  devDependencies['@types/pg'] = '~8.15.0';
38
38
  }
39
39
 
40
- // Add zod for schema validation (commonly used)
41
- dependencies.zod = '~4.1.0';
42
-
43
- // For monorepo apps, remove biome/turbo (they're at root) and lint/fmt scripts
40
+ // For monorepo apps, remove biome/turbo/esbuild (they're at root) and lint/fmt scripts
41
+ // zod is at root level for monorepos
44
42
  if (monorepo) {
45
43
  delete devDependencies['@biomejs/biome'];
46
44
  delete devDependencies.turbo;
45
+ delete devDependencies.esbuild;
46
+ delete dependencies.zod;
47
47
  delete scripts.lint;
48
48
  delete scripts.fmt;
49
49
  delete scripts['fmt:check'];
50
50
 
51
51
  // Add models package as dependency
52
52
  dependencies[`@${name}/models`] = 'workspace:*';
53
-
54
- // Remove zod from api package (it's in models)
55
- delete dependencies.zod;
56
53
  }
57
54
 
58
55
  // Sort dependencies alphabetically
@@ -23,12 +23,14 @@ export const apiTemplate: TemplateConfig = {
23
23
  '@hono/node-server': '~1.14.1',
24
24
  hono: '~4.8.2',
25
25
  pino: '~9.6.0',
26
+ zod: '~4.1.0',
26
27
  },
27
28
 
28
29
  devDependencies: {
29
30
  '@biomejs/biome': '~2.3.0',
30
31
  '@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],
31
32
  '@types/node': '~22.0.0',
33
+ esbuild: '~0.27.0',
32
34
  tsx: '~4.20.0',
33
35
  turbo: '~2.3.0',
34
36
  typescript: '~5.8.2',
@@ -131,8 +133,8 @@ export const listUsersEndpoint = e
131
133
  .output(ListUsersResponseSchema)
132
134
  .handle(async () => ({
133
135
  users: [
134
- { id: '1', name: 'Alice' },
135
- { id: '2', name: 'Bob' },
136
+ { id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },
137
+ { id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },
136
138
  ],
137
139
  }));
138
140
  `
@@ -161,12 +163,12 @@ export const listUsersEndpoint = e
161
163
  path: getRoutePath('users/get.ts'),
162
164
  content: modelsImport
163
165
  ? `import { e } from '@geekmidas/constructs/endpoints';
164
- import { z } from 'zod';
166
+ import { IdSchema } from '${modelsImport}/common';
165
167
  import { UserResponseSchema } from '${modelsImport}/user';
166
168
 
167
169
  export const getUserEndpoint = e
168
170
  .get('/users/:id')
169
- .params(z.object({ id: z.string() }))
171
+ .params({ id: IdSchema })
170
172
  .output(UserResponseSchema)
171
173
  .handle(async ({ params }) => ({
172
174
  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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"}