@geekmidas/cli 10.0.0-alpha.76 → 10.0.0-alpha.77
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/{add-j2yI3cbS.cjs → add-DCsgtvDk.cjs} +7 -7
- package/dist/{add-j2yI3cbS.cjs.map → add-DCsgtvDk.cjs.map} +1 -1
- package/dist/{add-B7IMXzou.mjs → add-EPQO-_dt.mjs} +2 -2
- package/dist/{add-B7IMXzou.mjs.map → add-EPQO-_dt.mjs.map} +1 -1
- package/dist/{bundler-Cf6OgaOe.cjs → bundler-5spPyduN.cjs} +3 -3
- package/dist/{bundler-Cf6OgaOe.cjs.map → bundler-5spPyduN.cjs.map} +1 -1
- package/dist/{bundler-DO6bHhnb.mjs → bundler-DgO_EMVs.mjs} +3 -3
- package/dist/{bundler-DO6bHhnb.mjs.map → bundler-DgO_EMVs.mjs.map} +1 -1
- package/dist/{cli-BCPOHmg9.mjs → cli-B74Ru-V1.mjs} +3 -3
- package/dist/{cli-BCPOHmg9.mjs.map → cli-B74Ru-V1.mjs.map} +1 -1
- package/dist/{cli-CNanUB7a.cjs → cli-ZpFTMbGw.cjs} +4 -4
- package/dist/{cli-CNanUB7a.cjs.map → cli-ZpFTMbGw.cjs.map} +1 -1
- package/dist/{compose-h_6oNnHC.cjs → compose-CePlrbUw.cjs} +66 -59
- package/dist/{compose-h_6oNnHC.cjs.map → compose-CePlrbUw.cjs.map} +1 -1
- package/dist/{compose-Dq4VCtu5.mjs → compose-IUuxRW0J.mjs} +16 -9
- package/dist/{compose-Dq4VCtu5.mjs.map → compose-IUuxRW0J.mjs.map} +1 -1
- package/dist/{config-CqAvPP-f.d.mts → config-Ckmoj56i.d.mts} +3 -3
- package/dist/{config-CWyhLSY1.d.cts.map → config-Ckmoj56i.d.mts.map} +1 -1
- package/dist/{config-CWyhLSY1.d.cts → config-aAeLXH86.d.cts} +3 -3
- package/dist/{config-CqAvPP-f.d.mts.map → config-aAeLXH86.d.cts.map} +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/deploy/public.cjs +11 -11
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +5 -5
- package/dist/{deploy-CVXEx7Nm.mjs → deploy-Q6X6RXRG.mjs} +3 -3
- package/dist/{deploy-CVXEx7Nm.mjs.map → deploy-Q6X6RXRG.mjs.map} +1 -1
- package/dist/{deploy-CT3R9de9.cjs → deploy-XHXi-_tL.cjs} +9 -9
- package/dist/{deploy-CT3R9de9.cjs.map → deploy-XHXi-_tL.cjs.map} +1 -1
- package/dist/{dokploy-CYm2ozFs.mjs → dokploy-BtP5XSrS.mjs} +2 -2
- package/dist/{dokploy-CYm2ozFs.mjs.map → dokploy-BtP5XSrS.mjs.map} +1 -1
- package/dist/{dokploy-eSGmlhhj.cjs → dokploy-MSsPBO-t.cjs} +2 -2
- package/dist/{dokploy-eSGmlhhj.cjs.map → dokploy-MSsPBO-t.cjs.map} +1 -1
- package/dist/{encryption-DC0rsR1W.mjs → encryption-D4Ykywfr.mjs} +2 -2
- package/dist/{encryption-DC0rsR1W.mjs.map → encryption-D4Ykywfr.mjs.map} +1 -1
- package/dist/{encryption-vS3Qzw73.cjs → encryption-DY0na43R.cjs} +5 -5
- package/dist/{encryption-vS3Qzw73.cjs.map → encryption-DY0na43R.cjs.map} +1 -1
- package/dist/{engine-BOO5TWZd.mjs → engine-BI2xjCKt.mjs} +7 -2
- package/dist/{engine-BOO5TWZd.mjs.map → engine-BI2xjCKt.mjs.map} +1 -1
- package/dist/{engine-C0N2d1i5.cjs → engine-y53kE_3H.cjs} +71 -66
- package/dist/{engine-C0N2d1i5.cjs.map → engine-y53kE_3H.cjs.map} +1 -1
- package/dist/{github-CEaFDL6t.mjs → github-BBIqk1Jv.mjs} +2 -2
- package/dist/{github-CEaFDL6t.mjs.map → github-BBIqk1Jv.mjs.map} +1 -1
- package/dist/{github-ClkdCOL9.cjs → github-Bmb45xUQ.cjs} +6 -6
- package/dist/{github-ClkdCOL9.cjs.map → github-Bmb45xUQ.cjs.map} +1 -1
- package/dist/{index-DOxmDKqv.d.mts → index-C7Tma2m1.d.cts} +2 -2
- package/dist/{index-Ccu0f_2m.d.cts.map → index-C7Tma2m1.d.cts.map} +1 -1
- package/dist/{index-Ccu0f_2m.d.cts → index-CNdSRwar.d.mts} +2 -2
- package/dist/{index-DOxmDKqv.d.mts.map → index-CNdSRwar.d.mts.map} +1 -1
- package/dist/index.cjs +175 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +103 -143
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-BRbYtFXG.cjs → migrate-31JXUOaG.cjs} +4 -4
- package/dist/{migrate-BRbYtFXG.cjs.map → migrate-31JXUOaG.cjs.map} +1 -1
- package/dist/{migrate-DrO2p9Rl.mjs → migrate-BUBsUiM3.mjs} +2 -2
- package/dist/{migrate-DrO2p9Rl.mjs.map → migrate-BUBsUiM3.mjs.map} +1 -1
- package/dist/{migrate-D3NAT7Ns.mjs → migrate-DWVl5PQK.mjs} +2 -2
- package/dist/{migrate-D3NAT7Ns.mjs.map → migrate-DWVl5PQK.mjs.map} +1 -1
- package/dist/{migrate-D5_-ylI1.cjs → migrate-sny0NjKe.cjs} +7 -7
- package/dist/{migrate-D5_-ylI1.cjs.map → migrate-sny0NjKe.cjs.map} +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-C1muFos5.mjs → resolve-BF1ICosS.mjs} +3 -3
- package/dist/{resolve-C1muFos5.mjs.map → resolve-BF1ICosS.mjs.map} +1 -1
- package/dist/{resolve-Fa1Ii0BK.cjs → resolve-DokLtTUb.cjs} +3 -3
- package/dist/{resolve-Fa1Ii0BK.cjs.map → resolve-DokLtTUb.cjs.map} +1 -1
- package/dist/{rollback-C9N5lKVf.cjs → rollback-CpOWRR9H.cjs} +5 -5
- package/dist/{rollback-C9N5lKVf.cjs.map → rollback-CpOWRR9H.cjs.map} +1 -1
- package/dist/{rollback-DeQzbRqM.mjs → rollback-sg0ZhKGG.mjs} +3 -3
- package/dist/{rollback-DeQzbRqM.mjs.map → rollback-sg0ZhKGG.mjs.map} +1 -1
- package/dist/{runtime-BSvzPqXW.d.mts → runtime-B5bYom9w.d.mts} +2 -2
- package/dist/{runtime-BSvzPqXW.d.mts.map → runtime-B5bYom9w.d.mts.map} +1 -1
- package/dist/{runtime-Cm7QA53H.d.cts → runtime-BozOkPtG.d.cts} +2 -2
- package/dist/{runtime-Cm7QA53H.d.cts.map → runtime-BozOkPtG.d.cts.map} +1 -1
- package/dist/{state-CUecOCNJ.mjs → stale-DGzpiN5S.mjs} +103 -23
- package/dist/stale-DGzpiN5S.mjs.map +1 -0
- package/dist/{state-C2qi0iQw.cjs → stale-yu2FkH3G.cjs} +108 -22
- package/dist/stale-yu2FkH3G.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-OxE0OAn2.d.mts → types-B9yWJAis.d.mts} +1 -3
- package/dist/types-B9yWJAis.d.mts.map +1 -0
- package/dist/{types-BdptGBFS.d.cts → types-ct7pdQRf.d.cts} +1 -3
- package/dist/types-ct7pdQRf.d.cts.map +1 -0
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/package.json +15 -15
- package/dist/state-C2qi0iQw.cjs.map +0 -1
- package/dist/state-CUecOCNJ.mjs.map +0 -1
- package/dist/types-BdptGBFS.d.cts.map +0 -1
- package/dist/types-OxE0OAn2.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-DO6bHhnb.mjs","names":[],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, 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/** The bundle's file name in `outputDir`. Defaults to `server.mjs`. */\n\toutfile?: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * The esbuild binary, resolved from this package rather than from PATH.\n *\n * It used to be `npx esbuild`, which is two assumptions: that esbuild is\n * installed somewhere npx can find, and that the *app's* directory is where to\n * look. Neither holds — the CLI did not depend on esbuild at all, so a deploy\n * run from an app that had not installed it failed at the bundle step with\n * `sh: esbuild: command not found`, after provisioning had already happened.\n *\n * The same fix `bin/gkm.mjs` makes for tsx: resolve from this package's own\n * `node_modules`, so the tool the CLI shells out to is the one it depends on.\n */\nfunction esbuildBinary(): string {\n\tconst require = createRequire(import.meta.url);\n\n\ttry {\n\t\t// The package root, then its bin — `require.resolve('esbuild')` gives the\n\t\t// JS entry point, which is a library rather than the CLI.\n\t\tconst pkg = require.resolve('esbuild/package.json');\n\t\treturn join(dirname(pkg), 'bin', 'esbuild');\n\t} catch {\n\t\t// Better a PATH lookup than a hard failure: a project that installed\n\t\t// esbuild itself still works.\n\t\treturn 'esbuild';\n\t}\n}\n\n/**\n * Collect the environment variables a build cannot proceed without.\n *\n * Uses the SnifferEnvironmentParser to detect which env vars each service\n * reads, and keeps only the ones it cannot do without. `markOptional` is what\n * separates them: the sniffer already knows which reads went through\n * `.optional()` or `.default()`, and asking for that distinction is the\n * difference between a build that stops and one that proceeds correctly.\n *\n * Without it, a key that is *absent by design* failed the build. A surface\n * publishes `AUTH_COOKIE_DOMAIN` only when there is a domain to widen a cookie\n * to — one host has nothing to share it with, so the derivation correctly\n * yields nothing, and Better Auth reads it as optional for exactly that\n * reason. Treating every sniffed read as required made the honest answer\n * indistinguishable from a missing secret.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated, sorted names of the required variables\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\t// A key read optionally by one construct and required by another stays\n\t// required: the strictest read is the one that fails at runtime, and taking\n\t// the union of the required reads is what says so.\n\tconst required = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tfor (const name of await construct.getEnvironment({ markOptional: true })) {\n\t\t\tif (!name.endsWith('?')) required.add(name);\n\t\t}\n\t}\n\n\treturn Array.from(required).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\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst mjsOutput = join(outputDir, options.outfile ?? 'server.mjs');\n\n\t// Build command-line arguments for esbuild\n\tconst args = [\n\t\tesbuildBinary(),\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\t// Names kept: an error's class name is what a log line's `err.type` and\n\t\t// a response's `name` say, and minified they read `_6`.\n\t\targs.push('--minify', '--keep-names');\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\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t\tinitStageSecrets,\n\t\t} = await import('../secrets/storage');\n\t\tconst { FileSecretsStore, secretsStoreFor } = await import(\n\t\t\t'../secrets/store'\n\t\t);\n\t\tconst { ConfigNotFound, loadWorkspaceSettings } = await import('../config');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\t// The stage's own store — SSM or Secrets Manager for a deployed stage\n\t\t// kept there. Outside\n\t\t// any workspace nothing names one, so it is the file.\n\t\tconst store = await loadWorkspaceSettings().then(\n\t\t\t(workspace) => secretsStoreFor(workspace, stage),\n\t\t\t(error) => {\n\t\t\t\tif (error instanceof ConfigNotFound) {\n\t\t\t\t\treturn new FileSecretsStore(process.cwd());\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t},\n\t\t);\n\t\tlet secrets = await store.read(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 store.write(stage, secrets);\n\t\t\tconsole.log(` ✓ Created the \"${stage}\" secrets (${store.name})`);\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 the \"${stage}\" secrets 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\t// `value` is already a JS string literal; quoting it again would\n\t\t\t// embed the quotes, and the IV would not parse as hex.\n\t\t\targs.push(`--define:${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t} else {\n\t\t// Credentials encrypted elsewhere — an image build hands them in as a\n\t\t// BuildKit secret and writes them beside the app's `.gkm/server` — are\n\t\t// embedded as they are; whoever encrypted them holds the key.\n\t\tconst gkmDir = join(outputDir, '..', '..');\n\t\tconst encryptedPath = join(gkmDir, 'credentials.enc');\n\t\tconst ivPath = join(gkmDir, 'credentials.iv');\n\t\tif (existsSync(encryptedPath) && existsSync(ivPath)) {\n\t\t\tconst { generateDefineOptions } = await import('../secrets/encryption');\n\t\t\tconst defines = generateDefineOptions({\n\t\t\t\tencrypted: readFileSync(encryptedPath, 'utf-8').trim(),\n\t\t\t\tiv: readFileSync(ivPath, 'utf-8').trim(),\n\t\t\t\tmasterKey: '',\n\t\t\t});\n\t\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\t\targs.push(`--define:${key}=${value}`);\n\t\t\t}\n\t\t\tconsole.log(' Embedded the encrypted credentials the build was given');\n\t\t}\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
|
+
{"version":3,"file":"bundler-DgO_EMVs.mjs","names":[],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, 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/** The bundle's file name in `outputDir`. Defaults to `server.mjs`. */\n\toutfile?: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * The esbuild binary, resolved from this package rather than from PATH.\n *\n * It used to be `npx esbuild`, which is two assumptions: that esbuild is\n * installed somewhere npx can find, and that the *app's* directory is where to\n * look. Neither holds — the CLI did not depend on esbuild at all, so a deploy\n * run from an app that had not installed it failed at the bundle step with\n * `sh: esbuild: command not found`, after provisioning had already happened.\n *\n * The same fix `bin/gkm.mjs` makes for tsx: resolve from this package's own\n * `node_modules`, so the tool the CLI shells out to is the one it depends on.\n */\nfunction esbuildBinary(): string {\n\tconst require = createRequire(import.meta.url);\n\n\ttry {\n\t\t// The package root, then its bin — `require.resolve('esbuild')` gives the\n\t\t// JS entry point, which is a library rather than the CLI.\n\t\tconst pkg = require.resolve('esbuild/package.json');\n\t\treturn join(dirname(pkg), 'bin', 'esbuild');\n\t} catch {\n\t\t// Better a PATH lookup than a hard failure: a project that installed\n\t\t// esbuild itself still works.\n\t\treturn 'esbuild';\n\t}\n}\n\n/**\n * Collect the environment variables a build cannot proceed without.\n *\n * Uses the SnifferEnvironmentParser to detect which env vars each service\n * reads, and keeps only the ones it cannot do without. `markOptional` is what\n * separates them: the sniffer already knows which reads went through\n * `.optional()` or `.default()`, and asking for that distinction is the\n * difference between a build that stops and one that proceeds correctly.\n *\n * Without it, a key that is *absent by design* failed the build. A surface\n * publishes `AUTH_COOKIE_DOMAIN` only when there is a domain to widen a cookie\n * to — one host has nothing to share it with, so the derivation correctly\n * yields nothing, and Better Auth reads it as optional for exactly that\n * reason. Treating every sniffed read as required made the honest answer\n * indistinguishable from a missing secret.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated, sorted names of the required variables\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\t// A key read optionally by one construct and required by another stays\n\t// required: the strictest read is the one that fails at runtime, and taking\n\t// the union of the required reads is what says so.\n\tconst required = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tfor (const name of await construct.getEnvironment({ markOptional: true })) {\n\t\t\tif (!name.endsWith('?')) required.add(name);\n\t\t}\n\t}\n\n\treturn Array.from(required).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\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst mjsOutput = join(outputDir, options.outfile ?? 'server.mjs');\n\n\t// Build command-line arguments for esbuild\n\tconst args = [\n\t\tesbuildBinary(),\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\t// Names kept: an error's class name is what a log line's `err.type` and\n\t\t// a response's `name` say, and minified they read `_6`.\n\t\targs.push('--minify', '--keep-names');\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\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t\tinitStageSecrets,\n\t\t} = await import('../secrets/storage');\n\t\tconst { FileSecretsStore, secretsStoreFor } = await import(\n\t\t\t'../secrets/store'\n\t\t);\n\t\tconst { ConfigNotFound, loadWorkspaceSettings } = await import('../config');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\t// The stage's own store — SSM or Secrets Manager for a deployed stage\n\t\t// kept there. Outside\n\t\t// any workspace nothing names one, so it is the file.\n\t\tconst store = await loadWorkspaceSettings().then(\n\t\t\t(workspace) => secretsStoreFor(workspace, stage),\n\t\t\t(error) => {\n\t\t\t\tif (error instanceof ConfigNotFound) {\n\t\t\t\t\treturn new FileSecretsStore(process.cwd());\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t},\n\t\t);\n\t\tlet secrets = await store.read(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 store.write(stage, secrets);\n\t\t\tconsole.log(` ✓ Created the \"${stage}\" secrets (${store.name})`);\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 the \"${stage}\" secrets 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\t// `value` is already a JS string literal; quoting it again would\n\t\t\t// embed the quotes, and the IV would not parse as hex.\n\t\t\targs.push(`--define:${key}=${value}`);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t} else {\n\t\t// Credentials encrypted elsewhere — an image build hands them in as a\n\t\t// BuildKit secret and writes them beside the app's `.gkm/server` — are\n\t\t// embedded as they are; whoever encrypted them holds the key.\n\t\tconst gkmDir = join(outputDir, '..', '..');\n\t\tconst encryptedPath = join(gkmDir, 'credentials.enc');\n\t\tconst ivPath = join(gkmDir, 'credentials.iv');\n\t\tif (existsSync(encryptedPath) && existsSync(ivPath)) {\n\t\t\tconst { generateDefineOptions } = await import('../secrets/encryption');\n\t\t\tconst defines = generateDefineOptions({\n\t\t\t\tencrypted: readFileSync(encryptedPath, 'utf-8').trim(),\n\t\t\t\tiv: readFileSync(ivPath, 'utf-8').trim(),\n\t\t\t\tmasterKey: '',\n\t\t\t});\n\t\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\t\targs.push(`--define:${key}=${value}`);\n\t\t\t}\n\t\t\tconsole.log(' Embedded the encrypted credentials the build was given');\n\t\t}\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,6 +1,6 @@
|
|
|
1
1
|
import { r as storedCredentials } from "./credentials-pAtB70k3.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as deploy } from "./deploy-
|
|
2
|
+
import { R as parseDevServices } from "./stale-DGzpiN5S.mjs";
|
|
3
|
+
import { t as deploy } from "./deploy-Q6X6RXRG.mjs";
|
|
4
4
|
import { i as formatError } from "./index.mjs";
|
|
5
5
|
import { n as targetForProvider } from "./provider-q4lsYzYG.mjs";
|
|
6
6
|
import { terminalCredentials } from "./terminal-BdvrmkaC.mjs";
|
|
@@ -73,4 +73,4 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
|
|
|
73
73
|
//#endregion
|
|
74
74
|
export { deployCli };
|
|
75
75
|
|
|
76
|
-
//# sourceMappingURL=cli-
|
|
76
|
+
//# sourceMappingURL=cli-B74Ru-V1.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-
|
|
1
|
+
{"version":3,"file":"cli-B74Ru-V1.mjs","names":[],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAAS,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmB,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAM,OAAO;GAClB,GAAG;GACH,aAAa,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAM,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAM,OAAO;EAClB,GAAG;EACH,aAAa,oBAAoB,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_credentials = require("./credentials-BVs7mrtw.cjs");
|
|
2
|
-
const
|
|
3
|
-
const require_deploy = require("./deploy-
|
|
2
|
+
const require_stale = require("./stale-yu2FkH3G.cjs");
|
|
3
|
+
const require_deploy = require("./deploy-XHXi-_tL.cjs");
|
|
4
4
|
const require_index = require("./index.cjs");
|
|
5
5
|
const require_provider = require("./provider-C9_-45d5.cjs");
|
|
6
6
|
const require_terminal = require("./terminal-BL5E0xbR.cjs");
|
|
@@ -27,7 +27,7 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
|
|
|
27
27
|
}
|
|
28
28
|
let allowDevServices;
|
|
29
29
|
try {
|
|
30
|
-
allowDevServices =
|
|
30
|
+
allowDevServices = require_stale.parseDevServices(options.allowDevServices);
|
|
31
31
|
} catch (error) {
|
|
32
32
|
console.error(require_index.formatError(error));
|
|
33
33
|
return 1;
|
|
@@ -73,4 +73,4 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
|
|
|
73
73
|
//#endregion
|
|
74
74
|
exports.deployCli = deployCli;
|
|
75
75
|
|
|
76
|
-
//# sourceMappingURL=cli-
|
|
76
|
+
//# sourceMappingURL=cli-ZpFTMbGw.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-
|
|
1
|
+
{"version":3,"file":"cli-ZpFTMbGw.cjs","names":["targetForProvider","formatError","parseDevServices","deploy","storedCredentials","terminalCredentials"],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAASA,iBAAAA,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAMC,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmBC,cAAAA,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAMD,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAME,eAAAA,OAAO;GAClB,GAAG;GACH,aAAaC,oBAAAA,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAME,eAAAA,OAAO;EAClB,GAAG;EACH,aAAaE,iBAAAA,oBAAoBD,oBAAAA,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
|
|
@@ -4,7 +4,7 @@ const require_discover = require("./discover-D1It5r_h.cjs");
|
|
|
4
4
|
const require_derive = require("./derive-DAbo49sm.cjs");
|
|
5
5
|
const require_workspace = require("./workspace-DOm81oUo.cjs");
|
|
6
6
|
const require_define = require("./define-DzRz8FgH.cjs");
|
|
7
|
-
const
|
|
7
|
+
const require_stale = require("./stale-yu2FkH3G.cjs");
|
|
8
8
|
const require_SubscriberGenerator = require("./SubscriberGenerator-CajwOa5W.cjs");
|
|
9
9
|
const require_drivers = require("./drivers-BdvtCKc7.cjs");
|
|
10
10
|
const require_databases = require("./databases-C2p5LGAp.cjs");
|
|
@@ -496,9 +496,9 @@ function otlpHeaders(email, password) {
|
|
|
496
496
|
/** The stack's OpenObserve for one stage. */
|
|
497
497
|
function stackLogs(options) {
|
|
498
498
|
const { config, stage, local, custom } = options;
|
|
499
|
-
const conflicting = Object.keys(custom).filter(
|
|
499
|
+
const conflicting = Object.keys(custom).filter(require_stale.isOtlpDestination).sort();
|
|
500
500
|
if (conflicting.length > 0) throw new LogsEndpointConflict(stage, conflicting);
|
|
501
|
-
if (!local && !options.domain) throw new
|
|
501
|
+
if (!local && !options.domain) throw new require_stale.NoDomainForStage(stage);
|
|
502
502
|
const email = custom["ZO_ROOT_USER_EMAIL"] ?? (local ? "admin@gkm.localhost" : `admin@${options.domain}`);
|
|
503
503
|
const set = custom[LOGS_PASSWORD_KEY];
|
|
504
504
|
if (!set && !local) throw new LogsPasswordMissing(stage);
|
|
@@ -596,7 +596,7 @@ const REDIS_SERVICE = "redis";
|
|
|
596
596
|
/** The port it answers on, inside the network. */
|
|
597
597
|
const REDIS_PORT = 6379;
|
|
598
598
|
/** Reconcile's pin, so `gkm dev` and the stack run one Redis. */
|
|
599
|
-
const REDIS_IMAGE =
|
|
599
|
+
const REDIS_IMAGE = require_stale.DEFAULT_IMAGES.redis;
|
|
600
600
|
/**
|
|
601
601
|
* How much it may hold before it evicts. A cache that grows until the box
|
|
602
602
|
* runs out of memory takes the apps with it; 256 MB is a lot of sessions and
|
|
@@ -907,7 +907,7 @@ function composeStack(input) {
|
|
|
907
907
|
const custom = input.secrets?.custom ?? {};
|
|
908
908
|
const https = input.ports?.https ?? 443;
|
|
909
909
|
const http = input.ports?.http ?? 80;
|
|
910
|
-
const plan =
|
|
910
|
+
const plan = require_stale.planFor(manifest, stage, (0, _geekmidas_manifest.provisionOrder)(manifest), {
|
|
911
911
|
localStage: workspace.stages.local,
|
|
912
912
|
events: require_SubscriberGenerator.DEFAULT_EVENTS.server,
|
|
913
913
|
cache: STACK_CACHE,
|
|
@@ -917,7 +917,7 @@ function composeStack(input) {
|
|
|
917
917
|
const seed = local ? void 0 : input.secrets?.seed;
|
|
918
918
|
if (!local && !seed) throw new StageSeedMissing(stage);
|
|
919
919
|
const credential = {
|
|
920
|
-
master: local ? "geekmidas" :
|
|
920
|
+
master: local ? "geekmidas" : require_stale.localRolePassword(workspace.name, plan, "master", seed),
|
|
921
921
|
...seed ? { seed } : {}
|
|
922
922
|
};
|
|
923
923
|
const apps = stackApps(workspace, manifest, plan, {
|
|
@@ -927,7 +927,7 @@ function composeStack(input) {
|
|
|
927
927
|
identity,
|
|
928
928
|
images: input.images
|
|
929
929
|
});
|
|
930
|
-
const workers = stackWorkers(
|
|
930
|
+
const workers = stackWorkers(require_stale.workerUnits(workspace, manifest, input.background ?? {}), {
|
|
931
931
|
stage,
|
|
932
932
|
identity,
|
|
933
933
|
images: input.images
|
|
@@ -945,9 +945,9 @@ function composeStack(input) {
|
|
|
945
945
|
const reads = /* @__PURE__ */ new Map();
|
|
946
946
|
for (const app of apps) {
|
|
947
947
|
const site = manifest[app.id];
|
|
948
|
-
reads.set(app.name, site?.kind === "site" ? Object.values((0, _geekmidas_manifest.publicEnvFor)(site, manifest)) : [...
|
|
948
|
+
reads.set(app.name, site?.kind === "site" ? Object.values((0, _geekmidas_manifest.publicEnvFor)(site, manifest)) : [...require_stale.appEnvKeys(manifest, app.name, input.runnables) ?? []]);
|
|
949
949
|
}
|
|
950
|
-
for (const worker of workers) reads.set(worker.name, [...
|
|
950
|
+
for (const worker of workers) reads.set(worker.name, [...require_stale.workerEnvKeys(manifest, worker.id, input.runnables) ?? []]);
|
|
951
951
|
const domain = workspace.deploy?.domains?.[stage];
|
|
952
952
|
const logsConfig = require_workspace.resolveLogs(workspace.deploy?.compose?.logs);
|
|
953
953
|
const logs = logsConfig ? stackLogs({
|
|
@@ -963,7 +963,7 @@ function composeStack(input) {
|
|
|
963
963
|
missing: [],
|
|
964
964
|
minio: plan.resources.filter((r) => r.kind === "objects").map((r) => r.id),
|
|
965
965
|
mailpit: plan.resources.filter((r) => r.kind === "email").map((r) => r.id)
|
|
966
|
-
} :
|
|
966
|
+
} : require_stale.assertExternalServices({
|
|
967
967
|
stage,
|
|
968
968
|
declarations: serviceDeclarations(plan, reads, owners),
|
|
969
969
|
supplied: custom,
|
|
@@ -981,9 +981,9 @@ function composeStack(input) {
|
|
|
981
981
|
const buckets = services.minio.map((id) => byId.get(id)?.name).filter((name) => Boolean(name)).sort();
|
|
982
982
|
return {
|
|
983
983
|
user: custom.AWS_ACCESS_KEY_ID ?? (local ? "geekmidas" : `${workspace.name}-minio`),
|
|
984
|
-
password: custom.AWS_SECRET_ACCESS_KEY ?? (local ? "geekmidas" :
|
|
984
|
+
password: custom.AWS_SECRET_ACCESS_KEY ?? (local ? "geekmidas" : require_stale.localRolePassword(workspace.name, plan, "minio", seed)),
|
|
985
985
|
buckets,
|
|
986
|
-
policies:
|
|
986
|
+
policies: require_stale.bucketPolicies(plan).filter((p) => buckets.includes(p.bucket))
|
|
987
987
|
};
|
|
988
988
|
})() : void 0;
|
|
989
989
|
const derivation = {
|
|
@@ -992,11 +992,11 @@ function composeStack(input) {
|
|
|
992
992
|
...credential.seed ? { seed: credential.seed } : {},
|
|
993
993
|
...!local && domain ? { mailFrom: `noreply@${domain}` } : {}
|
|
994
994
|
};
|
|
995
|
-
const outside =
|
|
995
|
+
const outside = require_stale.networkEnv(plan, {
|
|
996
996
|
...derivation,
|
|
997
997
|
addresses: Object.fromEntries(apps.map((app) => [app.id, app.url]))
|
|
998
998
|
});
|
|
999
|
-
const inside =
|
|
999
|
+
const inside = require_stale.networkEnv(plan, {
|
|
1000
1000
|
...derivation,
|
|
1001
1001
|
addresses: Object.fromEntries(apps.map((app) => [app.id, `http://${app.name}:${app.port}`]))
|
|
1002
1002
|
});
|
|
@@ -1008,9 +1008,9 @@ function composeStack(input) {
|
|
|
1008
1008
|
const bucket = byId.get(resource.of);
|
|
1009
1009
|
if (!bucket) continue;
|
|
1010
1010
|
let host;
|
|
1011
|
-
if (local) host =
|
|
1011
|
+
if (local) host = require_stale.hostFor(resource, workspace.name);
|
|
1012
1012
|
else {
|
|
1013
|
-
if (!domain) throw new
|
|
1013
|
+
if (!domain) throw new require_stale.NoDomainForStage(stage);
|
|
1014
1014
|
host = `${resource.subdomain ?? require_derive.appKey(resource.id)}.${domain}`;
|
|
1015
1015
|
}
|
|
1016
1016
|
fileServers.set(resource.id, {
|
|
@@ -1034,7 +1034,7 @@ function composeStack(input) {
|
|
|
1034
1034
|
if (owner.kind === "file-server") return fileServers.get(owner.id)?.url;
|
|
1035
1035
|
return outside[key];
|
|
1036
1036
|
}
|
|
1037
|
-
if (owner &&
|
|
1037
|
+
if (owner && require_stale.suppliedOnly(owner.kind, owner.id, key, local)) {
|
|
1038
1038
|
const value = custom[key];
|
|
1039
1039
|
if (value === void 0) throw new StageSecretMissing(app.name, key, stage);
|
|
1040
1040
|
return value;
|
|
@@ -1074,7 +1074,7 @@ function composeStack(input) {
|
|
|
1074
1074
|
continue;
|
|
1075
1075
|
}
|
|
1076
1076
|
if (input.buildOnly) continue;
|
|
1077
|
-
const keys =
|
|
1077
|
+
const keys = require_stale.appEnvKeys(manifest, app.name, input.runnables) ?? /* @__PURE__ */ new Set();
|
|
1078
1078
|
const values = valuesFor(app, keys);
|
|
1079
1079
|
const trusted = (0, _geekmidas_manifest.provideKey)(app.id, "trustedOrigins");
|
|
1080
1080
|
if (keys.has(trusted)) {
|
|
@@ -1084,7 +1084,7 @@ function composeStack(input) {
|
|
|
1084
1084
|
}
|
|
1085
1085
|
app.env = {
|
|
1086
1086
|
...values,
|
|
1087
|
-
...
|
|
1087
|
+
...require_stale.otelEnv({
|
|
1088
1088
|
...custom,
|
|
1089
1089
|
...logs?.appEnv
|
|
1090
1090
|
}, app.name),
|
|
@@ -1095,14 +1095,14 @@ function composeStack(input) {
|
|
|
1095
1095
|
for (const [key, value] of Object.entries(app.env)) if (/[\r\n]/.test(value)) throw new EnvValueMultiline(app.name, key);
|
|
1096
1096
|
}
|
|
1097
1097
|
for (const worker of input.buildOnly ? [] : workers) {
|
|
1098
|
-
const keys =
|
|
1098
|
+
const keys = require_stale.workerEnvKeys(manifest, worker.id, input.runnables) ?? /* @__PURE__ */ new Set();
|
|
1099
1099
|
worker.env = {
|
|
1100
1100
|
...valuesFor({
|
|
1101
1101
|
name: worker.name,
|
|
1102
1102
|
id: worker.id,
|
|
1103
1103
|
kind: "rest-api"
|
|
1104
1104
|
}, keys),
|
|
1105
|
-
...
|
|
1105
|
+
...require_stale.otelEnv({
|
|
1106
1106
|
...custom,
|
|
1107
1107
|
...logs?.appEnv
|
|
1108
1108
|
}, worker.name),
|
|
@@ -1145,7 +1145,7 @@ function composeStack(input) {
|
|
|
1145
1145
|
const dockerfiles = {};
|
|
1146
1146
|
for (const app of apps) {
|
|
1147
1147
|
if (!app.build) continue;
|
|
1148
|
-
dockerfiles[app.build.dockerfile] =
|
|
1148
|
+
dockerfiles[app.build.dockerfile] = require_stale.appDockerfile(app.name, workspace.apps[app.name], {
|
|
1149
1149
|
layout,
|
|
1150
1150
|
workspaceRoot: workspace.root,
|
|
1151
1151
|
apps: workspace.apps,
|
|
@@ -1155,7 +1155,7 @@ function composeStack(input) {
|
|
|
1155
1155
|
}
|
|
1156
1156
|
for (const worker of workers) {
|
|
1157
1157
|
if (!worker.build) continue;
|
|
1158
|
-
dockerfiles[worker.build.dockerfile] =
|
|
1158
|
+
dockerfiles[worker.build.dockerfile] = require_stale.workerDockerfile({
|
|
1159
1159
|
id: worker.id,
|
|
1160
1160
|
name: worker.name,
|
|
1161
1161
|
app: worker.host
|
|
@@ -1178,7 +1178,7 @@ function composeStack(input) {
|
|
|
1178
1178
|
plan,
|
|
1179
1179
|
credential,
|
|
1180
1180
|
...storage ? { storage } : {},
|
|
1181
|
-
devServices: local ? [] :
|
|
1181
|
+
devServices: local ? [] : require_stale.devServicesUsed(services),
|
|
1182
1182
|
...logs ? { logs } : {},
|
|
1183
1183
|
...redis ? { redis } : {}
|
|
1184
1184
|
};
|
|
@@ -1239,7 +1239,7 @@ function stackApps(workspace, manifest, plan, options) {
|
|
|
1239
1239
|
if (!app || !resource || !app.port) continue;
|
|
1240
1240
|
const host = hostOf(name, app, workspace, resource, options);
|
|
1241
1241
|
const tag = declaration.kind === "site" ? siteTag(options.images.tag, options.stage) : options.images.tag;
|
|
1242
|
-
const ref =
|
|
1242
|
+
const ref = require_stale.validateImageRef(require_stale.imageRef(options.identity, name, options.images.registry, tag));
|
|
1243
1243
|
apps.push({
|
|
1244
1244
|
app: name,
|
|
1245
1245
|
name,
|
|
@@ -1263,8 +1263,8 @@ function stackWorkers(units, options) {
|
|
|
1263
1263
|
name: unit.name,
|
|
1264
1264
|
id: unit.id,
|
|
1265
1265
|
host: unit.app,
|
|
1266
|
-
port:
|
|
1267
|
-
ref:
|
|
1266
|
+
port: require_stale.WORKER_PORT,
|
|
1267
|
+
ref: require_stale.validateImageRef(require_stale.imageRef(options.identity, unit.name, options.images.registry, options.images.tag)),
|
|
1268
1268
|
tag: options.images.tag,
|
|
1269
1269
|
...options.images.mode === "build" ? { build: { dockerfile: `${stackDir(options.stage)}/Dockerfile.${unit.name}` } } : {}
|
|
1270
1270
|
}));
|
|
@@ -1275,19 +1275,19 @@ function stackWorkers(units, options) {
|
|
|
1275
1275
|
* same rule a deploy follows — for any other.
|
|
1276
1276
|
*/
|
|
1277
1277
|
function hostOf(name, app, workspace, resource, options) {
|
|
1278
|
-
if (options.local) return
|
|
1279
|
-
return
|
|
1278
|
+
if (options.local) return require_stale.hostFor(resource, workspace.name);
|
|
1279
|
+
return require_stale.resolveHost(name, app, options.stage, workspace.deploy?.domains, require_stale.isMainFrontendApp(name, app, workspace.apps));
|
|
1280
1280
|
}
|
|
1281
1281
|
/** The compose document: the infrastructure, the apps, and the edge. */
|
|
1282
1282
|
function stackFile(options) {
|
|
1283
1283
|
const { project, plan, apps } = options;
|
|
1284
1284
|
const infra = options.infra.filter((name) => name !== LOGS_SERVICE);
|
|
1285
|
-
const derived =
|
|
1285
|
+
const derived = require_stale.composeFor({
|
|
1286
1286
|
...plan,
|
|
1287
1287
|
containers: [...infra]
|
|
1288
1288
|
}, {
|
|
1289
1289
|
project,
|
|
1290
|
-
ports: Object.fromEntries(
|
|
1290
|
+
ports: Object.fromEntries(require_stale.portKeys(infra, plan.fakes).map((key) => [key, 0]))
|
|
1291
1291
|
});
|
|
1292
1292
|
const services = {};
|
|
1293
1293
|
const volumes = {
|
|
@@ -1325,7 +1325,7 @@ function stackFile(options) {
|
|
|
1325
1325
|
for (const app of apps) services[app.name] = {
|
|
1326
1326
|
image: app.ref,
|
|
1327
1327
|
...app.build ? { build: {
|
|
1328
|
-
...
|
|
1328
|
+
...require_stale.composeBuildPaths({
|
|
1329
1329
|
composeDir: options.composeDir,
|
|
1330
1330
|
buildRoot: options.buildRoot,
|
|
1331
1331
|
workspaceRoot: options.workspaceRoot,
|
|
@@ -1345,7 +1345,7 @@ function stackFile(options) {
|
|
|
1345
1345
|
};
|
|
1346
1346
|
for (const worker of options.workers) services[worker.name] = {
|
|
1347
1347
|
image: worker.ref,
|
|
1348
|
-
...worker.build ? { build:
|
|
1348
|
+
...worker.build ? { build: require_stale.composeBuildPaths({
|
|
1349
1349
|
composeDir: options.composeDir,
|
|
1350
1350
|
buildRoot: options.buildRoot,
|
|
1351
1351
|
workspaceRoot: options.workspaceRoot,
|
|
@@ -1360,7 +1360,7 @@ function stackFile(options) {
|
|
|
1360
1360
|
healthcheck: probe(worker.port, "/health")
|
|
1361
1361
|
};
|
|
1362
1362
|
services.caddy = {
|
|
1363
|
-
image:
|
|
1363
|
+
image: require_stale.DEFAULT_IMAGES.caddy,
|
|
1364
1364
|
restart: "unless-stopped",
|
|
1365
1365
|
ports: [`${options.https}:443`, `${options.http}:80`],
|
|
1366
1366
|
volumes: [
|
|
@@ -1403,7 +1403,7 @@ function defaultLayout(root) {
|
|
|
1403
1403
|
gkmRoot: ".",
|
|
1404
1404
|
tools: {
|
|
1405
1405
|
packageManager: "pnpm",
|
|
1406
|
-
turboVersion:
|
|
1406
|
+
turboVersion: require_stale.TURBO_VERSION,
|
|
1407
1407
|
monorepo: true
|
|
1408
1408
|
},
|
|
1409
1409
|
gkmPaths: ["gkm.config.*"]
|
|
@@ -1583,8 +1583,8 @@ function edgePorts(env = process.env) {
|
|
|
1583
1583
|
const defaultDeps = {
|
|
1584
1584
|
docker: dockerCompose,
|
|
1585
1585
|
revision: gitRevision,
|
|
1586
|
-
sql:
|
|
1587
|
-
buckets:
|
|
1586
|
+
sql: require_stale.pgClient,
|
|
1587
|
+
buckets: require_stale.bucketClient,
|
|
1588
1588
|
migrate: require_databases.migrateDatabases,
|
|
1589
1589
|
probe: httpsProbe,
|
|
1590
1590
|
healthAttempts: 90,
|
|
@@ -1604,24 +1604,31 @@ async function validateCompose(ctx, deps, options = {}) {
|
|
|
1604
1604
|
if (push && mode !== "build") throw new ComposePushNeedsBuild();
|
|
1605
1605
|
if (options.pin && mode !== "pull") throw new ComposePinNeedsPull();
|
|
1606
1606
|
const registry = workspace.deploy?.registry;
|
|
1607
|
-
if (!registry && (push || mode === "pull")) throw new RegistryRequired(push ? "push" : "pull",
|
|
1607
|
+
if (!registry && (push || mode === "pull")) throw new RegistryRequired(push ? "push" : "pull", require_stale.imageRef(identity, ctx.apps[0] ?? workspace.name, void 0, tag));
|
|
1608
1608
|
const runnables = {};
|
|
1609
1609
|
const background = {};
|
|
1610
1610
|
const manifest = await require_discover.discover({
|
|
1611
|
-
patterns:
|
|
1611
|
+
patterns: require_stale.constructGlobs(workspace),
|
|
1612
1612
|
cwd: root,
|
|
1613
1613
|
runnables,
|
|
1614
1614
|
background
|
|
1615
1615
|
});
|
|
1616
1616
|
const { secrets, generated } = await stageSecrets(ctx, manifest);
|
|
1617
|
-
if (!push)
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1617
|
+
if (!push) {
|
|
1618
|
+
require_stale.assertNoStaleSecrets({
|
|
1619
|
+
manifest,
|
|
1620
|
+
stage,
|
|
1621
|
+
supplied: secrets?.custom ?? {}
|
|
1622
|
+
});
|
|
1623
|
+
await require_credentialSchemas.assertStageCredentials({
|
|
1624
|
+
root,
|
|
1625
|
+
patterns: require_stale.constructGlobs(workspace),
|
|
1626
|
+
manifest,
|
|
1627
|
+
stage,
|
|
1628
|
+
supplied: secrets?.custom ?? {}
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
const layout = mode === "build" ? require_stale.imageLayout(workspace) : void 0;
|
|
1625
1632
|
const composed = composeStack({
|
|
1626
1633
|
workspace,
|
|
1627
1634
|
manifest,
|
|
@@ -1640,7 +1647,7 @@ async function validateCompose(ctx, deps, options = {}) {
|
|
|
1640
1647
|
...layout ? { layout } : {},
|
|
1641
1648
|
...push ? { buildOnly: true } : {}
|
|
1642
1649
|
});
|
|
1643
|
-
|
|
1650
|
+
require_stale.reportDevServices(ctx, composed.devServices);
|
|
1644
1651
|
if (mode === "build") assertRedisClient(workspace, composed);
|
|
1645
1652
|
const stack = options.pin ? withPinnedImages(composed, options.pin.file, options.pin.digests) : composed;
|
|
1646
1653
|
if (mode === "pull" && !ctx.dryRun) await assertImagesExist(deps.docker, tag, [...stack.apps, ...stack.workers]);
|
|
@@ -1717,7 +1724,7 @@ async function stageSecrets(ctx, manifest) {
|
|
|
1717
1724
|
secrets: stored,
|
|
1718
1725
|
generated: []
|
|
1719
1726
|
};
|
|
1720
|
-
const withSeed =
|
|
1727
|
+
const withSeed = require_stale.withGeneratedSecrets(stored ?? require_stale.initStageSecrets(ctx.stage), manifest);
|
|
1721
1728
|
const withLogs = require_workspace.resolveLogs(ctx.workspace.deploy?.compose?.logs) ? withLogsPassword(withSeed.secrets) : {
|
|
1722
1729
|
secrets: withSeed.secrets,
|
|
1723
1730
|
generated: []
|
|
@@ -1855,7 +1862,7 @@ async function prepareBuckets(ctx, run, deps) {
|
|
|
1855
1862
|
if (storage.buckets.length === 0) return;
|
|
1856
1863
|
const port = await deps.docker.port(run.ref, "minio", 9e3);
|
|
1857
1864
|
const client = deps.buckets(port, storage);
|
|
1858
|
-
const created = [...await
|
|
1865
|
+
const created = [...await require_stale.applyBuckets(client, storage.buckets), ...await require_stale.applyPolicies(client, storage.policies)].filter((entry) => entry.created).length;
|
|
1859
1866
|
ctx.logger.info(`🪣 Buckets: ${storage.buckets.join(", ")}${created ? ` (${created} change(s))` : ""}`);
|
|
1860
1867
|
}
|
|
1861
1868
|
/** Create what the plan names in the stack's Postgres, then migrate it. */
|
|
@@ -1863,19 +1870,19 @@ async function prepareDatabases(ctx, run, deps) {
|
|
|
1863
1870
|
const { stack } = run;
|
|
1864
1871
|
const workspace = ctx.workspace;
|
|
1865
1872
|
const port = await deps.docker.port(run.ref, "postgres", 5432);
|
|
1866
|
-
const statements =
|
|
1873
|
+
const statements = require_stale.postgresStatements(stack.plan, workspace.name, stack.credential.seed);
|
|
1867
1874
|
if (statements.length > 0) {
|
|
1868
1875
|
ctx.logger.info("🗄️ Creating databases, roles and grants…");
|
|
1869
|
-
await
|
|
1876
|
+
await require_stale.applyPostgres(deps.sql(port, stack.credential.master), statements);
|
|
1870
1877
|
}
|
|
1871
1878
|
const sources = {};
|
|
1872
1879
|
const manifest = await require_discover.discover({
|
|
1873
|
-
patterns:
|
|
1880
|
+
patterns: require_stale.constructGlobs(workspace),
|
|
1874
1881
|
cwd: workspace.root,
|
|
1875
1882
|
sources
|
|
1876
1883
|
});
|
|
1877
|
-
const env =
|
|
1878
|
-
ports: { [
|
|
1884
|
+
const env = require_stale.envFor(stack.plan, {
|
|
1885
|
+
ports: { [require_stale.primaryPortKey("postgres")]: port },
|
|
1879
1886
|
project: workspace.name,
|
|
1880
1887
|
master: stack.credential.master,
|
|
1881
1888
|
...stack.credential.seed ? { seed: stack.credential.seed } : {}
|
|
@@ -1977,13 +1984,13 @@ async function releaseCompose(ctx, run, deps) {
|
|
|
1977
1984
|
* the tag resolved to.
|
|
1978
1985
|
*/
|
|
1979
1986
|
async function recordImages(ctx, run) {
|
|
1980
|
-
const journal = await
|
|
1987
|
+
const journal = await require_stale.DeployJournal.open(ctx.state, ctx.stage, () => require_stale.createEmptyState(ctx.stage, "", ""));
|
|
1981
1988
|
for (const app of [...run.stack.apps, ...run.stack.workers]) {
|
|
1982
1989
|
const image = run.images[app.app] ?? {
|
|
1983
1990
|
ref: app.ref,
|
|
1984
1991
|
tag: app.tag
|
|
1985
1992
|
};
|
|
1986
|
-
|
|
1993
|
+
require_stale.recordRelease(journal.state, app.app, image);
|
|
1987
1994
|
}
|
|
1988
1995
|
journal.state.identity = ctx.identity.key;
|
|
1989
1996
|
await journal.save();
|
|
@@ -2196,7 +2203,7 @@ async function writeStack(root, dir, stack) {
|
|
|
2196
2203
|
if (stack.redis && stack.compose.services["redis"]?.env_file) await write((0, node_path.join)(dir, `${REDIS_SERVICE}.env`), envFile(stack.redis.env), 384);
|
|
2197
2204
|
for (const entry of await (0, node_fs_promises.readdir)(dir)) if (entry.endsWith(".credentials")) await (0, node_fs_promises.rm)((0, node_path.join)(dir, entry));
|
|
2198
2205
|
for (const [path, content] of Object.entries(stack.dockerfiles)) await write((0, node_path.join)(root, path), content);
|
|
2199
|
-
await
|
|
2206
|
+
await require_stale.ensureDockerignore(require_stale.findBuildRoot(root));
|
|
2200
2207
|
return files;
|
|
2201
2208
|
}
|
|
2202
2209
|
function composeYaml(stack) {
|
|
@@ -2347,4 +2354,4 @@ Object.defineProperty(exports, "stackOverrideFile", {
|
|
|
2347
2354
|
}
|
|
2348
2355
|
});
|
|
2349
2356
|
|
|
2350
|
-
//# sourceMappingURL=compose-
|
|
2357
|
+
//# sourceMappingURL=compose-CePlrbUw.cjs.map
|