@geekmidas/cli 10.0.0-alpha.66 → 10.0.0-alpha.67

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.
Files changed (114) hide show
  1. package/README.md +110 -178
  2. package/dist/{HostingerProvider-CY_VpVud.mjs → HostingerProvider-D85ayzTi.mjs} +2 -2
  3. package/dist/{HostingerProvider-CY_VpVud.mjs.map → HostingerProvider-D85ayzTi.mjs.map} +1 -1
  4. package/dist/{HostingerProvider-BznqRC2S.cjs → HostingerProvider-dxkwynSs.cjs} +2 -2
  5. package/dist/{HostingerProvider-BznqRC2S.cjs.map → HostingerProvider-dxkwynSs.cjs.map} +1 -1
  6. package/dist/{LegacyStateStore-BFcTT2QL.cjs → LegacyStateStore-BZiO9-Lw.cjs} +2 -2
  7. package/dist/{LegacyStateStore-BFcTT2QL.cjs.map → LegacyStateStore-BZiO9-Lw.cjs.map} +1 -1
  8. package/dist/{LegacyStateStore-CFheFo62.mjs → LegacyStateStore-C39UKwmf.mjs} +2 -2
  9. package/dist/{LegacyStateStore-CFheFo62.mjs.map → LegacyStateStore-C39UKwmf.mjs.map} +1 -1
  10. package/dist/{LocalStateStore-BVUexSvu.cjs → LocalStateStore-DHVsZLyF.cjs} +2 -2
  11. package/dist/{LocalStateStore-BVUexSvu.cjs.map → LocalStateStore-DHVsZLyF.cjs.map} +1 -1
  12. package/dist/{LocalStateStore-Bm3x9oOg.mjs → LocalStateStore-Dk3Wbvzk.mjs} +2 -2
  13. package/dist/{LocalStateStore-Bm3x9oOg.mjs.map → LocalStateStore-Dk3Wbvzk.mjs.map} +1 -1
  14. package/dist/{S3StateStore-CoXBhILd.cjs → S3StateStore--4tYVMAL.cjs} +2 -2
  15. package/dist/{S3StateStore-CoXBhILd.cjs.map → S3StateStore--4tYVMAL.cjs.map} +1 -1
  16. package/dist/{S3StateStore-BFHuctWM.mjs → S3StateStore-B_ZF9eHt.mjs} +2 -2
  17. package/dist/{S3StateStore-BFHuctWM.mjs.map → S3StateStore-B_ZF9eHt.mjs.map} +1 -1
  18. package/dist/{SSMStateStore-BqCA9TP2.cjs → SSMStateStore-ACZ8hRvZ.cjs} +2 -2
  19. package/dist/{SSMStateStore-BqCA9TP2.cjs.map → SSMStateStore-ACZ8hRvZ.cjs.map} +1 -1
  20. package/dist/{SSMStateStore-C1kvHScY.mjs → SSMStateStore-DjPuKqrm.mjs} +2 -2
  21. package/dist/{SSMStateStore-C1kvHScY.mjs.map → SSMStateStore-DjPuKqrm.mjs.map} +1 -1
  22. package/dist/{bundler-Dvaiud0h.mjs → bundler-Bq3HaLOZ.mjs} +20 -5
  23. package/dist/bundler-Bq3HaLOZ.mjs.map +1 -0
  24. package/dist/{bundler-orRqUJNZ.cjs → bundler-pyLj-gS0.cjs} +20 -5
  25. package/dist/bundler-pyLj-gS0.cjs.map +1 -0
  26. package/dist/{cli-CfHm0AO7.mjs → cli-C2Tjbn27.mjs} +4 -4
  27. package/dist/{cli-CfHm0AO7.mjs.map → cli-C2Tjbn27.mjs.map} +1 -1
  28. package/dist/{cli-D1JkkOwg.cjs → cli-DR7B2_fX.cjs} +4 -4
  29. package/dist/{cli-D1JkkOwg.cjs.map → cli-DR7B2_fX.cjs.map} +1 -1
  30. package/dist/{compose-jrLy7KGO.cjs → compose-5oNHAKNT.cjs} +135 -110
  31. package/dist/compose-5oNHAKNT.cjs.map +1 -0
  32. package/dist/{compose-CNQL8BnO.mjs → compose-BjToENzG.mjs} +128 -103
  33. package/dist/compose-BjToENzG.mjs.map +1 -0
  34. package/dist/{credentials-Bzbg23n8.cjs → credentials-BVs7mrtw.cjs} +239 -3
  35. package/dist/credentials-BVs7mrtw.cjs.map +1 -0
  36. package/dist/{credentials-Dq1MnWQf.mjs → credentials-pAtB70k3.mjs} +223 -5
  37. package/dist/credentials-pAtB70k3.mjs.map +1 -0
  38. package/dist/deploy/public.cjs +17 -17
  39. package/dist/deploy/public.cjs.map +1 -1
  40. package/dist/deploy/public.mjs +9 -9
  41. package/dist/{deploy-B7aJi_Ah.cjs → deploy-BucRfbvX.cjs} +9 -9
  42. package/dist/{deploy-B7aJi_Ah.cjs.map → deploy-BucRfbvX.cjs.map} +1 -1
  43. package/dist/{deploy-DWn7YfIc.mjs → deploy-DRAwTG72.mjs} +6 -6
  44. package/dist/{deploy-DWn7YfIc.mjs.map → deploy-DRAwTG72.mjs.map} +1 -1
  45. package/dist/{dokploy-DalwLML5.mjs → dokploy-DIt1IZl1.mjs} +2 -2
  46. package/dist/{dokploy-DalwLML5.mjs.map → dokploy-DIt1IZl1.mjs.map} +1 -1
  47. package/dist/{dokploy-B4LcYG1E.cjs → dokploy-m345Zx02.cjs} +2 -2
  48. package/dist/{dokploy-B4LcYG1E.cjs.map → dokploy-m345Zx02.cjs.map} +1 -1
  49. package/dist/{encryption-CPfENwWO.mjs → encryption-Ccbahik7.mjs} +2 -2
  50. package/dist/{encryption-CPfENwWO.mjs.map → encryption-Ccbahik7.mjs.map} +1 -1
  51. package/dist/{encryption-3KlGS1sl.cjs → encryption-rZ3BghXy.cjs} +2 -2
  52. package/dist/{encryption-3KlGS1sl.cjs.map → encryption-rZ3BghXy.cjs.map} +1 -1
  53. package/dist/{engine-DR6KurWX.cjs → engine-Cx_dvx9q.cjs} +9 -187
  54. package/dist/engine-Cx_dvx9q.cjs.map +1 -0
  55. package/dist/{engine-CunvOG3s.mjs → engine-Gs0abjuj.mjs} +5 -183
  56. package/dist/engine-Gs0abjuj.mjs.map +1 -0
  57. package/dist/{github-MXA9v7Ge.mjs → github-CJANTYqi.mjs} +2 -2
  58. package/dist/{github-MXA9v7Ge.mjs.map → github-CJANTYqi.mjs.map} +1 -1
  59. package/dist/{github-BJ5gh9bw.cjs → github-CrcGFkfD.cjs} +2 -2
  60. package/dist/{github-BJ5gh9bw.cjs.map → github-CrcGFkfD.cjs.map} +1 -1
  61. package/dist/index.cjs +51 -65
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.mjs +47 -61
  64. package/dist/index.mjs.map +1 -1
  65. package/dist/{migrate-CF4J4GQS.cjs → migrate-CQdSpttI.cjs} +2 -2
  66. package/dist/{migrate-CF4J4GQS.cjs.map → migrate-CQdSpttI.cjs.map} +1 -1
  67. package/dist/{migrate-BJBcm4sG.mjs → migrate-DCVo5gLS.mjs} +2 -2
  68. package/dist/{migrate-BJBcm4sG.mjs.map → migrate-DCVo5gLS.mjs.map} +1 -1
  69. package/dist/{resolve-CVmch0wI.cjs → resolve-BexmDcsN.cjs} +4 -4
  70. package/dist/{resolve-CVmch0wI.cjs.map → resolve-BexmDcsN.cjs.map} +1 -1
  71. package/dist/{resolve-Db0tNlrW.mjs → resolve-DhZgtvZe.mjs} +4 -4
  72. package/dist/{resolve-Db0tNlrW.mjs.map → resolve-DhZgtvZe.mjs.map} +1 -1
  73. package/dist/{rollback-DxJK84hy.cjs → rollback-BnY7KuG_.cjs} +6 -7
  74. package/dist/{rollback-DxJK84hy.cjs.map → rollback-BnY7KuG_.cjs.map} +1 -1
  75. package/dist/{rollback-DvAo4OKS.mjs → rollback-m4Yeym5x.mjs} +5 -6
  76. package/dist/{rollback-DvAo4OKS.mjs.map → rollback-m4Yeym5x.mjs.map} +1 -1
  77. package/dist/run-BJLIerMM.mjs +133 -0
  78. package/dist/run-BJLIerMM.mjs.map +1 -0
  79. package/dist/run-fVZ-rLnc.cjs +174 -0
  80. package/dist/run-fVZ-rLnc.cjs.map +1 -0
  81. package/dist/{sniffer-BAQhLEsI.mjs → sniffer-BdFeLSmA.mjs} +8 -60
  82. package/dist/sniffer-BdFeLSmA.mjs.map +1 -0
  83. package/dist/{sniffer-5xmrkh2a.cjs → sniffer-D66HIvi9.cjs} +7 -77
  84. package/dist/{sniffer-5xmrkh2a.cjs.map → sniffer-D66HIvi9.cjs.map} +1 -1
  85. package/dist/{sst-B2HbrDR3.mjs → sst-DRi3H5TB.mjs} +3 -3
  86. package/dist/{sst-B2HbrDR3.mjs.map → sst-DRi3H5TB.mjs.map} +1 -1
  87. package/dist/{sst-DcfsVH6x.cjs → sst-hBrKouBy.cjs} +5 -5
  88. package/dist/{sst-DcfsVH6x.cjs.map → sst-hBrKouBy.cjs.map} +1 -1
  89. package/dist/{state-Y6ATakMX.cjs → state-DgmM4EKq.cjs} +3588 -3415
  90. package/dist/state-DgmM4EKq.cjs.map +1 -0
  91. package/dist/{state-uuYqnRVO.mjs → state-DkUStoqJ.mjs} +3528 -3385
  92. package/dist/state-DkUStoqJ.mjs.map +1 -0
  93. package/dist/target/public.cjs +1 -1
  94. package/dist/target/public.mjs +1 -1
  95. package/dist/{terminal-DUhcZ1ND.mjs → terminal-C3cv-OQu.mjs} +2 -2
  96. package/dist/{terminal-DUhcZ1ND.mjs.map → terminal-C3cv-OQu.mjs.map} +1 -1
  97. package/dist/{terminal-CHy_MdjG.cjs → terminal-DjzgLu6m.cjs} +2 -2
  98. package/dist/{terminal-CHy_MdjG.cjs.map → terminal-DjzgLu6m.cjs.map} +1 -1
  99. package/package.json +13 -13
  100. package/dist/bundler-Dvaiud0h.mjs.map +0 -1
  101. package/dist/bundler-orRqUJNZ.cjs.map +0 -1
  102. package/dist/compose-CNQL8BnO.mjs.map +0 -1
  103. package/dist/compose-jrLy7KGO.cjs.map +0 -1
  104. package/dist/credentials-Bzbg23n8.cjs.map +0 -1
  105. package/dist/credentials-Dq1MnWQf.mjs.map +0 -1
  106. package/dist/engine-CunvOG3s.mjs.map +0 -1
  107. package/dist/engine-DR6KurWX.cjs.map +0 -1
  108. package/dist/local-BdH4XN0E.cjs +0 -409
  109. package/dist/local-BdH4XN0E.cjs.map +0 -1
  110. package/dist/local-CWR4Y_kW.mjs +0 -350
  111. package/dist/local-CWR4Y_kW.mjs.map +0 -1
  112. package/dist/sniffer-BAQhLEsI.mjs.map +0 -1
  113. package/dist/state-Y6ATakMX.cjs.map +0 -1
  114. package/dist/state-uuYqnRVO.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundler-pyLj-gS0.cjs","names":["require","createRequire","join","dirname","mkdir","existsSync","readFileSync","spawnSync","writeFile"],"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/** 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, '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\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages (user-specified)\n\tfor (const ext of external) {\n\t\targs.push(`--external:${ext}`);\n\t}\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst {\n\t\t\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 for a deployed stage 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,8 +1,8 @@
1
- import { r as storedCredentials } from "./credentials-Dq1MnWQf.mjs";
2
- import { t as deploy } from "./deploy-DWn7YfIc.mjs";
1
+ import { r as storedCredentials } from "./credentials-pAtB70k3.mjs";
2
+ import { t as deploy } from "./deploy-DRAwTG72.mjs";
3
3
  import { i as formatError } from "./index.mjs";
4
4
  import { n as targetForProvider } from "./provider-q4lsYzYG.mjs";
5
- import { terminalCredentials } from "./terminal-DUhcZ1ND.mjs";
5
+ import { terminalCredentials } from "./terminal-C3cv-OQu.mjs";
6
6
  //#region src/deploy/cli.ts
7
7
  /**
8
8
  * `gkm deploy`: the terminal around `deploy()`. CLI layer only.
@@ -64,4 +64,4 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
64
64
  //#endregion
65
65
  export { deployCli };
66
66
 
67
- //# sourceMappingURL=cli-CfHm0AO7.mjs.map
67
+ //# sourceMappingURL=cli-C2Tjbn27.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-CfHm0AO7.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 { 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}\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\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};\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":";;;;;;;;;;;;;;;;;;AA4CA,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,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;CAC1C;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
+ {"version":3,"file":"cli-C2Tjbn27.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 { 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}\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\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};\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":";;;;;;;;;;;;;;;;;;AA4CA,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,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;CAC1C;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,8 +1,8 @@
1
- const require_credentials = require("./credentials-Bzbg23n8.cjs");
2
- const require_deploy = require("./deploy-B7aJi_Ah.cjs");
1
+ const require_credentials = require("./credentials-BVs7mrtw.cjs");
2
+ const require_deploy = require("./deploy-BucRfbvX.cjs");
3
3
  const require_index = require("./index.cjs");
4
4
  const require_provider = require("./provider-C9_-45d5.cjs");
5
- const require_terminal = require("./terminal-CHy_MdjG.cjs");
5
+ const require_terminal = require("./terminal-DjzgLu6m.cjs");
6
6
  //#region src/deploy/cli.ts
7
7
  /**
8
8
  * `gkm deploy`: the terminal around `deploy()`. CLI layer only.
@@ -64,4 +64,4 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
64
64
  //#endregion
65
65
  exports.deployCli = deployCli;
66
66
 
67
- //# sourceMappingURL=cli-D1JkkOwg.cjs.map
67
+ //# sourceMappingURL=cli-DR7B2_fX.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-D1JkkOwg.cjs","names":["targetForProvider","formatError","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 { 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}\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\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};\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":";;;;;;;;;;;;;;;;;;AA4CA,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,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;CAC1C;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAMC,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,MAAMF,cAAAA,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAMC,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,MAAMF,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
1
+ {"version":3,"file":"cli-DR7B2_fX.cjs","names":["targetForProvider","formatError","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 { 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}\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\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};\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":";;;;;;;;;;;;;;;;;;AA4CA,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,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;CAC1C;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAMC,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,MAAMF,cAAAA,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAMC,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,MAAMF,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
@@ -1,17 +1,14 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
- const require_local = require("./local-BdH4XN0E.cjs");
2
+ const require_run = require("./run-fVZ-rLnc.cjs");
3
3
  const require_discover = require("./discover-OEfZ9OkA.cjs");
4
- const require_sandbox = require("./sandbox-CL--ZDui.cjs");
5
4
  const require_derive = require("./derive-DAbo49sm.cjs");
6
5
  const require_define = require("./define-DzRz8FgH.cjs");
7
- const require_state = require("./state-Y6ATakMX.cjs");
6
+ const require_state = require("./state-DgmM4EKq.cjs");
8
7
  const require_fakes = require("./fakes-zW-jNAbQ.cjs");
9
8
  const require_databases = require("./databases-C2p5LGAp.cjs");
10
9
  let node_path = require("node:path");
11
- let node_fs = require("node:fs");
12
10
  let node_fs_promises = require("node:fs/promises");
13
11
  let _geekmidas_manifest = require("@geekmidas/manifest");
14
- let node_url = require("node:url");
15
12
  let node_child_process = require("node:child_process");
16
13
  let yaml = require("yaml");
17
14
  let node_https = require("node:https");
@@ -140,16 +137,16 @@ const dockerCompose = {
140
137
  };
141
138
  },
142
139
  async build(stack, services) {
143
- await require_local.run("docker", compose(stack, ["build", ...services]), runOptions(stack, {
140
+ await require_run.run("docker", compose(stack, ["build", ...services]), runOptions(stack, {
144
141
  ...process.env,
145
142
  DOCKER_BUILDKIT: "1"
146
143
  }));
147
144
  },
148
145
  async pull(stack, services) {
149
- await require_local.run("docker", compose(stack, ["pull", ...services]), runOptions(stack));
146
+ await require_run.run("docker", compose(stack, ["pull", ...services]), runOptions(stack));
150
147
  },
151
148
  async up(stack, services) {
152
- await require_local.run("docker", compose(stack, [
149
+ await require_run.run("docker", compose(stack, [
153
150
  "up",
154
151
  "-d",
155
152
  "--wait",
@@ -159,10 +156,10 @@ const dockerCompose = {
159
156
  ]), runOptions(stack));
160
157
  },
161
158
  async down(stack) {
162
- await require_local.run("docker", compose(stack, ["down"]), runOptions(stack));
159
+ await require_run.run("docker", compose(stack, ["down"]), runOptions(stack));
163
160
  },
164
161
  async port(stack, service, inside) {
165
- const output = await require_local.runOutput("docker", compose(stack, [
162
+ const output = await require_run.runOutput("docker", compose(stack, [
166
163
  "port",
167
164
  service,
168
165
  String(inside)
@@ -176,7 +173,7 @@ const dockerCompose = {
176
173
  },
177
174
  async copyOut(stack, service, from, to) {
178
175
  await (0, node_fs_promises.mkdir)((0, node_path.dirname)(to), { recursive: true });
179
- await require_local.run("docker", compose(stack, [
176
+ await require_run.run("docker", compose(stack, [
180
177
  "cp",
181
178
  `${service}:${from}`,
182
179
  to
@@ -533,6 +530,7 @@ function composeStack(input) {
533
530
  };
534
531
  for (const [key, value] of Object.entries(app.env)) if (/[\r\n]/.test(value)) throw new EnvValueMultiline(app.name, key);
535
532
  }
533
+ const layout = input.layout ?? defaultLayout(workspace.root);
536
534
  const compose = stackFile({
537
535
  project,
538
536
  plan,
@@ -540,7 +538,10 @@ function composeStack(input) {
540
538
  apps,
541
539
  master: credential.master,
542
540
  https,
543
- http
541
+ http,
542
+ composeDir: (0, node_path.join)(workspace.root, stackDir(stage)),
543
+ buildRoot: layout.buildRoot,
544
+ workspaceRoot: workspace.root
544
545
  });
545
546
  const caddyfile = edgeCaddyfile(apps.map((app) => ({
546
547
  host: app.host,
@@ -549,18 +550,10 @@ function composeStack(input) {
549
550
  const dockerfiles = {};
550
551
  for (const app of apps) {
551
552
  if (!app.build) continue;
552
- dockerfiles[app.build.dockerfile] = app.kind === "site" ? require_state.siteDockerfile(app.name, workspace.apps[app.name], {
553
- turboPackage: input.packages?.[app.name] ?? app.name,
554
- packageManager: input.packageManager ?? "pnpm",
553
+ dockerfiles[app.build.dockerfile] = require_state.appDockerfile(app.name, workspace.apps[app.name], {
554
+ layout,
555
+ workspaceRoot: workspace.root,
555
556
  manifest
556
- }) : require_state.generateSlimDockerfile({
557
- imageName: app.name,
558
- baseImage: "node:22-alpine",
559
- port: app.port,
560
- healthCheckPath: "/health",
561
- prebuilt: true,
562
- packageManager: input.packageManager ?? "pnpm",
563
- bundle: `${app.path}/.gkm/server/dist/server.mjs`
564
557
  });
565
558
  }
566
559
  return {
@@ -661,8 +654,12 @@ function stackFile(options) {
661
654
  for (const app of apps) services[app.name] = {
662
655
  image: app.ref,
663
656
  ...app.build ? { build: {
664
- context: "../../..",
665
- dockerfile: app.build.dockerfile,
657
+ ...require_state.composeBuildPaths({
658
+ composeDir: options.composeDir,
659
+ buildRoot: options.buildRoot,
660
+ workspaceRoot: options.workspaceRoot,
661
+ dockerfile: app.build.dockerfile
662
+ }),
666
663
  ...app.build.args ? { args: app.build.args } : {}
667
664
  } } : {},
668
665
  restart: "unless-stopped",
@@ -702,6 +699,80 @@ function stackFile(options) {
702
699
  volumes
703
700
  };
704
701
  }
702
+ /**
703
+ * A build without a layout: the workspace is the build root, with pnpm.
704
+ * What a caller that never looked at the filesystem gets.
705
+ */
706
+ function defaultLayout(root) {
707
+ return {
708
+ buildRoot: root,
709
+ gkmRoot: ".",
710
+ tools: {
711
+ packageManager: "pnpm",
712
+ turboVersion: require_state.TURBO_VERSION,
713
+ monorepo: true
714
+ },
715
+ gkmPaths: ["gkm.config.*"]
716
+ };
717
+ }
718
+ /** The id the stack's compose file names an app's build credentials by. */
719
+ function credentialsSecret(app) {
720
+ return `${app}_credentials`;
721
+ }
722
+ /** The file beside the compose file an app's build credentials are read from. */
723
+ function credentialsFile(app) {
724
+ return `${app}.credentials`;
725
+ }
726
+ /**
727
+ * The stack with each backend's image built with its encrypted credentials:
728
+ * a BuildKit secret per app — the file `credentialsFile` names, mounted as
729
+ * `gkm_credentials` — and the hash naming them as a build arg, so a new key
730
+ * rebuilds the layer that embeds them. Each backend's env file gains the
731
+ * `GKM_MASTER_KEY` that decrypts them, the way a Dokploy deploy injects it.
732
+ *
733
+ * Pure: the caller encrypted them.
734
+ */
735
+ function withBuildCredentials(stack, credentials) {
736
+ const services = { ...stack.compose.services };
737
+ const secrets = { ...stack.compose.secrets };
738
+ const apps = stack.apps.map((app) => {
739
+ const own = credentials[app.name];
740
+ const service = services[app.name];
741
+ if (!own || !service?.build) return app;
742
+ const [key, value] = own.buildArg.split("=");
743
+ services[app.name] = {
744
+ ...service,
745
+ build: {
746
+ ...service.build,
747
+ args: {
748
+ ...service.build.args,
749
+ [key]: value
750
+ },
751
+ secrets: [{
752
+ source: credentialsSecret(app.name),
753
+ target: "gkm_credentials"
754
+ }]
755
+ }
756
+ };
757
+ secrets[credentialsSecret(app.name)] = { file: `./${credentialsFile(app.name)}` };
758
+ return {
759
+ ...app,
760
+ env: {
761
+ ...app.env,
762
+ GKM_MASTER_KEY: own.masterKey
763
+ }
764
+ };
765
+ });
766
+ return {
767
+ ...stack,
768
+ apps,
769
+ compose: {
770
+ ...stack.compose,
771
+ services,
772
+ ...Object.keys(secrets).length ? { secrets } : {}
773
+ }
774
+ };
775
+ }
705
776
  /** Render an app's env file: one `KEY=value` per line, read raw by compose. */
706
777
  function envFile(env) {
707
778
  return `${Object.entries(env).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
@@ -789,7 +860,11 @@ var ComposeAppsUnhealthy = class extends Error {
789
860
  * - What was started answers (`verify`): each app is asked through Caddy,
790
861
  * over HTTPS, with the certificate verified.
791
862
  *
792
- * Docker, the registry, the bundler, Postgres and the health probe are
863
+ * Every image is built inside Docker from a pruned slice of the build root —
864
+ * the same Dockerfiles `gkm docker` writes — so nothing is built on this
865
+ * machine before `docker compose build`.
866
+ *
867
+ * Docker, the registry, Postgres and the health probe are
793
868
  * injected, so the rules are asserted without a daemon; the defaults are the
794
869
  * real ones.
795
870
  */
@@ -813,33 +888,11 @@ var NoGitRevision = class extends Error {
813
888
  this.name = "NoGitRevision";
814
889
  }
815
890
  };
816
- /** A backend's production bundle did not build. */
817
- var BundleFailed = class extends Error {
818
- app;
819
- exitCode;
820
- stderr;
821
- constructor(app, exitCode, stderr) {
822
- super(`Bundling '${app}' for production failed (exit code ${exitCode}).${stderr.trim() ? `\n${stderr.trim().slice(-4e3)}` : ""}\nRun \`gkm build --provider server --production\` in the app's directory to see it again.`);
823
- this.app = app;
824
- this.exitCode = exitCode;
825
- this.stderr = stderr;
826
- this.name = "BundleFailed";
827
- }
828
- };
829
- /** The CLI's own entry, which the bundle step runs, is not where it should be. */
830
- var CliEntryNotFound = class extends Error {
831
- from;
832
- constructor(from) {
833
- super(`Could not find bin/gkm.mjs above ${from}, which bundling a backend runs. Reinstall @geekmidas/cli.`);
834
- this.from = from;
835
- this.name = "CliEntryNotFound";
836
- }
837
- };
838
891
  /** The commit HEAD is at, short — and `-dirty` when the tree has changes. */
839
892
  async function gitRevision(root) {
840
893
  let sha;
841
894
  try {
842
- sha = (await require_local.runOutput("git", [
895
+ sha = (await require_run.runOutput("git", [
843
896
  "rev-parse",
844
897
  "--short",
845
898
  "HEAD"
@@ -848,7 +901,7 @@ async function gitRevision(root) {
848
901
  throw new NoGitRevision(root);
849
902
  }
850
903
  if (!sha) throw new NoGitRevision(root);
851
- return (await require_local.runOutput("git", ["status", "--porcelain"], { cwd: root }).catch(() => "")).trim() ? `${sha}-dirty` : sha;
904
+ return (await require_run.runOutput("git", ["status", "--porcelain"], { cwd: root }).catch(() => "")).trim() ? `${sha}-dirty` : sha;
852
905
  }
853
906
  /** The edge's ports, from the environment — 443 and 80 when unset. */
854
907
  function edgePorts(env = process.env) {
@@ -864,46 +917,12 @@ function edgePorts(env = process.env) {
864
917
  http: read(EDGE_PORT_ENV.http, 80)
865
918
  };
866
919
  }
867
- /** `bin/gkm.mjs` of the CLI that is running. */
868
- function cliEntry() {
869
- const from = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
870
- for (let dir = from; (0, node_path.dirname)(dir) !== dir; dir = (0, node_path.dirname)(dir)) {
871
- const entry = (0, node_path.join)(dir, "bin", "gkm.mjs");
872
- if ((0, node_fs.existsSync)(entry)) return entry;
873
- }
874
- throw new CliEntryNotFound(from);
875
- }
876
- /** A cold production bundle is seconds; a hung one must not hold the lock. */
877
- const BUNDLE_TIMEOUT_MS = 6e5;
878
- /**
879
- * Bundle a backend with the gkm that is running — the same build a deploy
880
- * makes, so the image holds one file and no dependencies — in the run's
881
- * sandbox, because the build imports the project's code.
882
- */
883
- async function bundleInSandbox(appRoot, ctx) {
884
- const sandbox = require_sandbox.activeSandbox() ?? new require_local.LocalSandbox({ root: ctx.cwd });
885
- const result = await sandbox.exec("node", [
886
- cliEntry(),
887
- "build",
888
- "--provider",
889
- "server",
890
- "--production"
891
- ], {
892
- cwd: appRoot,
893
- env: sandbox.env,
894
- timeoutMs: BUNDLE_TIMEOUT_MS,
895
- output: ctx.childOutput,
896
- signal: ctx.signal
897
- });
898
- if (result.exitCode !== 0) throw new BundleFailed(appRoot, result.exitCode, result.stderr);
899
- }
900
920
  /**
901
921
  * The real ones. Each app is asked for three minutes before it counts as
902
922
  * down: a deployed stage's first ACME certificate can take that long.
903
923
  */
904
924
  const defaultDeps = {
905
925
  docker: dockerCompose,
906
- bundle: bundleInSandbox,
907
926
  revision: gitRevision,
908
927
  sql: require_state.pgClient,
909
928
  migrate: require_databases.migrateDatabases,
@@ -928,7 +947,9 @@ async function validateCompose(ctx, deps, forced) {
928
947
  runnables
929
948
  });
930
949
  const { secrets, generated } = await stageSecrets(ctx, manifest);
931
- const stack = composeStack({
950
+ const masterKeys = {};
951
+ const layout = mode === "build" ? require_state.imageLayout(workspace) : void 0;
952
+ const composed = composeStack({
932
953
  workspace,
933
954
  manifest,
934
955
  runnables,
@@ -941,9 +962,26 @@ async function validateCompose(ctx, deps, forced) {
941
962
  },
942
963
  secrets,
943
964
  ports: edgePorts(deps.env),
944
- packageManager: require_state.detectPackageManager(root),
945
- packages: Object.fromEntries(Object.entries(workspace.apps).map(([name, app]) => [name, require_state.appPackageName(root, name, app.path)]))
965
+ ...layout ? { layout } : {}
946
966
  });
967
+ const credentials = {};
968
+ if (mode === "build") for (const app of composed.apps) {
969
+ if (app.kind !== "rest-api" || !app.env || !app.build) continue;
970
+ const { encrypted, iv, masterKey } = require_state.encryptSecrets(app.env);
971
+ credentials[app.name] = {
972
+ encrypted,
973
+ iv
974
+ };
975
+ ctx.secrets.mask(masterKey);
976
+ masterKeys[app.name] = {
977
+ masterKey,
978
+ buildArg: require_state.credentialsBuildArg({
979
+ encrypted,
980
+ iv
981
+ })
982
+ };
983
+ }
984
+ const stack = withBuildCredentials(composed, masterKeys);
947
985
  if (mode === "pull" && !ctx.dryRun) await assertImagesExist(deps.docker, tag, stack.apps);
948
986
  const dir = (0, node_path.join)(root, stackDir(stage));
949
987
  const previous = Object.fromEntries(Object.entries((await ctx.state.read(stage))?.state.releases ?? {}).map(([name, releases]) => {
@@ -969,6 +1007,7 @@ async function validateCompose(ctx, deps, forced) {
969
1007
  generated,
970
1008
  previous,
971
1009
  files: [],
1010
+ credentials,
972
1011
  images: {},
973
1012
  changes: []
974
1013
  };
@@ -1000,7 +1039,7 @@ async function stageSecrets(ctx, manifest) {
1000
1039
  */
1001
1040
  async function planCompose(ctx, run) {
1002
1041
  if (run.generated.length > 0) ctx.logger.info(`🔑 "${ctx.stage}" has no ${run.generated.join(", ")} yet; this dry run used values it did not keep.`);
1003
- run.files = await writeStack(ctx.cwd, run.dir, run.stack);
1042
+ run.files = await writeStack(ctx.cwd, run.dir, run.stack, run.credentials);
1004
1043
  printPlan(ctx, run);
1005
1044
  const planned = (change) => {
1006
1045
  run.changes.push(change);
@@ -1044,7 +1083,7 @@ async function provisionCompose(ctx, run, deps) {
1044
1083
  await ctx.secrets.write(run.secrets);
1045
1084
  ctx.logger.info(`🔑 Generated for "${ctx.stage}" (${ctx.secrets.store}): ${run.generated.join(", ")}`);
1046
1085
  }
1047
- run.files = await writeStack(ctx.cwd, run.dir, stack);
1086
+ run.files = await writeStack(ctx.cwd, run.dir, stack, run.credentials);
1048
1087
  printPlan(ctx, run);
1049
1088
  if (stack.infra.length > 0) {
1050
1089
  ctx.logger.info(`\n🗄️ Starting ${stack.infra.join(", ")}…`);
@@ -1090,18 +1129,14 @@ async function prepareDatabases(ctx, run, deps) {
1090
1129
  for (const { target, applied } of runs) if (applied.length > 0) ctx.logger.info(`🗄️ ${target.migrations}: applied ${applied.length}`);
1091
1130
  }
1092
1131
  /**
1093
- * Each app's image: built from this checkout — every backend bundled first,
1094
- * on the host, with this CLI — or pulled at the tag. Nothing live changes.
1132
+ * Each app's image: built from this checkout — inside Docker, every one of
1133
+ * them, from a pruned slice of the build root — or pulled at the tag. Nothing
1134
+ * live changes.
1095
1135
  */
1096
1136
  async function buildCompose(ctx, run, deps) {
1097
1137
  const { stack, ref } = run;
1098
1138
  const apps = stack.apps.map((app) => app.name);
1099
1139
  if (run.mode === "build") {
1100
- for (const app of stack.apps.filter((a) => a.kind === "rest-api")) {
1101
- ctx.signal.throwIfAborted();
1102
- ctx.logger.info(`\n📦 Bundling ${app.name}…`);
1103
- await deps.bundle((0, node_path.join)(ctx.cwd, app.path), ctx);
1104
- }
1105
1140
  ctx.logger.info("\n🐳 Building images…");
1106
1141
  await deps.docker.build(ref, apps);
1107
1142
  } else {
@@ -1284,7 +1319,7 @@ function applied(ctx, run, change) {
1284
1319
  });
1285
1320
  }
1286
1321
  /** Write the stack's files: owner-only, since the env files hold secrets. */
1287
- async function writeStack(root, dir, stack) {
1322
+ async function writeStack(root, dir, stack, credentials = {}) {
1288
1323
  await (0, node_fs_promises.mkdir)(dir, {
1289
1324
  recursive: true,
1290
1325
  mode: 448
@@ -1300,21 +1335,11 @@ async function writeStack(root, dir, stack) {
1300
1335
  await write((0, node_path.join)(dir, "docker-compose.yml"), composeYaml(stack));
1301
1336
  await write((0, node_path.join)(dir, "Caddyfile"), stack.caddyfile);
1302
1337
  for (const app of stack.apps) if (app.env) await write((0, node_path.join)(dir, `${app.name}.env`), envFile(app.env), 384);
1338
+ for (const [name, payload] of Object.entries(credentials)) await write((0, node_path.join)(dir, credentialsFile(name)), require_state.credentialsFileContent(payload), 384);
1303
1339
  for (const [path, content] of Object.entries(stack.dockerfiles)) await write((0, node_path.join)(root, path), content);
1304
- await ignoreStacks(root);
1340
+ await require_state.ensureDockerignore(require_state.findBuildRoot(root));
1305
1341
  return files;
1306
1342
  }
1307
- /** Make sure the build context leaves `.gkm/compose` out. */
1308
- async function ignoreStacks(root) {
1309
- const path = (0, node_path.join)(root, ".dockerignore");
1310
- if (!(0, node_fs.existsSync)(path)) {
1311
- await (0, node_fs_promises.writeFile)(path, require_state.generateDockerignore());
1312
- return;
1313
- }
1314
- const current = await (0, node_fs_promises.readFile)(path, "utf-8");
1315
- if (/^\/?\.gkm\/compose\/?$|^\/?\.gkm\/?$/m.test(current)) return;
1316
- await (0, node_fs_promises.appendFile)(path, `${current.endsWith("\n") ? "" : "\n"}\n# gkm compose's stacks: each app's env file holds its stage's secrets\n.gkm/compose\n`);
1317
- }
1318
1343
  function composeYaml(stack) {
1319
1344
  const stage = stack.local ? "" : ` --stage ${stack.stage}`;
1320
1345
  return `# Generated by gkm compose from the construct manifest — do not edit.
@@ -1424,4 +1449,4 @@ Object.defineProperty(exports, "stackDir", {
1424
1449
  }
1425
1450
  });
1426
1451
 
1427
- //# sourceMappingURL=compose-jrLy7KGO.cjs.map
1452
+ //# sourceMappingURL=compose-5oNHAKNT.cjs.map