@geekmidas/cli 10.0.0-alpha.76 → 10.0.0-alpha.78

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 (133) hide show
  1. package/dist/{LegacyStateStore-dyq07_Ir.mjs → LegacyStateStore-Ceq7A_75.mjs} +2 -2
  2. package/dist/{LegacyStateStore-dyq07_Ir.mjs.map → LegacyStateStore-Ceq7A_75.mjs.map} +1 -1
  3. package/dist/{LegacyStateStore-DwngfJxr.cjs → LegacyStateStore-Z-EKUGSX.cjs} +2 -2
  4. package/dist/{LegacyStateStore-DwngfJxr.cjs.map → LegacyStateStore-Z-EKUGSX.cjs.map} +1 -1
  5. package/dist/{LocalStateStore-B0NCde8Z.cjs → LocalStateStore-Bocb8dmZ.cjs} +2 -2
  6. package/dist/{LocalStateStore-B0NCde8Z.cjs.map → LocalStateStore-Bocb8dmZ.cjs.map} +1 -1
  7. package/dist/{LocalStateStore-DLxCCatI.mjs → LocalStateStore-C72bwpG2.mjs} +2 -2
  8. package/dist/{LocalStateStore-DLxCCatI.mjs.map → LocalStateStore-C72bwpG2.mjs.map} +1 -1
  9. package/dist/{S3StateStore-BOenb-3o.cjs → S3StateStore-35YfcdL_.cjs} +2 -2
  10. package/dist/{S3StateStore-BOenb-3o.cjs.map → S3StateStore-35YfcdL_.cjs.map} +1 -1
  11. package/dist/{S3StateStore-CGK_4hlo.mjs → S3StateStore-C9upSW5o.mjs} +2 -2
  12. package/dist/{S3StateStore-CGK_4hlo.mjs.map → S3StateStore-C9upSW5o.mjs.map} +1 -1
  13. package/dist/{SSMStateStore-DYeD__7p.cjs → SSMStateStore-W-Ps22AQ.cjs} +2 -2
  14. package/dist/{SSMStateStore-DYeD__7p.cjs.map → SSMStateStore-W-Ps22AQ.cjs.map} +1 -1
  15. package/dist/{SSMStateStore-B_5_RqY-.mjs → SSMStateStore-dOmFO6g1.mjs} +2 -2
  16. package/dist/{SSMStateStore-B_5_RqY-.mjs.map → SSMStateStore-dOmFO6g1.mjs.map} +1 -1
  17. package/dist/{add-j2yI3cbS.cjs → add-BvOICikp.cjs} +8 -8
  18. package/dist/{add-j2yI3cbS.cjs.map → add-BvOICikp.cjs.map} +1 -1
  19. package/dist/{add-B7IMXzou.mjs → add-D2XKszYP.mjs} +3 -3
  20. package/dist/{add-B7IMXzou.mjs.map → add-D2XKszYP.mjs.map} +1 -1
  21. package/dist/{bundler-Cf6OgaOe.cjs → bundler-C6T-1OLT.cjs} +5 -5
  22. package/dist/{bundler-Cf6OgaOe.cjs.map → bundler-C6T-1OLT.cjs.map} +1 -1
  23. package/dist/{bundler-DO6bHhnb.mjs → bundler-CtHzKqnZ.mjs} +5 -5
  24. package/dist/{bundler-DO6bHhnb.mjs.map → bundler-CtHzKqnZ.mjs.map} +1 -1
  25. package/dist/{cli-BCPOHmg9.mjs → cli-BgPyhx1i.mjs} +3 -3
  26. package/dist/{cli-BCPOHmg9.mjs.map → cli-BgPyhx1i.mjs.map} +1 -1
  27. package/dist/{cli-CNanUB7a.cjs → cli-K6Vj_pPW.cjs} +4 -4
  28. package/dist/{cli-CNanUB7a.cjs.map → cli-K6Vj_pPW.cjs.map} +1 -1
  29. package/dist/{compose-h_6oNnHC.cjs → compose-B7MC19eC.cjs} +668 -110
  30. package/dist/compose-B7MC19eC.cjs.map +1 -0
  31. package/dist/{compose-Dq4VCtu5.mjs → compose-DByK353T.mjs} +606 -66
  32. package/dist/compose-DByK353T.mjs.map +1 -0
  33. package/dist/{config-CqAvPP-f.d.mts → config-Bql0AmJt.d.mts} +3 -3
  34. package/dist/{config-CWyhLSY1.d.cts.map → config-Bql0AmJt.d.mts.map} +1 -1
  35. package/dist/{config-CWyhLSY1.d.cts → config-DlNpHK8p.d.cts} +3 -3
  36. package/dist/{config-CqAvPP-f.d.mts.map → config-DlNpHK8p.d.cts.map} +1 -1
  37. package/dist/config.cjs +1 -1
  38. package/dist/config.d.cts +3 -3
  39. package/dist/config.d.mts +3 -3
  40. package/dist/config.mjs +1 -1
  41. package/dist/deploy/public.cjs +12 -12
  42. package/dist/deploy/public.d.cts +3 -3
  43. package/dist/deploy/public.d.cts.map +1 -1
  44. package/dist/deploy/public.d.mts +3 -3
  45. package/dist/deploy/public.d.mts.map +1 -1
  46. package/dist/deploy/public.mjs +6 -6
  47. package/dist/{deploy-CVXEx7Nm.mjs → deploy-BerP7ppB.mjs} +5 -5
  48. package/dist/{deploy-CVXEx7Nm.mjs.map → deploy-BerP7ppB.mjs.map} +1 -1
  49. package/dist/{deploy-CT3R9de9.cjs → deploy-Dt42xiQA.cjs} +11 -11
  50. package/dist/{deploy-CT3R9de9.cjs.map → deploy-Dt42xiQA.cjs.map} +1 -1
  51. package/dist/{dokploy-eSGmlhhj.cjs → dokploy-NG9UrVrP.cjs} +2 -2
  52. package/dist/{dokploy-eSGmlhhj.cjs.map → dokploy-NG9UrVrP.cjs.map} +1 -1
  53. package/dist/{dokploy-CYm2ozFs.mjs → dokploy-ssZQRK2C.mjs} +2 -2
  54. package/dist/{dokploy-CYm2ozFs.mjs.map → dokploy-ssZQRK2C.mjs.map} +1 -1
  55. package/dist/{encryption-vS3Qzw73.cjs → encryption-CbMI24fI.cjs} +6 -6
  56. package/dist/{encryption-vS3Qzw73.cjs.map → encryption-CbMI24fI.cjs.map} +1 -1
  57. package/dist/{encryption-DC0rsR1W.mjs → encryption-De6MN0O5.mjs} +3 -3
  58. package/dist/{encryption-DC0rsR1W.mjs.map → encryption-De6MN0O5.mjs.map} +1 -1
  59. package/dist/{engine-C0N2d1i5.cjs → engine-CoCsNoW_.cjs} +73 -68
  60. package/dist/{engine-C0N2d1i5.cjs.map → engine-CoCsNoW_.cjs.map} +1 -1
  61. package/dist/{engine-BOO5TWZd.mjs → engine-DOjGIgl4.mjs} +9 -4
  62. package/dist/{engine-BOO5TWZd.mjs.map → engine-DOjGIgl4.mjs.map} +1 -1
  63. package/dist/{github-CEaFDL6t.mjs → github-CwX9z89E.mjs} +3 -3
  64. package/dist/{github-CEaFDL6t.mjs.map → github-CwX9z89E.mjs.map} +1 -1
  65. package/dist/{github-ClkdCOL9.cjs → github-D9vGqdLk.cjs} +7 -7
  66. package/dist/{github-ClkdCOL9.cjs.map → github-D9vGqdLk.cjs.map} +1 -1
  67. package/dist/{index-DOxmDKqv.d.mts → index-BXO0vlme.d.mts} +2 -2
  68. package/dist/{index-Ccu0f_2m.d.cts.map → index-BXO0vlme.d.mts.map} +1 -1
  69. package/dist/{index-Ccu0f_2m.d.cts → index-Rs0Fua-q.d.cts} +2 -2
  70. package/dist/{index-DOxmDKqv.d.mts.map → index-Rs0Fua-q.d.cts.map} +1 -1
  71. package/dist/index.cjs +180 -219
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.mjs +108 -147
  74. package/dist/index.mjs.map +1 -1
  75. package/dist/{migrate-BRbYtFXG.cjs → migrate-B4GBvCNY.cjs} +5 -5
  76. package/dist/{migrate-BRbYtFXG.cjs.map → migrate-B4GBvCNY.cjs.map} +1 -1
  77. package/dist/{migrate-D3NAT7Ns.mjs → migrate-BQ4wVKq_.mjs} +3 -3
  78. package/dist/{migrate-D3NAT7Ns.mjs.map → migrate-BQ4wVKq_.mjs.map} +1 -1
  79. package/dist/{migrate-DrO2p9Rl.mjs → migrate-CNKaQl3K.mjs} +3 -3
  80. package/dist/{migrate-DrO2p9Rl.mjs.map → migrate-CNKaQl3K.mjs.map} +1 -1
  81. package/dist/{migrate-D5_-ylI1.cjs → migrate-Cgoy58Sh.cjs} +8 -8
  82. package/dist/{migrate-D5_-ylI1.cjs.map → migrate-Cgoy58Sh.cjs.map} +1 -1
  83. package/dist/openapi.cjs +1 -1
  84. package/dist/openapi.d.cts +1 -1
  85. package/dist/openapi.d.mts +1 -1
  86. package/dist/openapi.mjs +1 -1
  87. package/dist/reconcile/public.d.cts +1 -1
  88. package/dist/reconcile/public.d.mts +1 -1
  89. package/dist/{resolve-Fa1Ii0BK.cjs → resolve-CEaqRBzY.cjs} +3 -3
  90. package/dist/{resolve-Fa1Ii0BK.cjs.map → resolve-CEaqRBzY.cjs.map} +1 -1
  91. package/dist/{resolve-C1muFos5.mjs → resolve-mvaystiE.mjs} +3 -3
  92. package/dist/{resolve-C1muFos5.mjs.map → resolve-mvaystiE.mjs.map} +1 -1
  93. package/dist/{rollback-C9N5lKVf.cjs → rollback-F3P-rA-r.cjs} +7 -7
  94. package/dist/{rollback-C9N5lKVf.cjs.map → rollback-F3P-rA-r.cjs.map} +1 -1
  95. package/dist/{rollback-DeQzbRqM.mjs → rollback-S2C-Y9pB.mjs} +5 -5
  96. package/dist/{rollback-DeQzbRqM.mjs.map → rollback-S2C-Y9pB.mjs.map} +1 -1
  97. package/dist/{runtime-Cm7QA53H.d.cts → runtime-D9AxGzrw.d.cts} +2 -2
  98. package/dist/{runtime-BSvzPqXW.d.mts.map → runtime-D9AxGzrw.d.cts.map} +1 -1
  99. package/dist/{runtime-BSvzPqXW.d.mts → runtime-Dflki3Vs.d.mts} +2 -2
  100. package/dist/{runtime-Cm7QA53H.d.cts.map → runtime-Dflki3Vs.d.mts.map} +1 -1
  101. package/dist/{sniffer-Y6GQOCXB.cjs → sniffer-BjG-1mlD.cjs} +6 -6
  102. package/dist/{sniffer-Y6GQOCXB.cjs.map → sniffer-BjG-1mlD.cjs.map} +1 -1
  103. package/dist/{sniffer-DR8AlRCk.mjs → sniffer-ByWtH28i.mjs} +6 -6
  104. package/dist/{sniffer-DR8AlRCk.mjs.map → sniffer-ByWtH28i.mjs.map} +1 -1
  105. package/dist/{state-C2qi0iQw.cjs → stale-BsiPJI7Y.cjs} +111 -25
  106. package/dist/stale-BsiPJI7Y.cjs.map +1 -0
  107. package/dist/{state-CUecOCNJ.mjs → stale-C5FqIVc8.mjs} +106 -26
  108. package/dist/stale-C5FqIVc8.mjs.map +1 -0
  109. package/dist/target/public.cjs +1 -1
  110. package/dist/target/public.d.cts +2 -2
  111. package/dist/target/public.d.mts +2 -2
  112. package/dist/target/public.mjs +1 -1
  113. package/dist/{types-BdptGBFS.d.cts → types-ByY0zi3n.d.cts} +42 -3
  114. package/dist/types-ByY0zi3n.d.cts.map +1 -0
  115. package/dist/{types-OxE0OAn2.d.mts → types-DKxkXsKC.d.mts} +42 -3
  116. package/dist/types-DKxkXsKC.d.mts.map +1 -0
  117. package/dist/workspace/index.cjs +1 -1
  118. package/dist/workspace/index.d.cts +2 -2
  119. package/dist/workspace/index.d.mts +2 -2
  120. package/dist/workspace/index.mjs +1 -1
  121. package/dist/{workspace-QUTqYmVy.mjs → workspace-BBdqmkch.mjs} +114 -17
  122. package/dist/workspace-BBdqmkch.mjs.map +1 -0
  123. package/dist/{workspace-DOm81oUo.cjs → workspace-Bp8FEkF-.cjs} +130 -15
  124. package/dist/workspace-Bp8FEkF-.cjs.map +1 -0
  125. package/package.json +15 -15
  126. package/dist/compose-Dq4VCtu5.mjs.map +0 -1
  127. package/dist/compose-h_6oNnHC.cjs.map +0 -1
  128. package/dist/state-C2qi0iQw.cjs.map +0 -1
  129. package/dist/state-CUecOCNJ.mjs.map +0 -1
  130. package/dist/types-BdptGBFS.d.cts.map +0 -1
  131. package/dist/types-OxE0OAn2.d.mts.map +0 -1
  132. package/dist/workspace-DOm81oUo.cjs.map +0 -1
  133. package/dist/workspace-QUTqYmVy.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-B7MC19eC.cjs","names":["spawn","run","runOutput","mkdir","dirname","createHash","yaml","stringify","join","gkmHome","writeFile","chmod","rename","readFile","mkdir","copyFile","rm","existsSync","randomBytes","isOtlpDestination","NoDomainForStage","LOGS_PORT","DEFAULT_IMAGES","randomBytes","proxyFor","certificateFor","planFor","provisionOrder","DEFAULT_EVENTS","localRolePassword","workerUnits","provideKey","publicEnvFor","appEnvKeys","workerEnvKeys","resolveLogs","assertExternalServices","bucketPolicies","hostFor","NoDomainForStage","appKey","networkEnv","suppliedOnly","otelEnv","join","LOGS_PORT","appDockerfile","workerDockerfile","devServicesUsed","validateImageRef","imageRef","WORKER_PORT","resolveHost","isMainFrontendApp","composeFor","portKeys","composeBuildPaths","DEFAULT_IMAGES","TURBO_VERSION","request","join","runOutput","pgClient","bucketClient","migrateDatabases","imageRef","discover","constructGlobs","assertStageCredentials","imageLayout","existsSync","ComposeTlsFileMissing","installedFrom","withGeneratedSecrets","initStageSecrets","resolveLogs","applyBuckets","applyPolicies","postgresStatements","applyPostgres","envFor","primaryPortKey","DeployJournal","createEmptyState","readFile","hostname","userInfo","mkdir","chmod","dirname","writeFile","rm","readdir","ensureDockerignore","findBuildRoot","stringify","defineTarget"],"sources":["../src/compose/docker.ts","../src/compose/traefik.ts","../src/compose/edge.ts","../src/compose/images.ts","../src/compose/logs.ts","../src/compose/redis.ts","../src/compose/caddyfile.ts","../src/compose/stack.ts","../src/target/compose/health.ts","../src/target/compose/phases.ts","../src/target/compose/index.ts"],"sourcesContent":["/**\n * The Docker operations `gkm compose` needs, behind an interface.\n *\n * Small on purpose, like reconcile's: the rules about *when* each runs — the\n * registry is asked before anything is pulled, nothing is started for a tag\n * that is missing — are asserted against a fake, and this file is only the\n * wiring to the real CLI.\n *\n * Every call is an argument array. Image refs, tags and paths come from the\n * workspace, and none of them reaches a shell.\n */\n\nimport { spawn } from 'node:child_process';\nimport { mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { type RunOptions, run, runOutput } from '../run';\n\n/** Where one stack lives: its compose project and the file that defines it. */\nexport interface StackRef {\n\tproject: string;\n\tfile: string;\n\t/**\n\t * The project's own files merged over `file`, in order — its\n\t * `docker-compose.<stage>.yml`, where it has one.\n\t */\n\toverrides?: readonly string[];\n\t/** Where relative paths in the file resolve — the workspace root. */\n\tcwd: string;\n\t/**\n\t * Where docker's own output goes: the terminal (the default), stderr — so\n\t * a `--json` run's stdout carries only events — or nowhere.\n\t */\n\toutput?: 'inherit' | 'stderr' | 'ignore';\n\t/** Stops whatever docker is doing for the stack. */\n\tsignal?: AbortSignal;\n}\n\n/** `output` as `spawn` reads it. */\nconst STDIO: Record<NonNullable<StackRef['output']>, RunOptions['stdio']> = {\n\tinherit: 'inherit',\n\tstderr: ['ignore', 2, 2],\n\tignore: 'ignore',\n};\n\n/** How a stack's docker commands run: where it is, where output goes. */\nfunction runOptions(stack: StackRef, env?: NodeJS.ProcessEnv): RunOptions {\n\treturn {\n\t\tcwd: stack.cwd,\n\t\tstdio: STDIO[stack.output ?? 'inherit'],\n\t\t...(env ? { env } : {}),\n\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t};\n}\n\n/** What the registry said about one image ref. */\nexport type ImageLookup =\n\t| { ref: string; status: 'found' }\n\t| { ref: string; status: 'missing' }\n\t| { ref: string; status: 'unreachable'; detail: string };\n\n/** A running container that publishes a host port. */\nexport interface PortHolder {\n\t/** The container's name. */\n\tcontainer: string;\n\t/** Its compose project and service, when compose started it. */\n\tproject?: string;\n\tservice?: string;\n}\n\nexport interface ComposeDocker {\n\t/** Ask the registry whether `ref` exists, without pulling it. */\n\tlookup(ref: string): Promise<ImageLookup>;\n\t/** Build every service with a `build:` entry. */\n\tbuild(stack: StackRef, services: readonly string[]): Promise<void>;\n\t/** Pull the named services' images. */\n\tpull(stack: StackRef, services: readonly string[]): Promise<void>;\n\t/**\n\t * Start services, detached, and wait for their health checks. With no\n\t * services named, the whole stack — and anything it no longer defines is\n\t * removed.\n\t */\n\tup(stack: StackRef, services?: readonly string[]): Promise<void>;\n\t/** Stop the stack. Its volumes are kept. */\n\tdown(stack: StackRef): Promise<void>;\n\t/** The host port a running service publishes for `inside`. */\n\tport(stack: StackRef, service: string, inside: number): Promise<number>;\n\t/**\n\t * A running service's health, as its own check reports it — `healthy`,\n\t * `starting`, `unhealthy` — or undefined when it is not running.\n\t */\n\thealth(stack: StackRef, service: string): Promise<string | undefined>;\n\t/** Copy a file out of a running service. */\n\tcopyOut(\n\t\tstack: StackRef,\n\t\tservice: string,\n\t\tfrom: string,\n\t\tto: string,\n\t): Promise<void>;\n\t/**\n\t * Push an image built here to its registry, and return the digest the\n\t * registry stored it under (`sha256:…`).\n\t */\n\tpush(stack: StackRef, ref: string): Promise<string>;\n\t/**\n\t * What an image resolved to: the registry digest a pulled image has, or\n\t * the content id of one built here and never pushed.\n\t */\n\tdigest(ref: string): Promise<string | undefined>;\n\t/** Create a network, unless one by that name is there. */\n\tensureNetwork(name: string): Promise<void>;\n\t/** Every running container publishing `port` on the host. */\n\tpublishers(port: number): Promise<PortHolder[]>;\n}\n\n/**\n * The host ports a `docker ps` Ports column publishes: `0.0.0.0:443->443/tcp,\n * [::]:443->443/tcp, 0.0.0.0:9000-9001->9000-9001/tcp`.\n */\nexport function publishedPorts(column: string): number[] {\n\tconst ports = new Set<number>();\n\tfor (const match of column.matchAll(\n\t\t/(?:[\\d.]+|\\[[^\\]]*\\]):(\\d+)(?:-(\\d+))?->/g,\n\t)) {\n\t\tconst first = Number(match[1]);\n\t\tconst last = match[2] ? Number(match[2]) : first;\n\t\tfor (let port = first; port <= last; port++) ports.add(port);\n\t}\n\treturn [...ports];\n}\n\n/** Each line `docker ps` printed, as the containers holding `port`. */\nexport function portHolders(output: string, port: number): PortHolder[] {\n\treturn output\n\t\t.split('\\n')\n\t\t.filter(Boolean)\n\t\t.map((line) => line.split('\\t'))\n\t\t.filter(([, , , column = '']) => publishedPorts(column).includes(port))\n\t\t.map(([container = '', project, service]) => ({\n\t\t\tcontainer,\n\t\t\t...(project ? { project } : {}),\n\t\t\t...(service ? { service } : {}),\n\t\t}));\n}\n\n/** How long a stack has to pass its health checks. */\nconst WAIT_TIMEOUT_S = 180;\n\n/** `docker compose port` printed nothing a port can be read from. */\nexport class ServicePortUnknown extends Error {\n\tconstructor(\n\t\treadonly service: string,\n\t\treadonly inside: number,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${service}' publishes no host port for ${inside} (docker said: ${output.trim() || 'nothing'}). Is it running? \\`docker compose ps\\` shows the stack.`,\n\t\t);\n\t\tthis.name = 'ServicePortUnknown';\n\t}\n}\n\n/**\n * Whether `ref` names a registry on this machine's loopback — which the\n * daemon pulls from and pushes to over plain HTTP by default, and `docker\n * manifest inspect` reaches only when told `--insecure` (without it, a local\n * registry's image is reported as no such manifest).\n */\nexport function isLoopbackRegistry(ref: string): boolean {\n\tconst first = ref.split('/')[0]!;\n\tif (!ref.includes('/') || !/[.:]|^localhost$/.test(first)) return false;\n\tconst host = first.replace(/:\\d+$/, '');\n\treturn host === 'localhost' || /^127(?:\\.\\d{1,3}){3}$/.test(host);\n}\n\n/** `docker push` finished without saying what digest the registry stored. */\nexport class PushDigestUnknown extends Error {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`Pushed ${ref}, but docker did not say which digest the registry stored ` +\n\t\t\t\t`(it said: ${output.trim().split('\\n').slice(-3).join(' / ') || 'nothing'}). ` +\n\t\t\t\t`Check the push with \\`docker buildx imagetools inspect ${ref}\\`.`,\n\t\t);\n\t\tthis.name = 'PushDigestUnknown';\n\t}\n}\n\n/** The digest `docker push` reports last: `<tag>: digest: sha256:… size: …`. */\nexport function pushedDigest(output: string): string | undefined {\n\tconst matches = [...output.matchAll(/digest: (sha256:[0-9a-f]{64})/g)];\n\treturn matches.at(-1)?.[1];\n}\n\nfunction compose(stack: StackRef, args: readonly string[]): string[] {\n\treturn [\n\t\t'compose',\n\t\t'-p',\n\t\tstack.project,\n\t\t'-f',\n\t\tstack.file,\n\t\t...(stack.overrides ?? []).flatMap((file) => ['-f', file]),\n\t\t...args,\n\t];\n}\n\n/** Run a program and keep everything it said, whatever it exits with. */\nfunction capture(\n\tcommand: string,\n\targs: readonly string[],\n\ttimeoutMs = 60_000,\n): Promise<{ code: number | null; stdout: string; stderr: string }> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t});\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\t\tchild.stdout.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString();\n\t\t});\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString();\n\t\t});\n\t\tconst timer = setTimeout(() => child.kill('SIGKILL'), timeoutMs);\n\t\ttimer.unref?.();\n\t\tchild.on('error', (error) => {\n\t\t\tclearTimeout(timer);\n\t\t\treject(error);\n\t\t});\n\t\tchild.on('close', (code) => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve({ code, stdout, stderr });\n\t\t});\n\t});\n}\n\n/**\n * Whether a failed `docker manifest inspect` means the tag is not there, as\n * opposed to the registry not answering.\n *\n * Read off the message because that is all the CLI gives. Anything not\n * recognisably \"no such tag\" is treated as the registry being unreachable:\n * a registry that refused credentials must not be reported as a tag that was\n * never pushed, or the fix offered would be the wrong one.\n */\nexport function isMissingManifest(output: string): boolean {\n\treturn /no such manifest|manifest unknown|manifest for .* not found|not found: manifest/i.test(\n\t\toutput,\n\t);\n}\n\nexport const dockerCompose: ComposeDocker = {\n\tasync lookup(ref) {\n\t\tconst { code, stdout, stderr } = await capture('docker', [\n\t\t\t'manifest',\n\t\t\t'inspect',\n\t\t\t...(isLoopbackRegistry(ref) ? ['--insecure'] : []),\n\t\t\tref,\n\t\t]);\n\t\tif (code === 0) return { ref, status: 'found' };\n\n\t\tconst output = `${stderr}\\n${stdout}`.trim();\n\t\treturn isMissingManifest(output)\n\t\t\t? { ref, status: 'missing' }\n\t\t\t: { ref, status: 'unreachable', detail: output };\n\t},\n\n\tasync build(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['build', ...services]),\n\t\t\trunOptions(stack, { ...process.env, DOCKER_BUILDKIT: '1' }),\n\t\t);\n\t},\n\n\tasync pull(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['pull', ...services]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync up(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, [\n\t\t\t\t'up',\n\t\t\t\t'-d',\n\t\t\t\t'--wait',\n\t\t\t\t`--wait-timeout=${WAIT_TIMEOUT_S}`,\n\t\t\t\t// Only when the whole stack is asked for: starting the databases\n\t\t\t\t// first must not remove the apps an earlier run left running.\n\t\t\t\t...(services ? [] : ['--remove-orphans']),\n\t\t\t\t...(services ?? []),\n\t\t\t]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync down(stack) {\n\t\tawait run('docker', compose(stack, ['down']), runOptions(stack));\n\t},\n\n\tasync port(stack, service, inside) {\n\t\tconst output = await runOutput(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['port', service, String(inside)]),\n\t\t\t{ cwd: stack.cwd, ...(stack.signal ? { signal: stack.signal } : {}) },\n\t\t);\n\t\t// `127.0.0.1:54321` — the part after the last colon is the host port.\n\t\tconst port = Number(output.trim().split(':').pop());\n\t\tif (!Number.isInteger(port) || port <= 0) {\n\t\t\tthrow new ServicePortUnknown(service, inside, output);\n\t\t}\n\t\treturn port;\n\t},\n\n\tasync health(stack, service) {\n\t\tconst { code, stdout } = await capture('docker', [\n\t\t\t...compose(stack, ['ps', '--format', '{{.Health}}', service]),\n\t\t]);\n\t\tif (code !== 0) return undefined;\n\t\treturn stdout.trim().split('\\n')[0] || undefined;\n\t},\n\n\tasync copyOut(stack, service, from, to) {\n\t\tawait mkdir(dirname(to), { recursive: true });\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['cp', `${service}:${from}`, to]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync push(stack, ref) {\n\t\t// What it printed is read back for the digest; its errors still reach\n\t\t// the terminal.\n\t\tconst output = await runOutput('docker', ['push', ref], {\n\t\t\tcwd: stack.cwd,\n\t\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t\t});\n\t\tconst digest = pushedDigest(output);\n\t\tif (!digest) throw new PushDigestUnknown(ref, output);\n\t\treturn digest;\n\t},\n\n\tasync digest(ref) {\n\t\tconst { code, stdout } = await capture('docker', [\n\t\t\t'image',\n\t\t\t'inspect',\n\t\t\t'--format={{json .RepoDigests}} {{.Id}}',\n\t\t\tref,\n\t\t]);\n\t\tif (code !== 0) return undefined;\n\n\t\tconst [json = '[]', id] = stdout.trim().split(' ');\n\t\tconst repository = ref.split('@')[0]!.replace(/:[\\w][\\w.-]*$/, '');\n\t\ttry {\n\t\t\tconst digests = JSON.parse(json) as unknown;\n\t\t\tconst match = Array.isArray(digests)\n\t\t\t\t? digests.find(\n\t\t\t\t\t\t(entry): entry is string =>\n\t\t\t\t\t\t\ttypeof entry === 'string' && entry.startsWith(`${repository}@`),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\t\t\tif (match) return match.slice(repository.length + 1);\n\t\t} catch {\n\t\t\t// Fall through to the content id.\n\t\t}\n\t\treturn id || undefined;\n\t},\n\n\tasync ensureNetwork(name) {\n\t\tconst { code } = await capture('docker', ['network', 'inspect', name]);\n\t\tif (code === 0) return;\n\t\tconst created = await capture('docker', ['network', 'create', name]);\n\t\t// Another run may have created it between the two calls.\n\t\tif (created.code !== 0 && !/already exists/.test(created.stderr)) {\n\t\t\tthrow new NetworkCreateFailed(name, created.stderr);\n\t\t}\n\t},\n\n\tasync publishers(port) {\n\t\tconst { stdout } = await capture('docker', [\n\t\t\t'ps',\n\t\t\t'--format',\n\t\t\t'{{.Names}}\\t{{.Label \"com.docker.compose.project\"}}\\t{{.Label \"com.docker.compose.service\"}}\\t{{.Ports}}',\n\t\t]);\n\t\treturn portHolders(stdout, port);\n\t},\n};\n\n/** `docker network create` failed. */\nexport class NetworkCreateFailed extends Error {\n\tconstructor(\n\t\treadonly network: string,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not create the Docker network '${network}' (docker said: ${output.trim() || 'nothing'}). Create it by hand with \\`docker network create ${network}\\` and run again.`,\n\t\t);\n\t\tthis.name = 'NetworkCreateFailed';\n\t}\n}\n","/**\n * The server's shared edge, rendered for Traefik: what the edge itself runs\n * with, and what one stack registers with it.\n *\n * One Traefik per server owns 80 and 443, the ACME state and the redirect to\n * HTTPS. It is configured through its file provider alone: each stack writes\n * one file — its routers, services and middlewares, every name prefixed with\n * its compose project — into a directory the edge watches, and removes it\n * when it stops. There is no Docker socket: the edge never learns what runs\n * on the server except from those files.\n *\n * The edge and the stacks meet on one external Docker network. Only a\n * stack's public services join it, each under an alias prefixed with its\n * project (`<project>-api`), because the network is shared: a bare service\n * name there would be answered by every stack's `api`.\n *\n * Pure: the documents are data, and the edge's side effects are `edge.ts`'s.\n */\n\nimport { createHash } from 'node:crypto';\nimport { stringify } from 'yaml';\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/**\n * The image, pinned: the edge is every stack's way in, so a new version is a\n * change to this line, not whatever `latest` is on the day a server starts.\n */\nexport const TRAEFIK_IMAGE = 'traefik:v3.7.13';\n\n/** The edge's compose project, one per server. */\nexport const EDGE_PROJECT = 'gkm-edge';\n\n/** The external network the edge and every stack's public services share. */\nexport const EDGE_NETWORK = 'gkm-edge';\n\n/** The edge's compose service. */\nexport const EDGE_SERVICE = 'traefik';\n\n/** Inside the edge's container: what it watches, and where certificates are. */\nexport const EDGE_DYNAMIC_DIR = '/etc/gkm-edge/dynamic';\nexport const EDGE_CERTS_DIR = '/etc/gkm-edge/certs';\n\n/** The certificate resolver every deployed route without its own certificate uses. */\nexport const ACME_RESOLVER = 'letsencrypt';\n\n/** The internal entrypoint the edge's health check asks; never published. */\nconst PING_PORT = 8082;\n\n/** A stack's service, as the edge — and the stack itself — reach it. */\nexport function edgeAlias(project: string, service: string): string {\n\treturn `${project}-${service}`;\n}\n\n/** A stack's certificate, as the edge's container reads it. */\nexport function edgeCertificatePaths(project: string): {\n\tcertFile: string;\n\tkeyFile: string;\n} {\n\treturn {\n\t\tcertFile: `${EDGE_CERTS_DIR}/${project}.crt`,\n\t\tkeyFile: `${EDGE_CERTS_DIR}/${project}.key`,\n\t};\n}\n\n/** The edge's ports on the host. */\nexport interface EdgePorts {\n\thttps: number;\n\thttp: number;\n}\n\n/**\n * The edge's static configuration: the entrypoints, the redirect, ACME, and\n * the directory it watches. No API and no dashboard — nothing about the edge\n * is reachable but the routes stacks register.\n */\nexport function traefikStatic(ports: EdgePorts): Record<string, unknown> {\n\treturn {\n\t\tglobal: { checkNewVersion: false, sendAnonymousUsage: false },\n\t\tentryPoints: {\n\t\t\tweb: {\n\t\t\t\taddress: ':80',\n\t\t\t\thttp: {\n\t\t\t\t\t// Every plain-HTTP request is sent to HTTPS — but an ACME\n\t\t\t\t\t// HTTP-01 challenge, which Traefik answers before the redirect.\n\t\t\t\t\tredirections: {\n\t\t\t\t\t\tentryPoint: {\n\t\t\t\t\t\t\t// The published port when it is not 443, so the redirect\n\t\t\t\t\t\t\t// lands where the edge actually listens.\n\t\t\t\t\t\t\tto: ports.https === 443 ? 'websecure' : `:${ports.https}`,\n\t\t\t\t\t\t\tscheme: 'https',\n\t\t\t\t\t\t\tpermanent: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twebsecure: { address: ':443' },\n\t\t\tping: { address: `:${PING_PORT}` },\n\t\t},\n\t\tping: { entryPoint: 'ping' },\n\t\tproviders: {\n\t\t\tfile: { directory: EDGE_DYNAMIC_DIR, watch: true },\n\t\t},\n\t\tcertificatesResolvers: {\n\t\t\t[ACME_RESOLVER]: {\n\t\t\t\tacme: {\n\t\t\t\t\tstorage: '/acme/acme.json',\n\t\t\t\t\thttpChallenge: { entryPoint: 'web' },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tlog: { level: 'INFO' },\n\t};\n}\n\n/** The edge's compose document. */\nexport function edgeCompose(options: {\n\t/** The edge's directory on the host. */\n\tdir: string;\n\tports: EdgePorts;\n\t/** The static configuration, as written — its hash recreates the edge. */\n\tstaticConfig: string;\n\tlogging: { driver: string; options: Record<string, string> };\n}): Record<string, unknown> {\n\tconst { dir, ports } = options;\n\treturn {\n\t\tname: EDGE_PROJECT,\n\t\tservices: {\n\t\t\t[EDGE_SERVICE]: {\n\t\t\t\timage: TRAEFIK_IMAGE,\n\t\t\t\trestart: 'unless-stopped',\n\t\t\t\tports: [`${ports.https}:443`, `${ports.http}:80`],\n\t\t\t\tvolumes: [\n\t\t\t\t\t`${dir}/traefik.yml:/etc/traefik/traefik.yml:ro`,\n\t\t\t\t\t// Directories, not files: a stack's file is replaced by a\n\t\t\t\t\t// rename, which a file mounted on its own would never see.\n\t\t\t\t\t`${dir}/dynamic:${EDGE_DYNAMIC_DIR}:ro`,\n\t\t\t\t\t`${dir}/certs:${EDGE_CERTS_DIR}:ro`,\n\t\t\t\t\t'acme:/acme',\n\t\t\t\t],\n\t\t\t\t// Static configuration is read at start: a change to it is a\n\t\t\t\t// change to the service, so `up` recreates the edge.\n\t\t\t\tlabels: {\n\t\t\t\t\t'dev.geekmidas.edge.config': createHash('sha256')\n\t\t\t\t\t\t.update(options.staticConfig)\n\t\t\t\t\t\t.digest('hex')\n\t\t\t\t\t\t.slice(0, 16),\n\t\t\t\t},\n\t\t\t\tnetworks: ['edge'],\n\t\t\t\thealthcheck: {\n\t\t\t\t\ttest: ['CMD', 'traefik', 'healthcheck', '--ping'],\n\t\t\t\t\tinterval: '10s',\n\t\t\t\t\ttimeout: '5s',\n\t\t\t\t\tretries: 5,\n\t\t\t\t},\n\t\t\t\tlogging: options.logging,\n\t\t\t},\n\t\t},\n\t\tvolumes: { acme: {} },\n\t\tnetworks: { edge: { name: EDGE_NETWORK, external: true } },\n\t};\n}\n\n/** What a stack registers with the edge — its routes, and its certificate. */\nexport interface TraefikStackOptions {\n\tproject: string;\n\t/** ACME, or the stage's own certificate. Never the local CA: that is Caddy's. */\n\ttls: Exclude<EdgeTls, { kind: 'internal' }>;\n}\n\n/** A stack's dynamic configuration, as an object. */\nexport function traefikDynamic(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): Record<string, unknown> {\n\tconst { project, tls } = options;\n\tconst name = (route: EdgeRoute, suffix?: string) =>\n\t\t`${project}-${route.name}${suffix ? `-${suffix}` : ''}`;\n\tconst url = ({ service, port }: Upstream) =>\n\t\t`http://${edgeAlias(project, service)}:${port}`;\n\n\tconst routers: Record<string, unknown> = {};\n\tconst services: Record<string, unknown> = {};\n\tconst middlewares: Record<string, unknown> = {};\n\n\tfor (const route of routes) {\n\t\tconst chain: string[] = [];\n\t\tif (route.allow) {\n\t\t\t// The peer Traefik sees — never X-Forwarded-For, which a client\n\t\t\t// could set. Everything else gets 403.\n\t\t\tmiddlewares[name(route, 'allow')] = {\n\t\t\t\tipAllowList: { sourceRange: [...route.allow] },\n\t\t\t};\n\t\t\tchain.push(name(route, 'allow'));\n\t\t}\n\t\tif (route.prefix) {\n\t\t\tmiddlewares[name(route, 'prefix')] = {\n\t\t\t\taddPrefix: { prefix: route.prefix },\n\t\t\t};\n\t\t\tchain.push(name(route, 'prefix'));\n\t\t}\n\n\t\trouters[name(route)] = {\n\t\t\trule: `Host(\\`${route.host}\\`)`,\n\t\t\tentryPoints: ['websecure'],\n\t\t\tservice: name(route),\n\t\t\t...(chain.length > 0 ? { middlewares: chain } : {}),\n\t\t\ttls: tls.kind === 'acme' ? { certResolver: ACME_RESOLVER } : {},\n\t\t};\n\n\t\tservices[name(route)] = {\n\t\t\tloadBalancer: {\n\t\t\t\tservers: route.upstreams.map((upstream) => ({ url: url(upstream) })),\n\t\t\t\t// A bucket is routed and signed on the Host header, so MinIO is\n\t\t\t\t// sent its own; an app is sent the one the caller used, which is\n\t\t\t\t// what it builds redirects, cookies and links on.\n\t\t\t\t...(route.prefix ? { passHostHeader: false } : {}),\n\t\t\t\t...(route.streaming\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t// Never buffer: each chunk of a streamed response is\n\t\t\t\t\t\t\t// flushed to the client as it is written.\n\t\t\t\t\t\t\tresponseForwarding: { flushInterval: '-1ms' },\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\t...(route.health\n\t\t\t\t\t? {\n\t\t\t\t\t\t\thealthCheck: {\n\t\t\t\t\t\t\t\tpath: route.health,\n\t\t\t\t\t\t\t\tinterval: '5s',\n\t\t\t\t\t\t\t\ttimeout: '3s',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\thttp: {\n\t\t\trouters,\n\t\t\tservices,\n\t\t\t...(Object.keys(middlewares).length > 0 ? { middlewares } : {}),\n\t\t},\n\t\t...(tls.kind === 'files'\n\t\t\t? {\n\t\t\t\t\ttls: {\n\t\t\t\t\t\tcertificates: [{ certFile: tls.certFile, keyFile: tls.keyFile }],\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/** A stack's dynamic configuration file, as written to the edge's directory. */\nexport function traefikDynamicFile(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): string {\n\treturn `# Generated by gkm compose for ${options.project} — do not edit.\n# The shared edge (${EDGE_PROJECT}) reads every file in this directory; this\n# one is removed by gkm compose --down.\n${yaml(traefikDynamic(routes, options))}`;\n}\n\n/** The edge's static configuration file. */\nexport function traefikStaticFile(ports: EdgePorts): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n${yaml(traefikStatic(ports))}`;\n}\n\n/** The edge's compose file. */\nexport function edgeComposeFile(\n\toptions: Parameters<typeof edgeCompose>[0],\n): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n#\n# Started by the first stack that runs with proxy: 'traefik', and left\n# running by gkm compose --down. Stop it, once nothing uses it, with:\n#\n# docker compose -p ${EDGE_PROJECT} -f ${options.dir}/docker-compose.yml down\n${yaml(edgeCompose(options))}`;\n}\n\nfunction yaml(value: unknown): string {\n\treturn stringify(value, { lineWidth: 0, aliasDuplicateObjects: false });\n}\n","/**\n * The server's shared Traefik edge, on disk and in Docker: started when a\n * stack needs it, and each stack's routes written to — and removed from —\n * the directory it watches.\n *\n * The edge lives in the deploy user's gkm home (`$GKM_HOME/edge`, else\n * `~/.gkm/edge`): the user who runs `gkm compose` owns it, so nothing needs\n * root, and it sits beside the stage keys that same user already keeps.\n *\n * ~/.gkm/edge/\n * docker-compose.yml the edge's compose project (gkm-edge)\n * traefik.yml its static configuration\n * dynamic/<project>.yml one per stack: its routers, services, middlewares\n * certs/<project>.crt|.key a stack's own certificate, where it has one\n */\n\nimport { existsSync } from 'node:fs';\nimport {\n\tchmod,\n\tcopyFile,\n\tmkdir,\n\treadFile,\n\trename,\n\trm,\n\twriteFile,\n} from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { gkmHome } from '../home.js';\nimport type { ComposeDocker, PortHolder, StackRef } from './docker.js';\nimport type { ComposeProxy } from './routes.js';\nimport {\n\tEDGE_NETWORK,\n\tEDGE_PROJECT,\n\tEDGE_SERVICE,\n\ttype EdgePorts,\n\tedgeComposeFile,\n\ttraefikStaticFile,\n} from './traefik.js';\n\n/** The edge's directory on this machine. */\nexport function edgeDir(env: NodeJS.ProcessEnv = process.env): string {\n\treturn join(gkmHome(env), 'edge');\n}\n\n/** The edge's compose project, as docker is asked about it. */\nexport function edgeRef(\n\tdir: string,\n\toptions: Pick<StackRef, 'output' | 'signal'> = {},\n): StackRef {\n\treturn {\n\t\tproject: EDGE_PROJECT,\n\t\tfile: join(dir, 'docker-compose.yml'),\n\t\tcwd: dir,\n\t\t...options,\n\t};\n}\n\n/**\n * Something other than the proxy a stack is set to holds the edge's ports.\n *\n * With `proxy: 'traefik'`, the stack's own Caddy — still running from before\n * the switch — or any other container; with `proxy: 'caddy'`, the shared\n * edge, or another stack's Caddy. Refused before anything is started, so the\n * stack is never left half on one proxy and half on the other.\n */\nexport class ComposeProxyClash extends Error {\n\tconstructor(\n\t\treadonly project: string,\n\t\treadonly proxy: ComposeProxy,\n\t\treadonly port: number,\n\t\treadonly holder: PortHolder,\n\t) {\n\t\tconst by = holder.project\n\t\t\t? `${holder.container} (compose project ${holder.project})`\n\t\t\t: holder.container;\n\t\tconst fix =\n\t\t\tproxy === 'traefik'\n\t\t\t\t? holder.project === project && holder.service === 'caddy'\n\t\t\t\t\t? `That is this stack's own Caddy, from before it was switched to proxy: 'traefik'. Move it once: stop it (docker compose -p ${project} stop caddy), then run gkm compose again — the shared edge takes 80/443 and the stack registers with it.`\n\t\t\t\t\t: `The shared edge needs ports 80 and 443. Stop ${holder.container}${holder.project ? ` (docker compose -p ${holder.project} down, or its own gkm compose --down)` : ''}, or move the edge with GKM_COMPOSE_HTTPS_PORT/GKM_COMPOSE_HTTP_PORT.`\n\t\t\t\t: holder.project === EDGE_PROJECT\n\t\t\t\t\t? `That is the server's shared Traefik edge, which other stacks register with. Set deploy.compose.proxy to 'traefik' for this stage so the stack registers with it too, or stop the edge once nothing uses it (docker compose -p ${EDGE_PROJECT} down).`\n\t\t\t\t\t: `Stop ${holder.container}, or publish this stack's Caddy elsewhere with GKM_COMPOSE_HTTPS_PORT/GKM_COMPOSE_HTTP_PORT.`;\n\t\tsuper(\n\t\t\t`${project} is set to proxy: '${proxy}', and port ${port} is held by ${by}. ${fix}`,\n\t\t);\n\t\tthis.name = 'ComposeProxyClash';\n\t}\n}\n\n/**\n * Refuse a stack whose edge ports are held by anything but its own proxy:\n * the shared edge for `'traefik'`, the stack's own Caddy for `'caddy'`.\n */\nexport async function assertEdgePorts(\n\tdocker: ComposeDocker,\n\toptions: { project: string; proxy: ComposeProxy; ports: EdgePorts },\n): Promise<void> {\n\tconst { project, proxy, ports } = options;\n\tfor (const port of [ports.https, ports.http]) {\n\t\tfor (const holder of await docker.publishers(port)) {\n\t\t\tconst own =\n\t\t\t\tproxy === 'traefik'\n\t\t\t\t\t? holder.project === EDGE_PROJECT\n\t\t\t\t\t: holder.project === project && holder.service === 'caddy';\n\t\t\tif (!own) throw new ComposeProxyClash(project, proxy, port, holder);\n\t\t}\n\t}\n}\n\n/** Write a file whole or not at all: a temporary file, then a rename. */\nasync function writeAtomic(\n\tpath: string,\n\tcontent: string,\n\tmode = 0o644,\n): Promise<void> {\n\t// Not `.yml`: the edge reads only `.yml`, `.yaml` and `.toml` files, so it\n\t// never sees one half written.\n\tconst temporary = `${path}.${process.pid}.tmp`;\n\tawait writeFile(temporary, content, { mode });\n\tawait chmod(temporary, mode);\n\tawait rename(temporary, path);\n}\n\n/** Write a file only when its content changed; whether it did. */\nasync function writeIfChanged(path: string, content: string): Promise<boolean> {\n\tconst current = await readFile(path, 'utf-8').catch(() => undefined);\n\tif (current === content) return false;\n\tawait writeAtomic(path, content);\n\treturn true;\n}\n\n/**\n * The edge, up: its network, its files, and its container — started when it\n * is not running, and recreated when its configuration changed. Idempotent:\n * on a server where it already runs as configured, `up` changes nothing.\n */\nexport async function ensureEdge(\n\tdocker: ComposeDocker,\n\toptions: {\n\t\tdir: string;\n\t\tports: EdgePorts;\n\t\tlogging: { driver: string; options: Record<string, string> };\n\t\toutput?: StackRef['output'];\n\t\tsignal?: AbortSignal;\n\t},\n): Promise<string[]> {\n\tconst { dir, ports } = options;\n\tawait mkdir(join(dir, 'dynamic'), { recursive: true });\n\tawait mkdir(join(dir, 'certs'), { recursive: true, mode: 0o700 });\n\n\tconst staticConfig = traefikStaticFile(ports);\n\tawait writeIfChanged(join(dir, 'traefik.yml'), staticConfig);\n\tawait writeIfChanged(\n\t\tjoin(dir, 'docker-compose.yml'),\n\t\tedgeComposeFile({ dir, ports, staticConfig, logging: options.logging }),\n\t);\n\n\tawait docker.ensureNetwork(EDGE_NETWORK);\n\tawait docker.up(\n\t\tedgeRef(dir, {\n\t\t\t...(options.output ? { output: options.output } : {}),\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t}),\n\t\t[EDGE_SERVICE],\n\t);\n\treturn [join(dir, 'traefik.yml'), join(dir, 'docker-compose.yml')];\n}\n\n/** A stack's file in the edge's directory. */\nexport function routesFile(dir: string, project: string): string {\n\treturn join(dir, 'dynamic', `${project}.yml`);\n}\n\n/**\n * Register a stack with the edge: its certificate first, where it has one,\n * so the routes that need it never load without it — then its routes, in one\n * rename the edge picks up whole.\n */\nexport async function writeEdgeRoutes(\n\tdir: string,\n\tproject: string,\n\troutes: string,\n\tcertificate?: { certFile: string; keyFile: string },\n): Promise<string[]> {\n\tconst files: string[] = [];\n\tif (certificate) {\n\t\tconst certs = join(dir, 'certs');\n\t\tawait mkdir(certs, { recursive: true, mode: 0o700 });\n\t\tconst crt = join(certs, `${project}.crt`);\n\t\tconst key = join(certs, `${project}.key`);\n\t\tawait copyFile(certificate.certFile, `${crt}.tmp`);\n\t\tawait rename(`${crt}.tmp`, crt);\n\t\tawait copyFile(certificate.keyFile, `${key}.tmp`);\n\t\tawait chmod(`${key}.tmp`, 0o600);\n\t\tawait rename(`${key}.tmp`, key);\n\t\tfiles.push(crt, key);\n\t} else {\n\t\tawait removeCertificate(dir, project);\n\t}\n\tawait mkdir(join(dir, 'dynamic'), { recursive: true });\n\tconst file = routesFile(dir, project);\n\tawait writeAtomic(file, routes);\n\tfiles.push(file);\n\treturn files;\n}\n\n/** What a stack's file holds for the moment between emptying and removal. */\nconst UNREGISTERED = '# Unregistered by gkm compose --down.\\n';\n\nasync function removeCertificate(dir: string, project: string): Promise<void> {\n\tfor (const ext of ['crt', 'key']) {\n\t\tawait rm(join(dir, 'certs', `${project}.${ext}`), { force: true });\n\t}\n}\n\n/**\n * Unregister a stack: its routes, then its certificate. Whether there was\n * anything to remove.\n */\nexport async function removeEdgeRoutes(\n\tdir: string,\n\tproject: string,\n): Promise<boolean> {\n\tconst file = routesFile(dir, project);\n\tconst existed = existsSync(file);\n\tif (existed) {\n\t\t// Emptied by a rename before it is removed. A watcher that misses the\n\t\t// removal — Docker Desktop's file sharing can drop a delete event —\n\t\t// has still seen the stack's routes go.\n\t\tawait writeAtomic(file, UNREGISTERED);\n\t}\n\tawait rm(file, { force: true });\n\tawait removeCertificate(dir, project);\n\treturn existed;\n}\n","/**\n * Which image each app runs — and, for a tag, whether every one exists.\n *\n * A tag is a release's identity: `--tag=v1.4.0` means the images CI pushed as\n * v1.4.0, and nothing else. So a stack is never half rolled out: every app's\n * image is asked of the registry before anything is pulled or the running\n * stack is touched, and one missing image stops the whole run naming every\n * one that is missing. Nor is a missing image quietly built instead — a build\n * of whatever is checked out here is not the release the tag names.\n */\n\nimport type { ComposeDocker } from './docker';\n\n/** One app's image, as the stack runs it. */\nexport interface AppImage {\n\tapp: string;\n\tref: string;\n\ttag: string;\n}\n\n/**\n * The tag a site's image carries for a release.\n *\n * A site's public URLs are inlined when it is built, so one bundle serves one\n * stage: `v1.4.0-production` and `v1.4.0-staging` are two images of the same\n * commit. A backend reads its URLs at runtime, so one image serves every stage\n * and its tag is the release's alone.\n */\nexport function siteTag(tag: string, stage: string): string {\n\treturn `${tag}-${stage}`;\n}\n\n/** Images a tag names that the registry does not have. */\nexport class ImageTagNotFound extends Error {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly refs: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The registry has no image for ${refs.length === 1 ? 'this app' : `${refs.length} apps`} at '${tag}':\\n` +\n\t\t\t\trefs.map((ref) => ` - ${ref}`).join('\\n') +\n\t\t\t\t`\\nNothing was pulled or started. Push '${tag}' for every app from CI, ` +\n\t\t\t\t`pick a tag that exists, or run without --tag to build from this checkout.`,\n\t\t);\n\t\tthis.name = 'ImageTagNotFound';\n\t}\n}\n\n/** The registry did not answer, or did not let this machine in. */\nexport class RegistryUnreachable extends Error {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask the registry about ${ref}: ${detail || 'no answer'}\\n` +\n\t\t\t\t`Nothing was pulled or started. Check the registry is reachable and ` +\n\t\t\t\t`that this machine is logged in to it (\\`docker login <registry>\\`).`,\n\t\t);\n\t\tthis.name = 'RegistryUnreachable';\n\t}\n}\n\n/**\n * Assert every image exists, before anything else happens.\n *\n * Asked all at once and reported all at once: a release missing two images is\n * one problem with two names, and finding the second only after fixing the\n * first is a slower way to learn the same thing.\n *\n * @throws {RegistryUnreachable} when the registry cannot say\n * @throws {ImageTagNotFound} listing every missing image\n */\nexport async function assertImagesExist(\n\tdocker: Pick<ComposeDocker, 'lookup'>,\n\ttag: string,\n\timages: readonly AppImage[],\n): Promise<void> {\n\tconst lookups = await Promise.all(\n\t\timages.map((image) => docker.lookup(image.ref)),\n\t);\n\n\tconst unreachable = lookups.find((lookup) => lookup.status === 'unreachable');\n\tif (unreachable?.status === 'unreachable') {\n\t\tthrow new RegistryUnreachable(unreachable.ref, unreachable.detail);\n\t}\n\n\tconst missing = lookups\n\t\t.filter((lookup) => lookup.status === 'missing')\n\t\t.map((lookup) => lookup.ref);\n\tif (missing.length > 0) throw new ImageTagNotFound(tag, missing);\n}\n\n/**\n * A push or a pull with no `deploy.registry` to push to or pull from.\n *\n * Without one an image is named `<namespace>/<project>-<app>:<tag>`, which\n * Docker resolves to Docker Hub — so a release would be pushed to, or pulled\n * from, somebody else's account. It is never a fallback.\n */\nexport class RegistryRequired extends Error {\n\tconstructor(\n\t\t/** What needed the registry: `--push`, or a pull (`--tag`/`--pull`). */\n\t\treadonly operation: 'push' | 'pull',\n\t\t/** The ref an image would have had: a Docker Hub name. */\n\t\treadonly ref: string,\n\t) {\n\t\tsuper(\n\t\t\t`${operation === 'push' ? 'Pushing' : 'Pulling'} images needs a registry, and gkm.config.ts sets no deploy.registry: ` +\n\t\t\t\t`'${ref}' would be ${operation === 'push' ? 'pushed to' : 'pulled from'} Docker Hub. ` +\n\t\t\t\t`Set deploy.registry (e.g. registry: 'ghcr.io/acme') in gkm.config.ts.` +\n\t\t\t\t(operation === 'pull'\n\t\t\t\t\t? ' To run images built here instead, pass --build.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'RegistryRequired';\n\t}\n}\n\n/**\n * What a push reports, and what a pull can pin to: each app's image as\n * `<ref>@sha256:…` — the tag it was pushed as, and the exact image, whatever\n * that tag is later moved to.\n */\nexport type ImageDigests = Record<string, string>;\n\n/** An image pinned to its digest: `<ref>@sha256:…`. */\nexport function pinnedRef(ref: string, digest: string): string {\n\treturn `${ref.split('@')[0]}@${digest}`;\n}\n\n/** A digests file with no entry for an app the stack runs. */\nexport class ImageDigestMissing extends Error {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly apps: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${file} pins no digest for ${apps.join(', ')}. Use the file the ` +\n\t\t\t\t`same release's \\`gkm compose --build --push --digests-file\\` wrote, ` +\n\t\t\t\t`or run without --digests-file to pull by tag.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMissing';\n\t}\n}\n\n/** A digests file entry that is not this app's image. */\nexport class ImageDigestMismatch extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly expected: string,\n\t\treadonly found: string,\n\t) {\n\t\tsuper(\n\t\t\t`The digests file pins '${app}' to ${found}, but this release runs ` +\n\t\t\t\t`${expected}. It was written for another registry, project, stage ` +\n\t\t\t\t`or tag; use the file this stage's push of this tag wrote.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMismatch';\n\t}\n}\n\n/** A digests file that is not a JSON object of app to pinned ref. */\nexport class ImageDigestsInvalid extends Error {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`${file} is not a digests file (${detail}). It should be the JSON ` +\n\t\t\t\t`object \\`gkm compose --build --push --digests-file\\` writes: ` +\n\t\t\t\t`{ \"api\": \"<registry>/<image>:<tag>@sha256:…\" }.`,\n\t\t);\n\t\tthis.name = 'ImageDigestsInvalid';\n\t}\n}\n\n/** Parse a digests file's content, checking its shape. */\nexport function parseDigests(file: string, content: string): ImageDigests {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new ImageDigestsInvalid(\n\t\t\tfile,\n\t\t\terror instanceof Error ? error.message : String(error),\n\t\t);\n\t}\n\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\tthrow new ImageDigestsInvalid(file, 'not a JSON object');\n\t}\n\tfor (const [app, value] of Object.entries(parsed)) {\n\t\tif (typeof value !== 'string' || !/@sha256:[0-9a-f]{64}$/.test(value)) {\n\t\t\tthrow new ImageDigestsInvalid(\n\t\t\t\tfile,\n\t\t\t\t`'${app}' is not an <image>:<tag>@sha256:… ref`,\n\t\t\t);\n\t\t}\n\t}\n\treturn parsed as ImageDigests;\n}\n\n/**\n * Each image pinned to the digest the file names for it.\n *\n * @throws {ImageDigestMissing} naming every app the file has no entry for\n * @throws {ImageDigestMismatch} when an entry is another image or tag\n */\nexport function pinImages<T extends AppImage>(\n\tfile: string,\n\tdigests: ImageDigests,\n\timages: readonly T[],\n): T[] {\n\tconst missing = images\n\t\t.filter((image) => !digests[image.app])\n\t\t.map((image) => image.app);\n\tif (missing.length > 0) throw new ImageDigestMissing(file, missing);\n\n\treturn images.map((image) => {\n\t\tconst pinned = digests[image.app]!;\n\t\tif (pinned.split('@')[0] !== image.ref) {\n\t\t\tthrow new ImageDigestMismatch(image.app, image.ref, pinned);\n\t\t}\n\t\treturn { ...image, ref: pinned };\n\t});\n}\n","/**\n * The stack's log UI: OpenObserve, run beside the apps when\n * `deploy.compose.logs` asks for it, and every backend's OpenTelemetry\n * pointed at it.\n *\n * The production server already exports its traces and pino logs over\n * OTLP/HTTP when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. OpenObserve takes OTLP\n * at `/api/<org>/v1/{logs,traces}` with HTTP basic auth, so wiring an app is\n * two variables: the endpoint, `http://openobserve:5080/api/default`, and\n * the header that signs in as the root user.\n *\n * It is reached, by default, through an SSH tunnel: published on 127.0.0.1\n * only, because a port Docker publishes on every interface is opened in the\n * firewall by Docker itself, past ufw's rules. Served publicly, it is a host\n * on the stack's Caddy that refuses every address not allowed.\n *\n * Pure: the stack decides it, and the phases print and check it.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { isOtlpDestination } from '../deploy/otel.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport { LOGS_PORT, type ResolvedLogs } from './logsConfig.js';\nimport type { StackService } from './stack.js';\n\n/**\n * The image, pinned. A log store's on-disk format is the thing that must not\n * move under a running stack, so a new version is a change to this line.\n */\nexport const OPENOBSERVE_IMAGE = 'public.ecr.aws/zinclabs/openobserve:v1.0.4';\n\n/** Its compose service name — the host the apps send to. */\nexport const LOGS_SERVICE = 'openobserve';\n\n/** The organisation every app's telemetry lands in. */\nexport const LOGS_ORG = 'default';\n\n/** The stage secrets that sign in as OpenObserve's root user. */\nexport const LOGS_EMAIL_KEY = 'ZO_ROOT_USER_EMAIL';\nexport const LOGS_PASSWORD_KEY = 'ZO_ROOT_USER_PASSWORD';\n\n/**\n * The local stage's root login: fixed, as its Postgres password is. It meets\n * OpenObserve's password rules, which a weaker one would not.\n */\nexport const LOCAL_LOGS_EMAIL = 'admin@gkm.localhost';\nexport const LOCAL_LOGS_PASSWORD = 'Geekmidas-1';\n\n/** The stack's OpenObserve, as the stack runs it. */\nexport interface StackLogs extends ResolvedLogs {\n\t/** The root user's email and password. */\n\temail: string;\n\tpassword: string;\n\t/** Whether the stage's secrets set the password, rather than a default. */\n\tpasswordFromSecrets: boolean;\n\t/** Where a browser opens it: the tunnel's end, or its public host. */\n\turl: string;\n\t/** Its public host, when it is served through Caddy. */\n\thost?: string;\n\t/** Its own environment, written to `openobserve.env` (0600). */\n\tenv: Record<string, string>;\n\t/** What every backend is handed to send its telemetry here. */\n\tappEnv: {\n\t\tOTEL_EXPORTER_OTLP_ENDPOINT: string;\n\t\tOTEL_EXPORTER_OTLP_HEADERS: string;\n\t};\n}\n\n/** The stage sends its telemetry somewhere already, and logs are on too. */\nexport class LogsEndpointConflict extends Error {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly keys: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' sets ${keys.join(', ')} in its secrets, and ` +\n\t\t\t\t'deploy.compose.logs also runs OpenObserve for it — each backend can ' +\n\t\t\t\t'send its telemetry to one place. Either keep your own OTLP backend: ' +\n\t\t\t\t'remove logs from deploy.compose in gkm.config.ts; or use the ' +\n\t\t\t\t`bundled OpenObserve: remove ${keys.join(', ')} from the stage's ` +\n\t\t\t\t'secrets, and every backend is pointed at it.',\n\t\t);\n\t\tthis.name = 'LogsEndpointConflict';\n\t}\n}\n\n/** A root password OpenObserve would refuse to start with. */\nexport class LogsPasswordWeak extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' sets ${LOGS_PASSWORD_KEY}, and OpenObserve refuses ` +\n\t\t\t\t'it: a root password must be 8 to 128 characters with a lowercase ' +\n\t\t\t\t'letter, an uppercase letter, a digit and a symbol. Set another with ' +\n\t\t\t\t`gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}, or unset ` +\n\t\t\t\t'it to have one generated.',\n\t\t);\n\t\tthis.name = 'LogsPasswordWeak';\n\t}\n}\n\n/** A deployed stage with logs on and no root password generated yet. */\nexport class LogsPasswordMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' runs OpenObserve and has no ${LOGS_PASSWORD_KEY} ` +\n\t\t\t\t`in its secrets. Run gkm compose --stage ${stage} without --dry-run ` +\n\t\t\t\t'once to generate it, or set one: ' +\n\t\t\t\t`gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'LogsPasswordMissing';\n\t}\n}\n\n/** Whether OpenObserve accepts `password` for its root user. */\nexport function isStrongLogsPassword(password: string): boolean {\n\treturn (\n\t\tpassword.length >= 8 &&\n\t\tpassword.length <= 128 &&\n\t\t/[a-z]/.test(password) &&\n\t\t/[A-Z]/.test(password) &&\n\t\t/\\d/.test(password) &&\n\t\t/[^A-Za-z0-9]/.test(password)\n\t);\n}\n\n/**\n * A root password: 192 random bits, with a fixed tail so every class\n * OpenObserve requires is present whatever the random part drew.\n */\nexport function generateLogsPassword(): string {\n\treturn `${randomBytes(24).toString('base64url')}-Zo1`;\n}\n\n/**\n * The stage's secrets with a generated root password, where it has none.\n * Pure, like `withGeneratedSecrets`: the caller keeps the result once the\n * run goes ahead.\n */\nexport function withLogsPassword(secrets: StageSecrets): {\n\tsecrets: StageSecrets;\n\tgenerated: string[];\n} {\n\tif (secrets.custom?.[LOGS_PASSWORD_KEY]) return { secrets, generated: [] };\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tcustom: {\n\t\t\t\t...secrets.custom,\n\t\t\t\t[LOGS_PASSWORD_KEY]: generateLogsPassword(),\n\t\t\t},\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tgenerated: [LOGS_PASSWORD_KEY],\n\t};\n}\n\n/**\n * `OTEL_EXPORTER_OTLP_HEADERS` signing in as `email`.\n *\n * The variable's values are percent-decoded by the SDK (they follow the W3C\n * baggage format), so the space after `Basic` is written `%20`. Base64's own\n * `+`, `/` and `=` pass through decoding unchanged.\n */\nexport function otlpHeaders(email: string, password: string): string {\n\tconst token = Buffer.from(`${email}:${password}`).toString('base64');\n\treturn `Authorization=Basic%20${token}`;\n}\n\n/** The stack's OpenObserve for one stage. */\nexport function stackLogs(options: {\n\tconfig: ResolvedLogs;\n\tstage: string;\n\tlocal: boolean;\n\t/** The workspace's name: the local stage's public host is under it. */\n\tproject: string;\n\tdomain?: string;\n\tcustom: Readonly<Record<string, string>>;\n\t/** The edge's HTTPS port, which a local public URL carries. */\n\thttps: number;\n}): StackLogs {\n\tconst { config, stage, local, custom } = options;\n\n\tconst conflicting = Object.keys(custom).filter(isOtlpDestination).sort();\n\tif (conflicting.length > 0) {\n\t\tthrow new LogsEndpointConflict(stage, conflicting);\n\t}\n\n\tif (!local && !options.domain) throw new NoDomainForStage(stage);\n\n\tconst email =\n\t\tcustom[LOGS_EMAIL_KEY] ??\n\t\t(local ? LOCAL_LOGS_EMAIL : `admin@${options.domain}`);\n\tconst set = custom[LOGS_PASSWORD_KEY];\n\tif (!set && !local) throw new LogsPasswordMissing(stage);\n\tconst password = set ?? LOCAL_LOGS_PASSWORD;\n\tif (!isStrongLogsPassword(password)) throw new LogsPasswordWeak(stage);\n\n\tconst host = config.public\n\t\t? local\n\t\t\t? `logs.${options.project}.localhost`\n\t\t\t: `logs.${options.domain}`\n\t\t: undefined;\n\tconst url = host\n\t\t? `https://${host}${local && options.https !== 443 ? `:${options.https}` : ''}`\n\t\t: `http://localhost:${config.port}`;\n\n\treturn {\n\t\t...config,\n\t\temail,\n\t\tpassword,\n\t\tpasswordFromSecrets: Boolean(set),\n\t\turl,\n\t\t...(host ? { host } : {}),\n\t\tenv: {\n\t\t\t[LOGS_EMAIL_KEY]: email,\n\t\t\t[LOGS_PASSWORD_KEY]: password,\n\t\t\tZO_DATA_DIR: '/data',\n\t\t\t// Verified against the image: days, and it refuses fewer than 3.\n\t\t\tZO_COMPACT_DATA_RETENTION_DAYS: String(config.retentionDays),\n\t\t\t// A self-hosted log store on a stage's box does not report home.\n\t\t\tZO_TELEMETRY: 'false',\n\t\t},\n\t\tappEnv: {\n\t\t\tOTEL_EXPORTER_OTLP_ENDPOINT: `http://${LOGS_SERVICE}:${LOGS_PORT}/api/${LOGS_ORG}`,\n\t\t\tOTEL_EXPORTER_OTLP_HEADERS: otlpHeaders(email, password),\n\t\t},\n\t};\n}\n\n/**\n * OpenObserve's service. The image has no shell, `wget` or `curl`, so its\n * health check is its own binary asking the running server for its status —\n * which exits non-zero when nothing answers on its port.\n */\nexport function logsService(logs: StackLogs): StackService {\n\treturn {\n\t\timage: OPENOBSERVE_IMAGE,\n\t\trestart: 'unless-stopped',\n\t\tenv_file: [{ path: `./${LOGS_SERVICE}.env`, format: 'raw' }],\n\t\tvolumes: ['openobserve-data:/data'],\n\t\t// Loopback only: Docker opens a port it publishes on every interface in\n\t\t// the firewall itself, past ufw. Served publicly, Caddy is the way in.\n\t\t...(logs.public ? {} : { ports: [`127.0.0.1:${logs.port}:${LOGS_PORT}`] }),\n\t\thealthcheck: {\n\t\t\ttest: ['CMD', '/openobserve', 'node', 'status'],\n\t\t\tinterval: '10s',\n\t\t\ttimeout: '5s',\n\t\t\tretries: 12,\n\t\t\tstart_period: '20s',\n\t\t},\n\t};\n}\n\n/** Where to guess the stack is reached from, for the printed tunnel. */\nexport interface LogsAccessContext {\n\tstage: string;\n\tlocal: boolean;\n\t/** This machine's user and name — the best guess at the SSH target. */\n\tuser: string;\n\thostname: string;\n}\n\n/** What `gkm compose` prints once the stack is up: how to open the logs. */\nexport function logsAccess(logs: StackLogs, ctx: LogsAccessContext): string[] {\n\tconst login = `login: ${logs.email}, password: ${\n\t\tctx.local && !logs.passwordFromSecrets\n\t\t\t? logs.password\n\t\t\t: `gkm secrets:show --stage ${ctx.stage} --reveal → ${LOGS_PASSWORD_KEY}`\n\t}`;\n\n\tif (logs.public) {\n\t\treturn [\n\t\t\t`📜 Logs (OpenObserve): ${logs.url} (${login})`,\n\t\t\t` answered only for ${logs.public.allow.join(', ')}; every other address gets 403`,\n\t\t];\n\t}\n\n\treturn [\n\t\t`📜 Logs (OpenObserve) on 127.0.0.1:${logs.port} — from your computer:`,\n\t\t// The local stage usually runs where you are; it can run on a box too.\n\t\t...(ctx.local\n\t\t\t? [\n\t\t\t\t\t` on this machine, open http://localhost:${logs.port} directly; from another:`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t` ssh -N -L ${logs.port}:localhost:${logs.port} ${ctx.user}@${ctx.hostname} (user and host are guesses: this machine's)`,\n\t\t` then open http://localhost:${logs.port} (${login})`,\n\t\t`⚠️ Docker-published ports bypass ufw, so OpenObserve is bound to 127.0.0.1 only — reach it through the tunnel, not by opening the port.`,\n\t];\n}\n","/**\n * The stack's Redis: what every declared cache lives in when a workspace runs\n * as a `gkm compose` stack, on the local stage and on a deployed one alike.\n *\n * A cache is the one store whose contents can always be rebuilt, so unlike\n * Mailpit and MinIO it is a production service, not a dev stand-in: it runs\n * for every stage, on the compose network only, with nothing published. It\n * is bounded (`maxmemory`, evicting the least recently used key), persisted\n * (an append-only file on a named volume, kept by `--down`) and password\n * protected — the stage's own password, generated once like its seed.\n *\n * A stage that sets a cache's URL in its secrets — a managed Redis — keeps\n * it, and a stack whose every cache is set that way runs no Redis at all.\n *\n * Pure: the stack decides it, and the phases keep the password.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { DEFAULT_IMAGES } from '../reconcile/containers.js';\nimport type { Plan } from '../reconcile/plan.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport type { CacheBackend } from '../types.js';\nimport type { StackService } from './stack.js';\n\n/**\n * Where a stack's caches live: its own Redis, whatever the deploy target's\n * default is. A stack is one machine running containers, and a Redis beside\n * the apps is cheaper for a cache than a table in the database they share.\n */\nexport const STACK_CACHE: CacheBackend = 'redis';\n\n/** Its compose service name — the host every cache URL points at. */\nexport const REDIS_SERVICE = 'redis';\n\n/** The port it answers on, inside the network. */\nexport const REDIS_PORT = 6379;\n\n/** Reconcile's pin, so `gkm dev` and the stack run one Redis. */\nexport const REDIS_IMAGE = DEFAULT_IMAGES.redis!;\n\n/**\n * How much it may hold before it evicts. A cache that grows until the box\n * runs out of memory takes the apps with it; 256 MB is a lot of sessions and\n * little of a small server. A project's `docker-compose.<stage>.yml` can\n * replace the command to change it.\n */\nexport const REDIS_MAXMEMORY = '256mb';\n\n/** The stage secret holding its password. */\nexport const REDIS_PASSWORD_KEY = 'REDIS_PASSWORD';\n\n/** The local stage's password: fixed, as its Postgres password is. */\nexport const LOCAL_REDIS_PASSWORD = 'geekmidas';\n\n/** Redis's own count of logical databases, before `--databases` raises it. */\nconst REDIS_DATABASES = 16;\n\n/** A deployed stage that runs the stack's Redis and has no password yet. */\nexport class RedisPasswordMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' runs the stack's Redis and has no ` +\n\t\t\t\t`${REDIS_PASSWORD_KEY} in its secrets. Run gkm compose --stage ` +\n\t\t\t\t`${stage} without --dry-run once to generate it, or set one: ` +\n\t\t\t\t`gkm secrets:set ${REDIS_PASSWORD_KEY} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'RedisPasswordMissing';\n\t}\n}\n\n/** The stack's Redis, as the stack runs it. */\nexport interface StackRedis {\n\tpassword: string;\n\t/** Whether the stage's secrets set the password, rather than the local one. */\n\tpasswordFromSecrets: boolean;\n\t/** Each cache it holds: its URL key, and the URL. */\n\turls: Record<string, string>;\n\t/** Its own environment, written to `redis.env` (0600). */\n\tenv: Record<string, string>;\n\t/** How many logical databases it keeps — one per cache, at least 16. */\n\tdatabases: number;\n}\n\n/**\n * Whether a stage's stack runs Redis: a cache is declared and the stage's\n * secrets do not set the URL of every one.\n */\nexport function runsRedis(\n\tmanifest: ConstructManifest,\n\tcustom: Readonly<Record<string, string>>,\n): boolean {\n\treturn Object.values(manifest).some(\n\t\t(declaration) =>\n\t\t\tdeclaration?.kind === 'cache' &&\n\t\t\t(declaration.provides ?? []).some((key) => custom[key] === undefined),\n\t);\n}\n\n/** A password: 256 random bits, URL-safe, so it sits in a URL unescaped. */\nexport function generateRedisPassword(): string {\n\treturn randomBytes(32).toString('base64url');\n}\n\n/**\n * The stage's secrets with a generated Redis password, where it has none.\n * Pure, like `withGeneratedSecrets`: the caller keeps the result once the run\n * goes ahead.\n */\nexport function withRedisPassword(secrets: StageSecrets): {\n\tsecrets: StageSecrets;\n\tgenerated: string[];\n} {\n\tif (secrets.custom?.[REDIS_PASSWORD_KEY]) return { secrets, generated: [] };\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tcustom: {\n\t\t\t\t...secrets.custom,\n\t\t\t\t[REDIS_PASSWORD_KEY]: generateRedisPassword(),\n\t\t\t},\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tgenerated: [REDIS_PASSWORD_KEY],\n\t};\n}\n\n/**\n * The stack's Redis for one stage, or nothing where no cache needs it.\n *\n * Each cache it holds gets a logical database of its own, by the order of\n * their ids, so two caches never read each other's keys.\n */\nexport function stackRedis(options: {\n\tplan: Plan;\n\tstage: string;\n\tlocal: boolean;\n\tcustom: Readonly<Record<string, string>>;\n}): StackRedis | undefined {\n\tconst { plan, stage, local, custom } = options;\n\n\tconst caches = plan.resources\n\t\t.filter((r) => r.kind === 'cache' && custom[r.envKey] === undefined)\n\t\t.sort((a, b) => a.id.localeCompare(b.id));\n\tif (caches.length === 0) return undefined;\n\n\tconst set = custom[REDIS_PASSWORD_KEY];\n\tif (!set && !local) throw new RedisPasswordMissing(stage);\n\tconst password = set ?? LOCAL_REDIS_PASSWORD;\n\tconst auth = encodeURIComponent(password);\n\n\treturn {\n\t\tpassword,\n\t\tpasswordFromSecrets: Boolean(set),\n\t\turls: Object.fromEntries(\n\t\t\tcaches.map((cache, index) => [\n\t\t\t\tcache.envKey,\n\t\t\t\t`redis://:${auth}@${REDIS_SERVICE}:${REDIS_PORT}/${index}`,\n\t\t\t]),\n\t\t),\n\t\tenv: {\n\t\t\t// What the server is started with, by name: the command reads it\n\t\t\t// from the environment, so the value is never in its arguments.\n\t\t\t[REDIS_PASSWORD_KEY]: password,\n\t\t\t// What `redis-cli` signs in with — the health check's, and anyone's\n\t\t\t// who execs into the container — without `-a` on a command line.\n\t\t\tREDISCLI_AUTH: password,\n\t\t},\n\t\tdatabases: Math.max(REDIS_DATABASES, caches.length),\n\t};\n}\n\n/**\n * Redis's service: bounded, persisted and password protected, on the\n * network alone.\n *\n * The command runs the image's own entrypoint with `redis-server` first, so\n * it still drops to the `redis` user and owns `/data`; the password is read\n * from the env file by the shell (`$$` is compose's escape for `$`), so\n * neither the compose file nor the container's command holds it.\n */\nexport function redisService(redis: StackRedis): StackService {\n\tconst flags = [\n\t\t`--requirepass \"$$${REDIS_PASSWORD_KEY}\"`,\n\t\t`--maxmemory ${REDIS_MAXMEMORY}`,\n\t\t'--maxmemory-policy allkeys-lru',\n\t\t'--appendonly yes',\n\t\t...(redis.databases > REDIS_DATABASES\n\t\t\t? [`--databases ${redis.databases}`]\n\t\t\t: []),\n\t];\n\treturn {\n\t\timage: REDIS_IMAGE,\n\t\trestart: 'unless-stopped',\n\t\tcommand: [\n\t\t\t'sh',\n\t\t\t'-c',\n\t\t\t`exec docker-entrypoint.sh redis-server ${flags.join(' ')}`,\n\t\t],\n\t\tenv_file: [{ path: `./${REDIS_SERVICE}.env`, format: 'raw' }],\n\t\tvolumes: ['redis-data:/data'],\n\t\thealthcheck: {\n\t\t\t// `redis-cli` signs in with REDISCLI_AUTH; an unauthenticated ping\n\t\t\t// answers NOAUTH, which is not PONG.\n\t\t\ttest: ['CMD-SHELL', 'redis-cli ping | grep -q PONG'],\n\t\t\tinterval: '5s',\n\t\t\ttimeout: '3s',\n\t\t\tretries: 10,\n\t\t},\n\t};\n}\n","/**\n * The stack's own edge, rendered for Caddy: one site block per route.\n *\n * Deployed, each host is the stage's real domain and Caddy gets it a\n * certificate from Let's Encrypt on first request — the same automatic HTTPS\n * it does anywhere, with nothing to configure but the name — or serves the\n * stage's own certificate (`deploy.compose.tls`). Locally the hosts are\n * `*.localhost` and the certificates come from Caddy's own CA, as the `gkm\n * dev` edge does, so a local stack is `https://` like a deployed one.\n *\n * Pure: the routes are data (`routes.ts`), and rendering them is one string.\n */\n\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/** Where Caddy reads a stage's own certificate, inside its container. */\nexport const CADDY_TLS_DIR = '/etc/caddy/tls';\n\nexport interface CaddyfileOptions {\n\ttls: EdgeTls;\n\t/** Where ACME sends expiry notices, when someone wants them. */\n\temail?: string;\n}\n\n/** An upstream on the stack's own network: its service name. */\nfunction address({ service, port }: Upstream): string {\n\treturn `${service}:${port}`;\n}\n\n/** The Caddyfile for a stack's edge. */\nexport function edgeCaddyfile(\n\troutes: readonly EdgeRoute[],\n\toptions: CaddyfileOptions,\n): string {\n\tconst { tls } = options;\n\tconst global =\n\t\ttls.kind === 'internal'\n\t\t\t? `{\n\t# No ACME and no public DNS: the CA is Caddy's own and the names resolve\n\t# to this machine.\n\tlocal_certs\n\tauto_https disable_redirects\n}`\n\t\t\t: options.email\n\t\t\t\t? `{\n\temail ${options.email}\n}`\n\t\t\t\t: '';\n\n\tconst certificate =\n\t\ttls.kind === 'internal'\n\t\t\t? `\n\ttls internal\n`\n\t\t\t: tls.kind === 'files'\n\t\t\t\t? `\n\ttls ${tls.certFile} ${tls.keyFile}\n`\n\t\t\t\t: '';\n\n\tconst blocks = routes.map(\n\t\t({\n\t\t\thost,\n\t\t\tupstreams,\n\t\t\tprefix,\n\t\t\tallow,\n\t\t\tstreaming,\n\t\t}) => `https://${host} {${certificate}${\n\t\t\tallow\n\t\t\t\t? `\n\t# Only these addresses — the peer Caddy sees, never a header a client\n\t# could set. Everything else is refused before it reaches the upstream.\n\t@denied not remote_ip ${allow.join(' ')}\n\trespond @denied 403\n`\n\t\t\t\t: ''\n\t\t}${\n\t\t\tprefix\n\t\t\t\t? `\n\t# A bucket, served at a host of its own: the bucket is a prefix on MinIO,\n\t# which routes and signs on the Host header — so it is sent the upstream's.\n\treverse_proxy ${upstreams.map(address).join(' ')} {\n\t\trewrite ${prefix}{uri}\n\t\theader_up Host {upstream_hostport}\n\t}`\n\t\t\t\t: `\n\t# Host and X-Forwarded-* are passed through as Caddy does by default, so\n\t# an app builds redirects, cookies and links on the address a caller used.\n\treverse_proxy ${upstreams.map(address).join(' ')}${\n\t\tstreaming\n\t\t\t? ` {\n\t\t# Never buffer: a streamed response — server-sent events, a Next.js\n\t\t# RSC payload — reaches the client as each chunk is written.\n\t\tflush_interval -1\n\t}`\n\t\t\t: ''\n\t}`\n\t\t}\n}`,\n\t);\n\n\t// No blank line under the header: `caddy fmt` wants the first block there.\n\treturn `${HEADER}${global ? `${global}\\n\\n` : ''}${blocks.join('\\n\\n')}\\n`;\n}\n\nconst HEADER = `# Generated by gkm compose from the construct manifest — do not edit.\n#\n# One host per API and site, each in front of its own container, one per\n# file server in front of the stack's MinIO, and — when its logs are served\n# publicly — one for OpenObserve, to the addresses it allows.\n`;\n","/**\n * The stack a workspace runs as for one stage — pure.\n *\n * Everything `gkm compose` writes is decided here, as data: the compose file,\n * the Caddyfile, one env file per backend, and the image each app runs. The\n * command around it reads the workspace, asks the registry, writes the files\n * and starts Docker; none of those decide anything, so all of it can be\n * asserted without a daemon.\n *\n * The values come from the same derivations every other target uses. The\n * plan is reconcile's `planFor`, the keys an app reads are `appEnvKeys`, and\n * every URL is `envFor`'s — asked twice, once with each app at its public\n * address and once on the compose network, because a browser and a sibling\n * service reach the same API by different names.\n */\n\nimport { join } from 'node:path';\nimport {\n\ttype ConstructManifest,\n\tprovideKey,\n\tprovisionOrder,\n\tpublicEnvFor,\n} from '@geekmidas/manifest';\nimport { type WorkerUnit, workerUnits } from '../build/workers.js';\nimport {\n\tassertExternalServices,\n\ttype DevService,\n\ttype DevServiceUse,\n\tdevServicesUsed,\n\ttype ExternalServices,\n\ttype ServiceDeclaration,\n\tsuppliedOnly,\n} from '../deploy/devServices.js';\nimport { isMainFrontendApp, resolveHost } from '../deploy/domain.js';\nimport { type DeployIdentity, imageRef } from '../deploy/identity.js';\nimport { otelEnv } from '../deploy/otel.js';\nimport { validateImageRef } from '../docker/imageRef.js';\nimport { appDockerfile, workerDockerfile } from '../docker/index.js';\nimport { composeBuildPaths, type ImageLayout } from '../docker/layout.js';\nimport { TURBO_VERSION, WORKER_PORT } from '../docker/templates.js';\nimport { appEnvKeys, networkEnv, workerEnvKeys } from '../reconcile/apps.js';\nimport { hostFor } from '../reconcile/caddyfile.js';\nimport { type ComposeService, composeFor } from '../reconcile/compose.js';\nimport { DEFAULT_IMAGES, portKeys } from '../reconcile/containers.js';\nimport { localRolePassword } from '../reconcile/env.js';\nimport { type Plan, type PlannedResource, planFor } from '../reconcile/plan.js';\nimport { bucketPolicies } from '../reconcile/provision.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport { DEFAULT_EVENTS } from '../types.js';\nimport { appKey } from '../workspace/derive.js';\nimport type {\n\tComposeTlsConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../workspace/types.js';\nimport { CADDY_TLS_DIR, edgeCaddyfile } from './caddyfile.js';\nimport { type AppImage, siteTag } from './images.js';\nimport {\n\tLOGS_SERVICE,\n\tlogsService,\n\ttype StackLogs,\n\tstackLogs,\n} from './logs.js';\nimport { LOGS_PORT, resolveLogs } from './logsConfig.js';\nimport { certificateFor, proxyFor } from './proxy.js';\nimport {\n\tREDIS_SERVICE,\n\tredisService,\n\tSTACK_CACHE,\n\ttype StackRedis,\n\tstackRedis,\n} from './redis.js';\nimport type { ComposeProxy, EdgeRoute, EdgeTls } from './routes.js';\nimport {\n\tEDGE_NETWORK,\n\tedgeAlias,\n\tedgeCertificatePaths,\n\ttraefikDynamicFile,\n} from './traefik.js';\n\n/** Where a stack's files are written, relative to the workspace root. */\nexport function stackDir(stage: string): string {\n\treturn `.gkm/compose/${stage}`;\n}\n\n/**\n * The compose project a stage's stack runs as.\n *\n * The deploy identity's scope, so two workspaces with one name in different\n * namespaces never share containers or volumes — and the stage, so a\n * machine can run two stages side by side.\n */\nexport function composeProject(identity: DeployIdentity): string {\n\treturn `${identity.scope}-${identity.stage}`;\n}\n\n/** The ports the edge is published on, and the variables that move them. */\nexport const EDGE_PORT_ENV = {\n\thttps: 'GKM_COMPOSE_HTTPS_PORT',\n\thttp: 'GKM_COMPOSE_HTTP_PORT',\n} as const;\n\n/**\n * Containers this target does not run.\n *\n * The AWS emulator never applies: a stack is a server target, whose events\n * are pg-boss. Reconcile's Caddy fronts `gkm dev`'s host processes; the stack\n * brings its own edge.\n *\n * MinIO and Mailpit run on the local stage always, and on a deployed stage\n * only where `--allow-dev-services` allowed them and its secrets configure no\n * real bucket or mail server — see `devServices.ts`.\n */\nconst NOT_RUN: Readonly<Record<string, true>> = {\n\tlocalstack: true,\n\tcaddy: true,\n};\n\n/** The kinds a deployed stage takes from its secrets, or a dev service. */\nconst SERVICE_KINDS: Readonly<Record<string, ServiceDeclaration['kind']>> = {\n\temail: 'email',\n\tobjects: 'objects',\n\t'file-server': 'file-server',\n};\n\n/** The region MinIO is addressed with. It has no regions; the SDK wants one. */\nconst MINIO_REGION = 'us-east-1';\n\n/** The S3 client's credentials, read beside a bucket's URL when it has them. */\nconst STORAGE_KEYS = [\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_REGION',\n] as const;\n\n/**\n * Every service's Docker logs, rotated. The json-file driver keeps a\n * container's output in one file that grows until the disk is full — on a\n * small server, in weeks. Three files of 10 MB each per container is enough\n * to see what happened and never fills anything. A project's own override\n * file that sets `logging` wins over it.\n */\nexport const LOG_ROTATION = {\n\tdriver: 'json-file',\n\toptions: { 'max-size': '10m', 'max-file': '3' },\n} as const;\n\n/** Each image's build, where the stack builds rather than pulls. */\nexport interface AppBuild {\n\t/** Where the Dockerfile is written, relative to the workspace root. */\n\tdockerfile: string;\n\t/** A site's public URLs, inlined by its bundler. */\n\targs?: Record<string, string>;\n}\n\n/** One app in the stack. */\nexport interface StackApp extends AppImage {\n\t/** Its compose service name — the app key, `api`. */\n\tname: string;\n\t/** The construct it serves. */\n\tid: string;\n\tkind: 'rest-api' | 'site';\n\t/** Its directory, relative to the workspace root. */\n\tpath: string;\n\tport: number;\n\t/** The host the edge answers it on. */\n\thost: string;\n\t/** `https://<host>` — with the edge's port where it is not 443. */\n\turl: string;\n\tbuild?: AppBuild;\n\t/** A backend's environment, exactly the keys it reads. Absent for a site. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A Worker in the stack: its crons, queue consumers and subscribers in a\n * container of their own. Nothing routes to it and nothing is published —\n * its one route is the health check Docker asks.\n */\nexport interface StackWorker extends AppImage {\n\t/** Its compose service name — `jobs`. */\n\tname: string;\n\t/** The Worker construct. */\n\tid: string;\n\t/** The app whose build writes its entry, which its image is built from. */\n\thost: string;\n\t/** Where its health check answers, inside the container. */\n\tport: number;\n\tbuild?: AppBuild;\n\t/** Exactly the keys the worker's constructs read. */\n\tenv?: Record<string, string>;\n}\n\n/** A service as the stack's compose file defines it. */\nexport interface StackService {\n\timage: string;\n\tbuild?: {\n\t\tcontext: string;\n\t\tdockerfile: string;\n\t\targs?: Record<string, string>;\n\t};\n\trestart?: string;\n\tcommand?: string | string[];\n\tenv_file?: { path: string; format: 'raw' }[];\n\tenvironment?: Record<string, string>;\n\tports?: string[];\n\tvolumes?: string[];\n\tdepends_on?: Record<string, { condition: 'service_healthy' }>;\n\thealthcheck?: ComposeService['healthcheck'];\n\t/**\n\t * Behind the shared edge, a public service is on the stack's own network\n\t * and the edge's, by an alias unique on both.\n\t */\n\tnetworks?: Record<string, { aliases: string[] }>;\n\tlogging?: {\n\t\tdriver: string;\n\t\toptions: Record<string, string>;\n\t};\n}\n\nexport interface StackFile {\n\tname: string;\n\tservices: Record<string, StackService>;\n\tvolumes: Record<string, Record<string, never>>;\n\t/** The shared edge's network, which the stack joins but never creates. */\n\tnetworks?: Record<string, { name: string; external: true }>;\n}\n\nexport interface ComposeStack {\n\tproject: string;\n\tstage: string;\n\t/** The project's local stage, served with Caddy's internal CA. */\n\tlocal: boolean;\n\tapps: StackApp[];\n\t/** Each Worker with background work, in a container of its own. */\n\tworkers: StackWorker[];\n\t/** The infrastructure containers, by compose service name. */\n\tinfra: string[];\n\tcompose: StackFile;\n\t/**\n\t * What serves the stack: its own Caddy, or the server's shared Traefik\n\t * edge (`deploy.compose.proxy`). The local stage is always Caddy.\n\t */\n\tproxy: ComposeProxy;\n\t/** Every public host and what answers it — what either proxy renders. */\n\troutes: EdgeRoute[];\n\t/** The stack's own Caddy's configuration — with `proxy: 'caddy'`. */\n\tcaddyfile?: string;\n\t/**\n\t * What the stack registers with the shared edge — with `proxy:\n\t * 'traefik'`: the dynamic configuration file written to its directory.\n\t */\n\ttraefik?: string;\n\t/**\n\t * The stage's own certificate and key, on this machine\n\t * (`deploy.compose.tls`) — copied to where the proxy reads it.\n\t */\n\ttls?: ComposeTlsConfig;\n\t/** Generated Dockerfiles, by path relative to the workspace root. */\n\tdockerfiles: Record<string, string>;\n\t/** The plan the stack was derived from — what provisioning creates. */\n\tplan: Plan;\n\t/** The Postgres master's password, and the seed role passwords take. */\n\tcredential: { master: string; seed?: string };\n\t/**\n\t * The stack's MinIO, where it runs one: its root credential — what the\n\t * backends sign with — and the buckets and open paths provisioning\n\t * creates in it.\n\t */\n\tstorage?: StackStorage;\n\t/** The dev services a deployed stage runs (`--allow-dev-services`). */\n\tdevServices: DevServiceUse[];\n\t/**\n\t * The stack's OpenObserve, when `deploy.compose.logs` runs one — every\n\t * backend sends its logs and traces to it.\n\t */\n\tlogs?: StackLogs;\n\t/**\n\t * The stack's Redis, where a declared cache lives in it — every cache\n\t * whose URL the stage's secrets do not set.\n\t */\n\tredis?: StackRedis;\n}\n\n/** The stack's MinIO, and what is created in it. */\nexport interface StackStorage {\n\tuser: string;\n\tpassword: string;\n\t/** Each bucket's stage-scoped name. */\n\tbuckets: string[];\n\t/** The open paths of each served bucket. */\n\tpolicies: { bucket: string; open: string[] }[];\n}\n\nexport interface StackInput {\n\tworkspace: NormalizedWorkspace;\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/**\n\t * Each Worker's crons', queues' and subscribers' files, from discovery —\n\t * which workers run, and which app each is built from.\n\t */\n\tbackground?: Readonly<Record<string, readonly string[]>>;\n\tstage: string;\n\tidentity: DeployIdentity;\n\timages: {\n\t\tmode: 'build' | 'pull';\n\t\t/** A release tag, or — building — the commit. */\n\t\ttag: string;\n\t\tregistry?: string;\n\t};\n\t/** The stage's secrets — set by hand, and what a deployed stage generated. */\n\tsecrets?: StageSecrets | null;\n\t/**\n\t * The dev services a deployed stage may run for mail and buckets its\n\t * secrets do not configure. The local stage runs both regardless.\n\t */\n\tallowDevServices?: readonly DevService[];\n\t/** The edge's published ports. 443 and 80 by default. */\n\tports?: { https?: number; http?: number };\n\t/**\n\t * The stack only builds its images, to push them (`--build --push`): no\n\t * backend's or worker's runtime environment is resolved and no service\n\t * reads an env file, so building needs none of the stage's backend\n\t * secrets. A site's build args — its public URLs — are still resolved.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * For builds: where the images are built from and with what — the build\n\t * root, its package manager and turbo. The workspace's root, with pnpm,\n\t * when not given.\n\t */\n\tlayout?: ImageLayout;\n}\n\n/** A value only the stage's secrets can hold, and they do not. */\nexport class StageSecretMissing extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${app}' reads ${key}, and the stage '${stage}' has none. Nothing in ` +\n\t\t\t\t`the stack can derive it; set it in the stage's secrets: ` +\n\t\t\t\t`gkm secrets:set ${key} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'StageSecretMissing';\n\t}\n}\n\n/** A deployed stage's secrets with no seed to derive its passwords from. */\nexport class StageSeedMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' has no seed in its secrets, and a deployed stage's ` +\n\t\t\t\t`database passwords are derived from it. Run gkm compose --stage ${stage} ` +\n\t\t\t\t`without --dry-run once, or gkm deploy, to generate it.`,\n\t\t);\n\t\tthis.name = 'StageSeedMissing';\n\t}\n}\n\n/** A workspace with no API and no site to run. */\nexport class NothingToCompose extends Error {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`${root} declares no RestApi, no site and no Worker with work to do, ` +\n\t\t\t\t`so a stack would run nothing. Mobile apps ship through their own ` +\n\t\t\t\t`toolchain.`,\n\t\t);\n\t\tthis.name = 'NothingToCompose';\n\t}\n}\n\n/** A value that cannot be written to an env file a line at a time. */\nexport class EnvValueMultiline extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t) {\n\t\tsuper(\n\t\t\t`${key} for '${app}' spans more than one line, and an env file holds ` +\n\t\t\t\t`one value per line. Store it on one line — base64, or JSON — and ` +\n\t\t\t\t`decode it where it is read.`,\n\t\t);\n\t\tthis.name = 'EnvValueMultiline';\n\t}\n}\n\n/** The services a stack's apps wait on and the edge waits on in turn. */\nconst HEALTHY = { condition: 'service_healthy' } as const;\n\n/**\n * An app's health check: its own server, asked on 127.0.0.1 — not\n * `localhost`, which resolves to `::1` first in an Alpine container while a\n * server may listen on IPv4 alone.\n */\nfunction probe(port: number, path: string): StackService['healthcheck'] {\n\treturn {\n\t\ttest: [\n\t\t\t'CMD',\n\t\t\t'wget',\n\t\t\t'-q',\n\t\t\t'-O',\n\t\t\t'/dev/null',\n\t\t\t`http://127.0.0.1:${port}${path}`,\n\t\t],\n\t\tinterval: '5s',\n\t\ttimeout: '3s',\n\t\tretries: 20,\n\t\tstart_period: '10s',\n\t};\n}\n\n/** The stack for one stage. */\nexport function composeStack(input: StackInput): ComposeStack {\n\tconst { workspace, manifest, stage, identity } = input;\n\tconst local = stage === workspace.stages.local;\n\tconst project = composeProject(identity);\n\tconst custom = input.secrets?.custom ?? {};\n\tconst https = input.ports?.https ?? 443;\n\tconst http = input.ports?.http ?? 80;\n\tconst proxy = proxyFor(workspace.deploy?.compose, stage, local);\n\tconst certificate = local\n\t\t? undefined\n\t\t: certificateFor(workspace.deploy?.compose, stage, workspace.root);\n\n\t// A server target's backends, whatever `deploy.default` says: the stack is\n\t// one machine running containers, so events are pg-boss beside the\n\t// declared database — and every cache, one declared from that database\n\t// included, is in the stack's own Redis.\n\tconst plan = planFor(manifest, stage, provisionOrder(manifest), {\n\t\tlocalStage: workspace.stages.local,\n\t\tevents: DEFAULT_EVENTS.server,\n\t\tcache: STACK_CACHE,\n\t\t// The stack brings its own edge; reconcile's would front the host.\n\t\tedge: false,\n\t});\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tconst seed = local ? undefined : input.secrets?.seed;\n\tif (!local && !seed) throw new StageSeedMissing(stage);\n\tconst credential = {\n\t\tmaster: local\n\t\t\t? 'geekmidas'\n\t\t\t: localRolePassword(workspace.name, plan, 'master', seed),\n\t\t...(seed ? { seed } : {}),\n\t};\n\n\tconst apps = stackApps(workspace, manifest, plan, {\n\t\tlocal,\n\t\tstage,\n\t\thttps,\n\t\tidentity,\n\t\timages: input.images,\n\t});\n\tconst workers = stackWorkers(\n\t\tworkerUnits(workspace, manifest, input.background ?? {}),\n\t\t{ stage, identity, images: input.images },\n\t);\n\tif (apps.length === 0 && workers.length === 0) {\n\t\tthrow new NothingToCompose(workspace.root);\n\t}\n\n\t// Which construct each key belongs to, so a key is resolved by what it is\n\t// rather than by its spelling.\n\tconst owners = new Map<string, PlannedResource>();\n\tfor (const resource of plan.resources) {\n\t\towners.set(resource.envKey, resource);\n\t\tif (resource.kind === 'email') {\n\t\t\towners.set(provideKey(resource.id, 'from'), resource);\n\t\t\towners.set(provideKey(resource.id, 'inboxUrl'), resource);\n\t\t}\n\t\tif (resource.kind === 'external-api') {\n\t\t\towners.set(provideKey(resource.id, 'credentials'), resource);\n\t\t}\n\t}\n\n\t// The keys each app reads: a backend's environment, and the keys a\n\t// site's build args rename.\n\tconst reads = new Map<string, string[]>();\n\tfor (const app of apps) {\n\t\tconst site = manifest[app.id];\n\t\treads.set(\n\t\t\tapp.name,\n\t\t\tsite?.kind === 'site'\n\t\t\t\t? Object.values(publicEnvFor(site, manifest))\n\t\t\t\t: [...(appEnvKeys(manifest, app.name, input.runnables) ?? [])],\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\treads.set(worker.name, [\n\t\t\t...(workerEnvKeys(manifest, worker.id, input.runnables) ?? []),\n\t\t]);\n\t}\n\tconst domain = workspace.deploy?.domains?.[stage];\n\n\t// The log UI, when the workspace asks for one: its root login, how it is\n\t// reached, and what each backend is handed to send to it.\n\tconst logsConfig = resolveLogs(workspace.deploy?.compose?.logs);\n\tconst logsBase = logsConfig\n\t\t? stackLogs({\n\t\t\t\tconfig: logsConfig,\n\t\t\t\tstage,\n\t\t\t\tlocal,\n\t\t\t\tproject: workspace.name,\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\tcustom,\n\t\t\t\thttps,\n\t\t\t})\n\t\t: undefined;\n\n\t// Mail and storage: the local stage runs Mailpit and MinIO for all of it.\n\t// A deployed stage takes each from its secrets — or, where allowed, from a\n\t// dev service — and one missing anything stops here, naming every key.\n\tconst services: ExternalServices = local\n\t\t? {\n\t\t\t\tmissing: [],\n\t\t\t\tminio: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'objects')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t\tmailpit: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'email')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t}\n\t\t: assertExternalServices({\n\t\t\t\tstage,\n\t\t\t\tdeclarations: serviceDeclarations(plan, reads, owners),\n\t\t\t\tsupplied: custom,\n\t\t\t\tallow: input.allowDevServices ?? [],\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t});\n\n\t// The caches: in the stack's Redis, unless the stage set a cache's URL —\n\t// a managed Redis — and with every one set, there is no Redis to run.\n\tconst redis = stackRedis({ plan, stage, local, custom });\n\n\tconst infra = [\n\t\t...plan.containers\n\t\t\t.filter((c) => !NOT_RUN[c])\n\t\t\t.filter((c) => c !== 'minio' || services.minio.length > 0)\n\t\t\t.filter((c) => c !== 'mailpit' || services.mailpit.length > 0)\n\t\t\t.filter((c) => c !== REDIS_SERVICE || redis !== undefined),\n\t\t...(logsBase ? [LOGS_SERVICE] : []),\n\t].sort();\n\n\t// The stack's MinIO signs with the stage's own key pair where it set one,\n\t// and otherwise with a credential derived like every other: the fixed\n\t// local one, or — deployed — from the stage's seed.\n\tconst storage: StackStorage | undefined = infra.includes('minio')\n\t\t? (() => {\n\t\t\t\tconst buckets = services.minio\n\t\t\t\t\t.map((id) => byId.get(id)?.name)\n\t\t\t\t\t.filter((name): name is string => Boolean(name))\n\t\t\t\t\t.sort();\n\t\t\t\treturn {\n\t\t\t\t\tuser:\n\t\t\t\t\t\tcustom.AWS_ACCESS_KEY_ID ??\n\t\t\t\t\t\t(local ? 'geekmidas' : `${workspace.name}-minio`),\n\t\t\t\t\tpassword:\n\t\t\t\t\t\tcustom.AWS_SECRET_ACCESS_KEY ??\n\t\t\t\t\t\t(local\n\t\t\t\t\t\t\t? 'geekmidas'\n\t\t\t\t\t\t\t: localRolePassword(workspace.name, plan, 'minio', seed)),\n\t\t\t\t\tbuckets,\n\t\t\t\t\tpolicies: bucketPolicies(plan).filter((p) =>\n\t\t\t\t\t\tbuckets.includes(p.bucket),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t})()\n\t\t: undefined;\n\n\t// Each file server over the stack's MinIO, at a host of its own on the\n\t// edge — the shape it has deployed: a domain serving a bucket.\n\tconst fileServers = new Map<string, { url: string; route: EdgeRoute }>();\n\tif (storage) {\n\t\tfor (const resource of plan.resources) {\n\t\t\tif (resource.kind !== 'file-server' || !resource.of) continue;\n\t\t\tif (!services.minio.includes(resource.of)) continue;\n\t\t\tif (custom[resource.envKey] !== undefined) continue;\n\t\t\tconst bucket = byId.get(resource.of);\n\t\t\tif (!bucket) continue;\n\n\t\t\tlet host: string;\n\t\t\tif (local) {\n\t\t\t\thost = hostFor(resource, workspace.name);\n\t\t\t} else {\n\t\t\t\tif (!domain) throw new NoDomainForStage(stage);\n\t\t\t\thost = `${resource.subdomain ?? appKey(resource.id)}.${domain}`;\n\t\t\t}\n\t\t\tfileServers.set(resource.id, {\n\t\t\t\turl: `https://${host}${local && https !== 443 ? `:${https}` : ''}`,\n\t\t\t\troute: {\n\t\t\t\t\tname: `files-${appKey(resource.id)}`,\n\t\t\t\t\thost,\n\t\t\t\t\tupstreams: [{ service: 'minio', port: 9000 }],\n\t\t\t\t\tstreaming: false,\n\t\t\t\t\tprefix: `/${bucket.name}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// Behind the shared edge, the services it routes to are on a network\n\t// every stack's public services share, where a bare name — `api` — would\n\t// be answered by each stack's. They are reached, from the edge and from\n\t// inside the stack alike, by an alias prefixed with the project.\n\tconst edgeServices = new Set(\n\t\tproxy === 'traefik'\n\t\t\t? [\n\t\t\t\t\t...apps.map((app) => app.name),\n\t\t\t\t\t...(fileServers.size > 0 ? ['minio'] : []),\n\t\t\t\t\t...(logsBase?.host && logsBase.public ? [LOGS_SERVICE] : []),\n\t\t\t\t]\n\t\t\t: [],\n\t);\n\tconst hostOf = (service: string) =>\n\t\tedgeServices.has(service) ? edgeAlias(project, service) : service;\n\tconst logs: StackLogs | undefined = logsBase && {\n\t\t...logsBase,\n\t\tappEnv: {\n\t\t\t...logsBase.appEnv,\n\t\t\tOTEL_EXPORTER_OTLP_ENDPOINT:\n\t\t\t\tlogsBase.appEnv.OTEL_EXPORTER_OTLP_ENDPOINT.replace(\n\t\t\t\t\t`//${LOGS_SERVICE}:`,\n\t\t\t\t\t`//${hostOf(LOGS_SERVICE)}:`,\n\t\t\t\t),\n\t\t},\n\t};\n\n\t// Every key the stage resolves, twice: with each app at its public address\n\t// — what a browser is handed, and what an app says it is — and with each on\n\t// the compose network, which is how one service reaches another.\n\tconst derivation = {\n\t\tproject: workspace.name,\n\t\tmaster: credential.master,\n\t\t...(credential.seed ? { seed: credential.seed } : {}),\n\t\t// Mailpit on a deployed stage sends as the stage's domain.\n\t\t...(!local && domain ? { mailFrom: `noreply@${domain}` } : {}),\n\t};\n\tconst outside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(apps.map((app) => [app.id, app.url])),\n\t\t},\n\t\thostOf,\n\t);\n\tconst inside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(\n\t\t\t\tapps.map((app) => [app.id, `http://${hostOf(app.name)}:${app.port}`]),\n\t\t\t),\n\t\t},\n\t\thostOf,\n\t);\n\n\tconst surfaceUrls = new Map(\n\t\tplan.resources\n\t\t\t.filter((r) => r.kind === 'rest-api' || r.kind === 'site')\n\t\t\t.map((r) => [r.envKey, r.id]),\n\t);\n\tconst appById = new Map(apps.map((app) => [app.id, app]));\n\n\t/**\n\t * What a key resolves to for one app, from the stage's secrets where only\n\t * they can hold it, and the derivations otherwise.\n\t */\n\tconst valueFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkey: string,\n\t\towner: PlannedResource | undefined,\n\t): string | undefined => {\n\t\t// Mail and storage: what the stage set — a real server, a real bucket —\n\t\t// and otherwise the dev service it runs, which `services` has already\n\t\t// checked it may.\n\t\tif (owner && SERVICE_KINDS[owner.kind]) {\n\t\t\tif (custom[key] !== undefined) return custom[key];\n\t\t\tif (owner.kind === 'file-server') return fileServers.get(owner.id)?.url;\n\t\t\treturn outside[key];\n\t\t}\n\n\t\t// Supplied by somebody: a third party's credentials, and — deployed —\n\t\t// the secrets the stage generated.\n\t\tif (owner && suppliedOnly(owner.kind, owner.id, key, local)) {\n\t\t\tconst value = custom[key];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new StageSecretMissing(app.name, key, stage);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// Set by hand wins over derived: it is the stage saying what it is.\n\t\tif (custom[key] !== undefined) return custom[key];\n\n\t\t// A cache, in the stack's Redis, by its name on the network.\n\t\tif (owner?.kind === 'cache') return redis?.urls[key];\n\n\t\t// A backend reaches a sibling surface on the compose network; its own\n\t\t// address is the public one, which is what it builds links on. A site\n\t\t// runs in a browser, which has only the public addresses.\n\t\tconst surface = surfaceUrls.get(key);\n\t\tif (app.kind === 'rest-api' && surface && surface !== app.id) {\n\t\t\treturn inside[key];\n\t\t}\n\n\t\treturn outside[key];\n\t};\n\n\t/** Each key one backend process reads, resolved for this stage. */\n\tconst valuesFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkeys: ReadonlySet<string>,\n\t): Record<string, string> => {\n\t\tconst values: Record<string, string> = {};\n\t\tfor (const key of [...keys].sort()) {\n\t\t\tconst owner = owners.get(key) ?? storageOwner(key, plan);\n\t\t\t// A deployed stage has no inbox: Mailpit runs only locally.\n\t\t\tif (!local && owner?.kind === 'email' && key.endsWith('_INBOX_URL'))\n\t\t\t\tcontinue;\n\t\t\tif ((STORAGE_KEYS as readonly string[]).includes(key)) {\n\t\t\t\t// The stage's own key pair where it set one — an external bucket\n\t\t\t\t// signs with it — and otherwise the stack's MinIO's.\n\t\t\t\tconst value = custom[key] ?? storageValue(key, storage);\n\t\t\t\tif (value !== undefined) values[key] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = valueFor(app, key, owner);\n\t\t\tif (value !== undefined) values[key] = value;\n\t\t}\n\t\treturn values;\n\t};\n\n\tfor (const app of apps) {\n\t\tif (app.kind === 'site') {\n\t\t\tconst site = manifest[app.id];\n\t\t\tif (site?.kind !== 'site') continue;\n\n\t\t\tconst args: Record<string, string> = {};\n\t\t\tfor (const [key, source] of Object.entries(\n\t\t\t\tpublicEnvFor(site, manifest),\n\t\t\t)) {\n\t\t\t\tconst value = valueFor(app, source, owners.get(source));\n\t\t\t\tif (value !== undefined) args[key] = value;\n\t\t\t}\n\t\t\tif (app.build && Object.keys(args).length > 0) app.build.args = args;\n\t\t\tcontinue;\n\t\t}\n\t\t// Built to be pushed, a backend's image is every stage's: what it reads\n\t\t// at runtime is the deploy's business, not the build's.\n\t\tif (input.buildOnly) continue;\n\n\t\tconst keys = appEnvKeys(manifest, app.name, input.runnables) ?? new Set();\n\t\tconst values = valuesFor(app, keys);\n\n\t\t// The origins Better Auth trusts are the browser's and, now, each\n\t\t// service that calls this surface across the compose network: its CSRF\n\t\t// check applies to every caller, and a sibling's request carries its\n\t\t// own origin, not a browser's.\n\t\tconst trusted = provideKey(app.id, 'trustedOrigins');\n\t\tif (keys.has(trusted)) {\n\t\t\tconst internal = (byId.get(app.id)?.callers ?? [])\n\t\t\t\t.map((caller) => appById.get(caller))\n\t\t\t\t.filter((caller): caller is StackApp => caller?.kind === 'rest-api')\n\t\t\t\t.map((caller) => `http://${hostOf(caller.name)}:${caller.port}`);\n\t\t\tconst origins = [\n\t\t\t\t...(values[trusted] ?? '').split(',').filter(Boolean),\n\t\t\t\t...internal,\n\t\t\t];\n\t\t\tvalues[trusted] = [...new Set(origins)].join(',');\n\t\t}\n\n\t\t// Telemetry: the stage's own `OTEL_*`, or the stack's OpenObserve.\n\t\tapp.env = {\n\t\t\t...values,\n\t\t\t...otelEnv({ ...custom, ...logs?.appEnv }, app.name),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(app.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\n\t\tfor (const [key, value] of Object.entries(app.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(app.name, key);\n\t\t}\n\t}\n\n\t// A worker reaches every surface across the compose network: it is never\n\t// one, so no address is its own.\n\tfor (const worker of input.buildOnly ? [] : workers) {\n\t\tconst keys =\n\t\t\tworkerEnvKeys(manifest, worker.id, input.runnables) ?? new Set();\n\t\tworker.env = {\n\t\t\t...valuesFor(\n\t\t\t\t{ name: worker.name, id: worker.id, kind: 'rest-api' },\n\t\t\t\tkeys,\n\t\t\t),\n\t\t\t...otelEnv({ ...custom, ...logs?.appEnv }, worker.name),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(worker.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(worker.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(worker.name, key);\n\t\t}\n\t}\n\n\t// A deployed stage's certificates: its own, where it set one, as the\n\t// proxy's container reads them — otherwise Let's Encrypt's.\n\tconst deployedTls: Exclude<EdgeTls, { kind: 'internal' }> = certificate\n\t\t? {\n\t\t\t\tkind: 'files',\n\t\t\t\t...(proxy === 'caddy'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcertFile: `${CADDY_TLS_DIR}/cert.pem`,\n\t\t\t\t\t\t\tkeyFile: `${CADDY_TLS_DIR}/key.pem`,\n\t\t\t\t\t\t}\n\t\t\t\t\t: edgeCertificatePaths(project)),\n\t\t\t}\n\t\t: { kind: 'acme' };\n\tconst tls: EdgeTls = local ? { kind: 'internal' } : deployedTls;\n\n\tconst layout = input.layout ?? defaultLayout(workspace.root);\n\tconst compose = stackFile({\n\t\tproject,\n\t\tplan,\n\t\tinfra,\n\t\tapps,\n\t\tworkers,\n\t\tmaster: credential.master,\n\t\t...(storage ? { storage } : {}),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\thttps,\n\t\thttp,\n\t\tcomposeDir: join(workspace.root, stackDir(stage)),\n\t\tbuildRoot: layout.buildRoot,\n\t\tworkspaceRoot: workspace.root,\n\t\tenvFiles: !input.buildOnly,\n\t\tproxy,\n\t\tedge: new Map(\n\t\t\t[...edgeServices].map((service) => [service, hostOf(service)]),\n\t\t),\n\t\ttls: certificate !== undefined,\n\t});\n\n\t// One route per public host — the data both proxies render.\n\tconst routes: EdgeRoute[] = [\n\t\t...apps.map(\n\t\t\t(app): EdgeRoute => ({\n\t\t\t\tname: app.name,\n\t\t\t\thost: app.host,\n\t\t\t\tupstreams: [{ service: app.name, port: app.port }],\n\t\t\t\tstreaming: true,\n\t\t\t\thealth: app.kind === 'site' ? '/' : '/health',\n\t\t\t}),\n\t\t),\n\t\t...[...fileServers.values()].map(({ route }) => route),\n\t\t...(logs?.host && logs.public\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: LOGS_SERVICE,\n\t\t\t\t\t\thost: logs.host,\n\t\t\t\t\t\tupstreams: [{ service: LOGS_SERVICE, port: LOGS_PORT }],\n\t\t\t\t\t\tstreaming: true,\n\t\t\t\t\t\tallow: logs.public.allow,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\tconst dockerfiles: Record<string, string> = {};\n\tfor (const app of apps) {\n\t\tif (!app.build) continue;\n\t\t// The same Dockerfile `gkm docker` writes: the image is built inside\n\t\t// Docker from a pruned slice of the build root, and nothing is built\n\t\t// here first.\n\t\tdockerfiles[app.build.dockerfile] = appDockerfile(\n\t\t\tapp.name,\n\t\t\tworkspace.apps[app.name]!,\n\t\t\t{\n\t\t\t\tlayout,\n\t\t\t\tworkspaceRoot: workspace.root,\n\t\t\t\tapps: workspace.apps,\n\t\t\t\tmanifest,\n\t\t\t\tcache: STACK_CACHE,\n\t\t\t},\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\tif (!worker.build) continue;\n\t\tdockerfiles[worker.build.dockerfile] = workerDockerfile(\n\t\t\t{ id: worker.id, name: worker.name, app: worker.host },\n\t\t\tworkspace.apps[worker.host]!,\n\t\t\t{ layout, workspaceRoot: workspace.root, cache: STACK_CACHE },\n\t\t);\n\t}\n\n\treturn {\n\t\tproject,\n\t\tstage,\n\t\tlocal,\n\t\tapps,\n\t\tworkers,\n\t\tinfra,\n\t\tcompose,\n\t\tproxy,\n\t\troutes,\n\t\t...(proxy === 'caddy'\n\t\t\t? { caddyfile: edgeCaddyfile(routes, { tls }) }\n\t\t\t: {\n\t\t\t\t\ttraefik: traefikDynamicFile(routes, {\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttls: deployedTls,\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t...(certificate ? { tls: certificate } : {}),\n\t\tdockerfiles,\n\t\tplan,\n\t\tcredential,\n\t\t...(storage ? { storage } : {}),\n\t\tdevServices: local ? [] : devServicesUsed(services),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t};\n}\n\n/**\n * The mail and storage constructs a deployed stage's apps read, with who\n * reads each — and every file server's bucket, which serves it whether or\n * not an app reads it directly.\n */\nfunction serviceDeclarations(\n\tplan: Plan,\n\treads: ReadonlyMap<string, readonly string[]>,\n\towners: ReadonlyMap<string, PlannedResource>,\n): ServiceDeclaration[] {\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\tconst readers = new Map<string, Set<string>>();\n\tconst add = (id: string, app?: string) => {\n\t\tconst set = readers.get(id) ?? new Set<string>();\n\t\tif (app) set.add(app);\n\t\treaders.set(id, set);\n\t};\n\n\tfor (const [app, keys] of reads) {\n\t\tfor (const key of keys) {\n\t\t\tconst owner = owners.get(key);\n\t\t\tif (!owner || !SERVICE_KINDS[owner.kind]) continue;\n\t\t\t// The inbox is Mailpit's own, never a deployed stage's to set.\n\t\t\tif (owner.kind === 'email' && key.endsWith('_INBOX_URL')) continue;\n\t\t\tadd(owner.id, app);\n\t\t\tif (owner.kind === 'file-server' && owner.of) add(owner.of);\n\t\t}\n\t}\n\n\treturn [...readers].flatMap(([id, apps]) => {\n\t\tconst resource = byId.get(id);\n\t\tconst kind = resource && SERVICE_KINDS[resource.kind];\n\t\tif (!resource || !kind) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tkind,\n\t\t\t\t...(resource.of ? { of: resource.of } : {}),\n\t\t\t\tapps: [...apps].sort(),\n\t\t\t},\n\t\t];\n\t});\n}\n\n/** The stack's MinIO's value for one of the S3 client's keys. */\nfunction storageValue(\n\tkey: string,\n\tstorage: StackStorage | undefined,\n): string | undefined {\n\tif (!storage) return undefined;\n\tif (key === 'AWS_ACCESS_KEY_ID') return storage.user;\n\tif (key === 'AWS_SECRET_ACCESS_KEY') return storage.password;\n\tif (key === 'AWS_REGION') return MINIO_REGION;\n\treturn undefined;\n}\n\n/** Which bucket an S3 credential key belongs to — the first one declared. */\nfunction storageOwner(key: string, plan: Plan): PlannedResource | undefined {\n\tif (!(STORAGE_KEYS as readonly string[]).includes(key)) return undefined;\n\treturn plan.resources.find((r) => r.kind === 'objects');\n}\n\n/** The apps a stack runs: every API and every site, at its stage address. */\nfunction stackApps(\n\tworkspace: NormalizedWorkspace,\n\tmanifest: ConstructManifest,\n\tplan: Plan,\n\toptions: {\n\t\tlocal: boolean;\n\t\tstage: string;\n\t\thttps: number;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackApp[] {\n\tconst apps: StackApp[] = [];\n\tconst resources = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'site')\n\t\t\tcontinue;\n\n\t\tconst name = appKey(id);\n\t\tconst app = workspace.apps[name];\n\t\tconst resource = resources.get(id);\n\t\tif (!app || !resource || !app.port) continue;\n\n\t\tconst host = hostOf(name, app, workspace, resource, options);\n\t\tconst site = declaration.kind === 'site';\n\t\tconst tag = site\n\t\t\t? siteTag(options.images.tag, options.stage)\n\t\t\t: options.images.tag;\n\t\tconst ref = validateImageRef(\n\t\t\timageRef(options.identity, name, options.images.registry, tag),\n\t\t);\n\n\t\tapps.push({\n\t\t\tapp: name,\n\t\t\tname,\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tpath: app.path,\n\t\t\tport: app.port,\n\t\t\thost,\n\t\t\turl: `https://${host}${options.local && options.https !== 443 ? `:${options.https}` : ''}`,\n\t\t\tref,\n\t\t\ttag,\n\t\t\t...(options.images.mode === 'build'\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${name}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\treturn apps.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Each worker's image, and where it is built from. */\nfunction stackWorkers(\n\tunits: readonly WorkerUnit[],\n\toptions: {\n\t\tstage: string;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackWorker[] {\n\treturn units.map((unit) => ({\n\t\tapp: unit.name,\n\t\tname: unit.name,\n\t\tid: unit.id,\n\t\thost: unit.app,\n\t\tport: WORKER_PORT,\n\t\tref: validateImageRef(\n\t\t\timageRef(\n\t\t\t\toptions.identity,\n\t\t\t\tunit.name,\n\t\t\t\toptions.images.registry,\n\t\t\t\toptions.images.tag,\n\t\t\t),\n\t\t),\n\t\ttag: options.images.tag,\n\t\t...(options.images.mode === 'build'\n\t\t\t? {\n\t\t\t\t\tbuild: {\n\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${unit.name}`,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\n/**\n * The host an app answers on for a stage: the `gkm dev` edge's\n * `*.localhost` names for the local stage, and the stage's domain — by the\n * same rule a deploy follows — for any other.\n */\nfunction hostOf(\n\tname: string,\n\tapp: NormalizedAppConfig,\n\tworkspace: NormalizedWorkspace,\n\tresource: PlannedResource,\n\toptions: { local: boolean; stage: string },\n): string {\n\tif (options.local) return hostFor(resource, workspace.name);\n\n\treturn resolveHost(\n\t\tname,\n\t\tapp,\n\t\toptions.stage,\n\t\tworkspace.deploy?.domains,\n\t\tisMainFrontendApp(name, app, workspace.apps),\n\t);\n}\n\n/** The compose document: the infrastructure, the apps, and the edge. */\nfunction stackFile(options: {\n\tproject: string;\n\tplan: Plan;\n\tinfra: readonly string[];\n\tapps: readonly StackApp[];\n\tworkers: readonly StackWorker[];\n\tmaster: string;\n\tstorage?: StackStorage;\n\tlogs?: StackLogs;\n\tredis?: StackRedis;\n\thttps: number;\n\thttp: number;\n\tcomposeDir: string;\n\tbuildRoot: string;\n\tworkspaceRoot: string;\n\t/** Whether services read env files — not in a stack that only builds. */\n\tenvFiles: boolean;\n\tproxy: ComposeProxy;\n\t/** Behind the shared edge: each service it routes to, and its alias. */\n\tedge: ReadonlyMap<string, string>;\n\t/** Whether the stage has its own certificate, which Caddy mounts. */\n\ttls: boolean;\n}): StackFile {\n\tconst { project, plan, apps } = options;\n\t// What reconcile defines; OpenObserve is the stack's own.\n\tconst infra = options.infra.filter((name) => name !== LOGS_SERVICE);\n\n\t// Reconcile's definitions — images, health checks, volumes — with nothing\n\t// published to the host. Ports are allocation's business there; here the\n\t// edge is the only way in.\n\tconst derived = composeFor(\n\t\t{ ...plan, containers: [...infra] },\n\t\t{\n\t\t\tproject,\n\t\t\tports: Object.fromEntries(\n\t\t\t\tportKeys(infra, plan.fakes).map((key) => [key, 0]),\n\t\t\t),\n\t\t},\n\t);\n\n\tconst services: Record<string, StackService> = {};\n\tconst volumes: Record<string, Record<string, never>> = {\n\t\t...derived.volumes,\n\t\t...(options.proxy === 'caddy'\n\t\t\t? { 'caddy-data': {}, 'caddy-config': {} }\n\t\t\t: {}),\n\t\t...(options.logs ? { 'openobserve-data': {} } : {}),\n\t};\n\n\tfor (const name of infra) {\n\t\tconst {\n\t\t\tports: _ports,\n\t\t\tdepends_on,\n\t\t\tprofiles: _profiles,\n\t\t\t...service\n\t\t} = derived.services[name]!;\n\t\tservices[name] = {\n\t\t\t...service,\n\t\t\t...(depends_on?.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tdepends_on.map((dep) => [dep, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tconst postgres = services.postgres;\n\tif (postgres) {\n\t\tpostgres.environment = {\n\t\t\t...postgres.environment,\n\t\t\tPOSTGRES_PASSWORD: options.master,\n\t\t};\n\t\t// Loopback only, on a port Docker picks: gkm creates the databases and\n\t\t// roles and runs the migrations from this machine, and nothing else\n\t\t// should reach the database from outside the stack.\n\t\tpostgres.ports = ['127.0.0.1::5432'];\n\t}\n\n\tconst minio = services.minio;\n\tif (minio && options.storage) {\n\t\tminio.environment = {\n\t\t\t...minio.environment,\n\t\t\tMINIO_ROOT_USER: options.storage.user,\n\t\t\tMINIO_ROOT_PASSWORD: options.storage.password,\n\t\t};\n\t\t// Loopback only, like Postgres: gkm creates the buckets and their\n\t\t// policies from this machine. The apps reach it on the network, and a\n\t\t// browser through a file server's host on the edge.\n\t\tminio.ports = ['127.0.0.1::9000'];\n\t}\n\n\t// Its own definition rather than reconcile's: `gkm dev`'s Redis is an\n\t// open, unbounded scratch store; this one is a production cache.\n\tif (services[REDIS_SERVICE] && options.redis) {\n\t\tservices[REDIS_SERVICE] = redisService(options.redis);\n\t}\n\n\t// Started with the infrastructure, but nothing waits on it: an app whose\n\t// telemetry cannot be delivered still serves.\n\tif (options.logs) services[LOGS_SERVICE] = logsService(options.logs);\n\n\tfor (const app of apps) {\n\t\tservices[app.name] = {\n\t\t\timage: app.ref,\n\t\t\t...(app.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\t...composeBuildPaths({\n\t\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\t\tdockerfile: app.build.dockerfile,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(app.build.args ? { args: app.build.args } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\t// A site is a bundle and reads nothing at runtime; a backend reads\n\t\t\t// exactly the keys in its own file.\n\t\t\t...(app.kind === 'rest-api'\n\t\t\t\t? {\n\t\t\t\t\t\tenv_file: [{ path: `./${app.name}.env`, format: 'raw' as const }],\n\t\t\t\t\t\t...(infra.length\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(app.port, app.kind === 'site' ? '/' : '/health'),\n\t\t};\n\t}\n\n\t// A worker: no route, no published port — its health check is Docker's.\n\tfor (const worker of options.workers) {\n\t\tservices[worker.name] = {\n\t\t\timage: worker.ref,\n\t\t\t...(worker.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: composeBuildPaths({\n\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\tdockerfile: worker.build.dockerfile,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\tenv_file: [{ path: `./${worker.name}.env`, format: 'raw' as const }],\n\t\t\t...(infra.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(worker.port, '/health'),\n\t\t};\n\t}\n\n\tif (options.proxy === 'caddy') {\n\t\tservices.caddy = {\n\t\t\timage: DEFAULT_IMAGES.caddy!,\n\t\t\trestart: 'unless-stopped',\n\t\t\tports: [`${options.https}:443`, `${options.http}:80`],\n\t\t\tvolumes: [\n\t\t\t\t'./Caddyfile:/etc/caddy/Caddyfile:ro',\n\t\t\t\t'caddy-data:/data',\n\t\t\t\t'caddy-config:/config',\n\t\t\t\t// The stage's own certificate, copied beside the Caddyfile.\n\t\t\t\t...(options.tls ? [`./tls:${CADDY_TLS_DIR}:ro`] : []),\n\t\t\t],\n\t\t\tdepends_on: Object.fromEntries(apps.map((app) => [app.name, HEALTHY])),\n\t\t\thealthcheck: {\n\t\t\t\ttest: ['CMD', 'caddy', 'version'],\n\t\t\t\tinterval: '10s',\n\t\t\t\ttimeout: '5s',\n\t\t\t\tretries: 5,\n\t\t\t},\n\t\t};\n\t}\n\n\t// Behind the shared edge: each service it routes to joins its network,\n\t// under the alias the edge reaches it by — and keeps the stack's own,\n\t// with the same alias, which is how the stack's services reach it too.\n\t// Everything else — the databases, Redis, the workers — stays off it.\n\tfor (const [service, alias] of options.edge) {\n\t\tconst definition = services[service];\n\t\tif (!definition) continue;\n\t\tdefinition.networks = {\n\t\t\tdefault: { aliases: [alias] },\n\t\t\tedge: { aliases: [alias] },\n\t\t};\n\t}\n\n\tfor (const service of Object.values(services)) {\n\t\tif (!options.envFiles) delete service.env_file;\n\t\tservice.logging = {\n\t\t\tdriver: LOG_ROTATION.driver,\n\t\t\toptions: { ...LOG_ROTATION.options },\n\t\t};\n\t}\n\n\treturn {\n\t\tname: project,\n\t\tservices,\n\t\tvolumes,\n\t\t...(options.edge.size > 0\n\t\t\t? { networks: { edge: { name: EDGE_NETWORK, external: true as const } } }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * A build without a layout: the workspace is the build root, with pnpm.\n * What a caller that never looked at the filesystem gets.\n */\nfunction defaultLayout(root: string): ImageLayout {\n\treturn {\n\t\tbuildRoot: root,\n\t\tgkmRoot: '.',\n\t\ttools: {\n\t\t\tpackageManager: 'pnpm',\n\t\t\tturboVersion: TURBO_VERSION,\n\t\t\tmonorepo: true,\n\t\t},\n\t\tgkmPaths: ['gkm.config.*'],\n\t};\n}\n\n/** Render an app's env file: one `KEY=value` per line, read raw by compose. */\nexport function envFile(env: Readonly<Record<string, string>>): string {\n\treturn `${Object.entries(env)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join('\\n')}\\n`;\n}\n","/**\n * Asking each app of a stack whether it answers — through Caddy, over HTTPS,\n * the way a browser reaches it.\n *\n * `docker compose up --wait` already knows each container passed its own\n * health check, asked on 127.0.0.1 inside it. What that cannot say is whether\n * the stack is reachable: whether the edge routes the host to the app, and\n * whether the certificate it presents is one a client accepts. So the check\n * goes through the edge, by hostname, and verifies the certificate.\n */\n\nimport { request } from 'node:https';\n\n/** One request to the edge. */\nexport interface HealthRequest {\n\t/** The app's public URL plus its health path. */\n\turl: string;\n\t/**\n\t * The certificate authority to verify against, PEM — Caddy's internal CA\n\t * on the local stage. The system's when absent.\n\t */\n\tca?: string;\n\t/**\n\t * Connect here instead of resolving the URL's host — the local edge, at\n\t * 127.0.0.1. The host is still sent as SNI and `Host`, so nothing depends\n\t * on how this machine resolves `*.localhost`.\n\t */\n\tconnectTo?: string;\n\t/**\n\t * With `connectTo`, the port to connect to, where it is not the URL's —\n\t * the shared edge's published port, asked for a deployed host.\n\t */\n\tconnectPort?: number;\n\ttimeoutMs: number;\n\tsignal?: AbortSignal;\n}\n\n/** Asks once, resolving with the HTTP status. Rejects when nothing answers. */\nexport type HealthProbe = (request: HealthRequest) => Promise<number>;\n\n/** A request that got no answer in time. */\nexport class HealthRequestTimedOut extends Error {\n\tconstructor(\n\t\treadonly url: string,\n\t\treadonly timeoutMs: number,\n\t) {\n\t\tsuper(\n\t\t\t`${url} did not answer within ${timeoutMs}ms. Check the stack is up with \\`docker compose ps\\`.`,\n\t\t);\n\t\tthis.name = 'HealthRequestTimedOut';\n\t}\n}\n\n/** The real probe: one HTTPS GET, the certificate verified. */\nexport const httpsProbe: HealthProbe = ({\n\turl,\n\tca,\n\tconnectTo,\n\tconnectPort,\n\ttimeoutMs,\n\tsignal,\n}) => {\n\tconst target = new URL(url);\n\treturn new Promise((resolve, reject) => {\n\t\tconst req = request(\n\t\t\t{\n\t\t\t\thost: connectTo ?? target.hostname,\n\t\t\t\tport: connectPort ?? (target.port || 443),\n\t\t\t\tservername: target.hostname,\n\t\t\t\tpath: `${target.pathname}${target.search}`,\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: { host: target.host },\n\t\t\t\t...(ca ? { ca } : {}),\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t\ttimeout: timeoutMs,\n\t\t\t},\n\t\t\t(res) => {\n\t\t\t\t// The status is the answer; the body is drained so the socket closes.\n\t\t\t\tres.resume();\n\t\t\t\tres.on('end', () => resolve(res.statusCode ?? 0));\n\t\t\t\tres.on('error', reject);\n\t\t\t},\n\t\t);\n\t\treq.on('timeout', () =>\n\t\t\treq.destroy(new HealthRequestTimedOut(url, timeoutMs)),\n\t\t);\n\t\treq.on('error', reject);\n\t\treq.end();\n\t});\n};\n\n/** Whether a status means the app answered as it should. */\nexport function isHealthy(status: number): boolean {\n\treturn status >= 200 && status < 400;\n}\n\n/** Apps that did not answer through the edge. */\nexport class ComposeAppsUnhealthy extends Error {\n\tconstructor(\n\t\treadonly project: string,\n\t\t/** Each app, and the last thing its check got: a status or an error. */\n\t\treadonly apps: readonly { app: string; url: string; last: string }[],\n\t\t/** The proxy they were asked through. */\n\t\treadonly proxy: 'caddy' | 'traefik' = 'caddy',\n\t) {\n\t\tconst names = apps.map((a) => a.app).join(' ');\n\t\tsuper(\n\t\t\t`${project} started, but ${apps.length === 1 ? 'this app does' : 'these apps do'} not answer through ${proxy === 'caddy' ? 'Caddy' : 'the shared Traefik edge'}:\\n` +\n\t\t\t\tapps.map(({ url, last }) => ` - ${url}: ${last}`).join('\\n') +\n\t\t\t\t(proxy === 'caddy'\n\t\t\t\t\t? `\\nSee why with \\`docker compose -p ${project} logs caddy ${names}\\`.`\n\t\t\t\t\t: `\\nSee why with \\`docker compose -p gkm-edge logs traefik\\` and \\`docker compose -p ${project} logs ${names}\\`.`),\n\t\t);\n\t\tthis.name = 'ComposeAppsUnhealthy';\n\t}\n}\n","/**\n * The compose target's phases: a stage as one Docker Compose stack behind\n * Caddy, on the machine the deploy runs on.\n *\n * The order is the point of this file, and the rules it keeps are these:\n *\n * - A tag is checked before anything happens (`validate`). Every app's image\n * is asked of the registry first; one missing image stops the run naming\n * them all, and nothing is written, pulled or started.\n * - The databases exist before the apps do (`provision`). Postgres comes up\n * alone, its databases, roles and grants are created and its migrations\n * applied from this machine, and only then do the apps start — so an app\n * never boots against a schema that is not there yet.\n * - What a stage runs is recorded (`release`). Each app's image, the tag it\n * was released under and the digest it resolved to are written to the\n * stage's state, so \"what is this stage running\" has an exact answer.\n * - What was started answers (`verify`): each app is asked through Caddy,\n * over HTTPS, with the certificate verified.\n *\n * Every image is built inside Docker from a pruned slice of the build root —\n * the same Dockerfiles `gkm docker` writes — so nothing is built on this\n * machine before `docker compose build`.\n *\n * Docker, the registry, Postgres and the health probe are\n * injected, so the rules are asserted without a daemon; the defaults are the\n * real ones.\n */\n\nimport { existsSync } from 'node:fs';\nimport {\n\tchmod,\n\tmkdir,\n\treaddir,\n\treadFile,\n\trm,\n\twriteFile,\n} from 'node:fs/promises';\nimport { hostname, userInfo } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { stringify } from 'yaml';\nimport {\n\ttype ComposeDocker,\n\tdockerCompose,\n\ttype StackRef,\n} from '../../compose/docker';\nimport {\n\tassertEdgePorts,\n\tedgeDir,\n\tensureEdge,\n\tremoveEdgeRoutes,\n\twriteEdgeRoutes,\n} from '../../compose/edge';\nimport {\n\tassertImagesExist,\n\ttype ImageDigests,\n\tpinImages,\n\tRegistryRequired,\n} from '../../compose/images';\nimport {\n\tLOGS_SERVICE,\n\tlogsAccess,\n\ttype StackLogs,\n\twithLogsPassword,\n} from '../../compose/logs';\nimport { resolveLogs } from '../../compose/logsConfig';\nimport { ComposeTlsFileMissing } from '../../compose/proxy';\nimport {\n\tREDIS_SERVICE,\n\trunsRedis,\n\twithRedisPassword,\n} from '../../compose/redis';\nimport {\n\ttype ComposeStack,\n\tcomposeProject,\n\tcomposeStack,\n\tEDGE_PORT_ENV,\n\tenvFile,\n\tLOG_ROTATION,\n\ttype StackApp,\n\tstackDir,\n} from '../../compose/stack';\nimport { EDGE_PROJECT, EDGE_SERVICE } from '../../compose/traefik';\nimport { reportDevServices } from '../../deploy/devServices';\nimport type { ResourceChange } from '../../deploy/events';\nimport { withGeneratedSecrets } from '../../deploy/generated.js';\nimport { imageRef } from '../../deploy/identity.js';\nimport { DeployJournal } from '../../deploy/journal';\nimport {\n\tcreateEmptyState,\n\ttype DeployedImage,\n\trecordRelease,\n} from '../../deploy/state.js';\nimport type { DeployResult } from '../../deploy/types';\nimport { ensureDockerignore } from '../../docker/index.js';\nimport { imageLayout } from '../../docker/layout.js';\nimport { findBuildRoot } from '../../docker/templates.js';\nimport { installedFrom } from '../../generators/drivers.js';\nimport { migrateDatabases } from '../../migrate/databases.js';\nimport { bucketClient, pgClient } from '../../reconcile/clients.js';\nimport { primaryPortKey } from '../../reconcile/containers.js';\nimport { type ConstructSource, discover } from '../../reconcile/discover.js';\nimport { envFor } from '../../reconcile/env.js';\nimport {\n\tapplyBuckets,\n\tapplyPolicies,\n\tapplyPostgres,\n\tpostgresStatements,\n} from '../../reconcile/provision.js';\nimport { constructGlobs } from '../../reconcile/workspace.js';\nimport { runOutput } from '../../run';\nimport { assertStageCredentials } from '../../secrets/credentialSchemas.js';\nimport { assertNoStaleSecrets } from '../../secrets/stale.js';\nimport { initStageSecrets } from '../../secrets/storage.js';\nimport type { StageSecrets } from '../../secrets/types.js';\nimport type { NormalizedWorkspace } from '../../workspace/types.js';\nimport type { DeployPhaseContext } from '../types';\nimport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\thttpsProbe,\n\tisHealthy,\n} from './health';\n\n/** Every phase's context: the compose target takes no options. */\nexport type ComposeContext = DeployPhaseContext<undefined>;\n\n/** What the target needs from outside the process, so tests can stand in. */\nexport interface ComposeDeps {\n\tdocker: ComposeDocker;\n\t/** The commit a build is tagged with. */\n\trevision: (root: string) => Promise<string>;\n\t/** The Postgres client provisioning and migrations connect through. */\n\tsql: typeof pgClient;\n\t/** The S3 client the stack's buckets are created through. */\n\tbuckets: typeof bucketClient;\n\t/** Apply the stage's migrations — `migrateDatabases` by default. */\n\tmigrate: typeof migrateDatabases;\n\t/** Ask one app, through the edge, whether it answers. */\n\tprobe: HealthProbe;\n\t/** How many times each app is asked before it counts as down. */\n\thealthAttempts: number;\n\t/** How long to wait between two asks of one app. */\n\thealthIntervalMs: number;\n\t/** Where the edge's ports are read from (`GKM_COMPOSE_HTTPS_PORT`, …). */\n\tenv: NodeJS.ProcessEnv;\n}\n\n/** One app's image, as the stage runs it. */\nexport interface ComposeImage {\n\tref: string;\n\ttag: string;\n\tdigest?: string;\n}\n\n/** A compose deploy in progress: what `validate` found, and what follows. */\nexport interface ComposeRun {\n\t/** Build the images from this checkout, or pull the ones a tag names. */\n\tmode: 'build' | 'pull';\n\t/**\n\t * Build and push the images, and nothing else (`--build --push`): no\n\t * provisioning, no container started, nothing recorded.\n\t */\n\tpush: boolean;\n\tstack: ComposeStack;\n\t/** The stack's directory, absolute: `.gkm/compose/<stage>`. */\n\tdir: string;\n\tref: StackRef;\n\t/** The stage's secrets, with whatever a deployed stage generates once. */\n\tsecrets: StageSecrets | null;\n\t/** The names of what was generated, written back in `provision`. */\n\tgenerated: string[];\n\t/** Each app's image as the stage's state last recorded it. */\n\tprevious: Record<string, DeployedImage>;\n\t/** Every file written, absolute. */\n\tfiles: string[];\n\t/** Each app's image, once built or pulled. */\n\timages: Record<string, ComposeImage>;\n\t/** Every resource the run touched, or for a dry run would. */\n\tchanges: ResourceChange[];\n}\n\n/** How a run gets its images, beyond what the tag implies. */\nexport interface ComposeRunOptions {\n\t/**\n\t * Build or pull whatever the tag says. By default a given tag is pulled\n\t * and no tag builds from the checkout.\n\t */\n\tmode?: 'build' | 'pull';\n\t/** Push what was built, and start nothing (`--build --push`). */\n\tpush?: boolean;\n\t/** Run each pulled image at the digest a push reported for it. */\n\tpin?: { file: string; digests: ImageDigests };\n}\n\n/** `--push` without `--build`: there is nothing built here to push. */\nexport class ComposePushNeedsBuild extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--push pushes the images this checkout builds, so it needs --build ' +\n\t\t\t\t'(and never --pull): gkm compose --stage <stage> --build --push --tag <tag>.',\n\t\t);\n\t\tthis.name = 'ComposePushNeedsBuild';\n\t}\n}\n\n/** Digests to run by, on a run that pulls nothing. */\nexport class ComposePinNeedsPull extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--digests-file pins the images a release pulls, so it needs --tag ' +\n\t\t\t\t'(or --pull) — or, with --build --push, it is where the pushed digests ' +\n\t\t\t\t'are written.',\n\t\t);\n\t\tthis.name = 'ComposePinNeedsPull';\n\t}\n}\n\n/** A port variable that does not hold a port. */\nexport class EdgePortInvalid extends Error {\n\tconstructor(\n\t\treadonly variable: string,\n\t\treadonly value: string,\n\t) {\n\t\tsuper(\n\t\t\t`${variable}=${value} is not a port. Set it to a number between 1 and 65535, or unset it for the default.`,\n\t\t);\n\t\tthis.name = 'EdgePortInvalid';\n\t}\n}\n\n/** A build with no commit to tag its images with. */\nexport class NoGitRevision extends Error {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`Images built here are tagged with the commit they were built from, ` +\n\t\t\t\t`and ${root} is not in a git repository with a commit. Commit, or ` +\n\t\t\t\t`pass --tag to name the images yourself.`,\n\t\t);\n\t\tthis.name = 'NoGitRevision';\n\t}\n}\n\n/**\n * The project's own file merged over a stage's stack: `docker-compose.<stage>.yml`\n * at the workspace root. What the generated file cannot know — a port bound\n * to a tailnet address, another log driver — goes there, and is never\n * overwritten.\n */\nexport function stackOverrideFile(root: string, stage: string): string {\n\treturn join(root, `docker-compose.${stage}.yml`);\n}\n\n/** The commit HEAD is at, short — and `-dirty` when the tree has changes. */\nexport async function gitRevision(root: string): Promise<string> {\n\tlet sha: string;\n\ttry {\n\t\tsha = (\n\t\t\tawait runOutput('git', ['rev-parse', '--short', 'HEAD'], { cwd: root })\n\t\t).trim();\n\t} catch {\n\t\tthrow new NoGitRevision(root);\n\t}\n\tif (!sha) throw new NoGitRevision(root);\n\n\t// An image built from uncommitted changes is not the commit's image, and a\n\t// tag that said it was would be the one thing worse than no tag.\n\tconst status = await runOutput('git', ['status', '--porcelain'], {\n\t\tcwd: root,\n\t}).catch(() => '');\n\treturn status.trim() ? `${sha}-dirty` : sha;\n}\n\n/** The edge's ports, from the environment — 443 and 80 when unset. */\nexport function edgePorts(env: NodeJS.ProcessEnv = process.env): {\n\thttps: number;\n\thttp: number;\n} {\n\tconst read = (variable: string, fallback: number) => {\n\t\tconst value = env[variable];\n\t\tif (value === undefined || value === '') return fallback;\n\t\tconst port = Number(value);\n\t\tif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n\t\t\tthrow new EdgePortInvalid(variable, value);\n\t\t}\n\t\treturn port;\n\t};\n\treturn {\n\t\thttps: read(EDGE_PORT_ENV.https, 443),\n\t\thttp: read(EDGE_PORT_ENV.http, 80),\n\t};\n}\n\n/**\n * The real ones. Each app is asked for three minutes before it counts as\n * down: a deployed stage's first ACME certificate can take that long.\n */\nexport const defaultDeps: ComposeDeps = {\n\tdocker: dockerCompose,\n\trevision: gitRevision,\n\tsql: pgClient,\n\tbuckets: bucketClient,\n\tmigrate: migrateDatabases,\n\tprobe: httpsProbe,\n\thealthAttempts: 90,\n\thealthIntervalMs: 2_000,\n\tenv: process.env,\n};\n\n// ============================================================================\n// validate\n// ============================================================================\n\n/**\n * The stack the stage would run, and — for a tag — the registry's word that\n * every image it names exists. Nothing is written: a missing image stops the\n * run here, before a file, a secret or a container is touched.\n */\nexport async function validateCompose(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n\toptions: ComposeRunOptions = {},\n): Promise<ComposeRun> {\n\tconst { workspace, stage, identity, tag } = ctx;\n\tconst root = workspace.root;\n\tconst mode = options.mode ?? (ctx.tagGiven ? 'pull' : 'build');\n\tconst push = options.push === true;\n\tif (push && mode !== 'build') throw new ComposePushNeedsBuild();\n\tif (options.pin && mode !== 'pull') throw new ComposePinNeedsPull();\n\n\t// An image pushed or pulled with no registry is a Docker Hub name, which\n\t// is somebody else's. Refused before anything is discovered, built or\n\t// asked of a registry.\n\tconst registry = workspace.deploy?.registry;\n\tif (!registry && (push || mode === 'pull')) {\n\t\tthrow new RegistryRequired(\n\t\t\tpush ? 'push' : 'pull',\n\t\t\timageRef(identity, ctx.apps[0] ?? workspace.name, undefined, tag),\n\t\t);\n\t}\n\n\t// The runnables' edges say which surface reaches which; the manifest the\n\t// run discovered has the declarations but not them.\n\tconst runnables: Record<string, string[]> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: root,\n\t\trunnables,\n\t\tbackground,\n\t});\n\n\tconst { secrets, generated } = await stageSecrets(ctx, manifest);\n\n\t// A third party's credentials against their construct's schema, before a\n\t// stack is composed with one every app reading it would refuse. A push\n\t// runs no app, so it reads none of them.\n\tif (!push) {\n\t\t// An address an older gkm stored for what a construct now provides:\n\t\t// set by hand wins, so every app would be handed `localhost`.\n\t\tassertNoStaleSecrets({\n\t\t\tmanifest,\n\t\t\tstage,\n\t\t\tsupplied: secrets?.custom ?? {},\n\t\t});\n\t\tawait assertStageCredentials({\n\t\t\troot,\n\t\t\tpatterns: constructGlobs(workspace),\n\t\t\tmanifest,\n\t\t\tstage,\n\t\t\tsupplied: secrets?.custom ?? {},\n\t\t});\n\t}\n\n\t// Where and with what the images are built — only asked when they are.\n\tconst layout = mode === 'build' ? imageLayout(workspace) : undefined;\n\n\tconst composed = composeStack({\n\t\tworkspace,\n\t\tmanifest,\n\t\trunnables,\n\t\tbackground,\n\t\tstage,\n\t\tidentity,\n\t\timages: {\n\t\t\tmode,\n\t\t\ttag,\n\t\t\t...(registry ? { registry } : {}),\n\t\t},\n\t\tsecrets,\n\t\tallowDevServices: ctx.allowDevServices,\n\t\tports: edgePorts(deps.env),\n\t\t...(layout ? { layout } : {}),\n\t\t...(push ? { buildOnly: true } : {}),\n\t});\n\n\t// Loud, every run — a dry run included: a deployed stage on Mailpit\n\t// delivers no mail, and one on MinIO keeps its files on one disk.\n\treportDevServices(ctx, composed.devServices);\n\n\t// A cache is reached over the Redis wire protocol, and the client is the\n\t// project's own dependency: a build without it fails deep inside Docker.\n\tif (mode === 'build') assertRedisClient(workspace, composed);\n\n\t// No image embeds the stage's secrets: a backend reads them at runtime\n\t// from its env file, so one image built at a commit runs on every stage.\n\t// A pinned release runs each image at the digest its push reported.\n\tconst stack = options.pin\n\t\t? withPinnedImages(composed, options.pin.file, options.pin.digests)\n\t\t: composed;\n\n\t// A release is all of its images or none of them. A dry run asks nothing,\n\t// so it can be run without a registry login.\n\tif (mode === 'pull' && !ctx.dryRun) {\n\t\tawait assertImagesExist(deps.docker, tag, [\n\t\t\t...stack.apps,\n\t\t\t...stack.workers,\n\t\t]);\n\t}\n\n\t// The stage's own certificate is read when the stack starts; one that is\n\t// not there stops the run here, before anything is written or started.\n\tif (stack.tls && !push) {\n\t\tfor (const file of [stack.tls.certFile, stack.tls.keyFile]) {\n\t\t\tif (!existsSync(file)) throw new ComposeTlsFileMissing(stage, file);\n\t\t}\n\t}\n\n\tif (stack.redis && !stack.local) ctx.secrets.mask(stack.redis.password);\n\n\t// The log UI's root login and the header every backend signs in with:\n\t// secrets, unless they are the local stage's fixed ones.\n\tif (stack.logs && (!stack.local || stack.logs.passwordFromSecrets)) {\n\t\tctx.secrets.mask(stack.logs.password);\n\t\tctx.secrets.mask(stack.logs.appEnv.OTEL_EXPORTER_OTLP_HEADERS);\n\t}\n\n\tconst dir = join(root, stackDir(stage));\n\tconst override = stackOverrideFile(root, stage);\n\tconst overrides = existsSync(override) ? [override] : [];\n\tif (overrides.length > 0) {\n\t\tctx.logger.info(\n\t\t\t`🧩 Merging docker-compose.${stage}.yml over the generated stack`,\n\t\t);\n\t}\n\t// What each app ran before this release: its current release, by the same\n\t// record the Dokploy target keeps, so a rollback reads one shape for both.\n\t// A push changes no stage, so it reads none of its state either.\n\tconst recorded = push ? undefined : await ctx.state.read(stage);\n\tconst previous = Object.fromEntries(\n\t\tObject.entries(recorded?.state.releases ?? {}).map(\n\t\t\t([name, releases]): [string, DeployedImage] => {\n\t\t\t\tconst { ref, tag, digest } = releases.current;\n\t\t\t\treturn [\n\t\t\t\t\tname,\n\t\t\t\t\t{ ref, ...(tag ? { tag } : {}), ...(digest ? { digest } : {}) },\n\t\t\t\t];\n\t\t\t},\n\t\t),\n\t);\n\n\treturn {\n\t\tmode,\n\t\tpush,\n\t\tstack,\n\t\tdir,\n\t\tref: {\n\t\t\tproject: composeProject(identity),\n\t\t\tfile: join(dir, 'docker-compose.yml'),\n\t\t\t...(overrides.length > 0 ? { overrides } : {}),\n\t\t\tcwd: root,\n\t\t\toutput: ctx.childOutput,\n\t\t\tsignal: ctx.signal,\n\t\t},\n\t\tsecrets,\n\t\tgenerated,\n\t\tprevious,\n\t\tfiles: [],\n\t\timages: {},\n\t\tchanges: [],\n\t};\n}\n\n/** A stack whose caches are in Redis, built for an app that has no client. */\nexport class RedisClientMissing extends Error {\n\tconstructor(readonly apps: readonly string[]) {\n\t\tsuper(\n\t\t\t`The stack keeps every cache in Redis, and ${apps.join(', ')} ` +\n\t\t\t\t`${apps.length === 1 ? 'does' : 'do'} not depend on ioredis, the client ` +\n\t\t\t\t'the generated server reaches it with. Add it to the workspace: ' +\n\t\t\t\t'pnpm add ioredis',\n\t\t);\n\t\tthis.name = 'RedisClientMissing';\n\t}\n}\n\n/**\n * Every backend and worker image built for a stack with a cache can resolve\n * `ioredis` — listed by its app or a directory above it, the way Node and\n * the image's install find it.\n */\nfunction assertRedisClient(\n\tworkspace: NormalizedWorkspace,\n\tstack: ComposeStack,\n): void {\n\tif (!stack.plan.resources.some((r) => r.kind === 'cache')) return;\n\n\tconst hosts = new Set([\n\t\t...stack.apps.filter((app) => app.kind === 'rest-api').map((a) => a.name),\n\t\t...stack.workers.map((worker) => worker.host),\n\t]);\n\tconst missing = [...hosts]\n\t\t.filter((name) => {\n\t\t\tconst app = workspace.apps[name];\n\t\t\treturn app && !installedFrom(join(workspace.root, app.path), 'ioredis');\n\t\t})\n\t\t.sort();\n\tif (missing.length > 0) throw new RedisClientMissing(missing);\n}\n\n/**\n * The stage's secrets — and, for a deployed stage, everything it generates\n * once: its seed, and each declared secret and keyring. Kept only once the\n * run goes ahead (`provision`), so a dry run, or a tag that is not there,\n * leaves the stage's secrets as it found them.\n */\nasync function stageSecrets(\n\tctx: ComposeContext,\n\tmanifest: ConstructManifest,\n): Promise<{ secrets: StageSecrets | null; generated: string[] }> {\n\tconst stored = await ctx.secrets.read();\n\tif (ctx.stage === ctx.workspace.stages.local) {\n\t\treturn { secrets: stored, generated: [] };\n\t}\n\n\tconst withSeed = withGeneratedSecrets(\n\t\tstored ?? initStageSecrets(ctx.stage),\n\t\tmanifest,\n\t);\n\t// The log UI's root password, generated once like the seed, where the\n\t// workspace runs one and the stage set none.\n\tconst withLogs = resolveLogs(ctx.workspace.deploy?.compose?.logs)\n\t\t? withLogsPassword(withSeed.secrets)\n\t\t: { secrets: withSeed.secrets, generated: [] };\n\t// The stack's Redis password, the same way, where a cache lives in it.\n\tconst withRedis = runsRedis(manifest, withLogs.secrets.custom ?? {})\n\t\t? withRedisPassword(withLogs.secrets)\n\t\t: { secrets: withLogs.secrets, generated: [] };\n\tconst secrets = withRedis.secrets;\n\tconst generated = [\n\t\t...withSeed.generated,\n\t\t...withLogs.generated,\n\t\t...withRedis.generated,\n\t];\n\t// Read through the store they are masked; made up here, they are not yet.\n\tif (secrets.seed) ctx.secrets.mask(secrets.seed);\n\tfor (const value of Object.values(secrets.custom ?? {})) {\n\t\tctx.secrets.mask(value);\n\t}\n\treturn { secrets, generated };\n}\n\n/**\n * The stack with each app's and worker's image pinned to the digest the file\n * names: the refs it is checked, pulled and recorded by, and the image each\n * compose service runs.\n */\nfunction withPinnedImages(\n\tstack: ComposeStack,\n\tfile: string,\n\tdigests: ImageDigests,\n): ComposeStack {\n\tconst apps = pinImages(file, digests, stack.apps);\n\tconst workers = pinImages(file, digests, stack.workers);\n\tconst services = { ...stack.compose.services };\n\tfor (const image of [...apps, ...workers]) {\n\t\tservices[image.name] = { ...services[image.name]!, image: image.ref };\n\t}\n\treturn {\n\t\t...stack,\n\t\tapps,\n\t\tworkers,\n\t\tcompose: { ...stack.compose, services },\n\t};\n}\n\n// ============================================================================\n// plan (dry run)\n// ============================================================================\n\n/**\n * A dry run: the stack's files, written so they can be read, and what a real\n * run would do — no image is built or pulled, no container touched, nothing\n * recorded and no secret kept.\n */\nexport async function planCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): Promise<void> {\n\tif (run.generated.length > 0) {\n\t\tctx.logger.info(\n\t\t\t`🔑 \"${ctx.stage}\" has no ${run.generated.join(', ')} yet; this dry run used values it did not keep.`,\n\t\t);\n\t}\n\trun.files = await writeStack(ctx.cwd, run.dir, run.stack);\n\tprintPlan(ctx, run);\n\n\tconst planned = (change: ResourceChange) => {\n\t\trun.changes.push(change);\n\t\tctx.emit({ type: 'resource.planned', ...change });\n\t};\n\tfor (const service of run.push ? [] : run.stack.infra) {\n\t\tplanned({\n\t\t\tkey: `service:${service}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t});\n\t}\n\tfor (const app of run.stack.apps) {\n\t\tplanned({\n\t\t\tkey: `image:${app.name}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: app.ref,\n\t\t});\n\t\tif (run.push) continue;\n\t\tplanned({\n\t\t\tkey: `service:${app.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: run.previous[app.name] ? 'reuse' : 'create',\n\t\t});\n\t}\n\tfor (const worker of run.stack.workers) {\n\t\tplanned({\n\t\t\tkey: `image:${worker.name}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: worker.ref,\n\t\t});\n\t\tif (run.push) continue;\n\t\tplanned({\n\t\t\tkey: `service:${worker.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: run.previous[worker.name] ? 'reuse' : 'create',\n\t\t});\n\t}\n\tif (!run.push) {\n\t\tplanned({\n\t\t\tkey:\n\t\t\t\trun.stack.proxy === 'caddy'\n\t\t\t\t\t? 'service:caddy'\n\t\t\t\t\t: `service:${EDGE_PROJECT}/${EDGE_SERVICE}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t});\n\t}\n}\n\n// ============================================================================\n// provision\n// ============================================================================\n\n/**\n * What the apps run on: the stage's generated secrets kept, the stack's files\n * written, its infrastructure started, and its databases, roles, grants and\n * migrations applied.\n */\nexport async function provisionCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack, ref } = run;\n\t// A push provisions nothing; its files are written where it builds.\n\tif (run.push) return;\n\n\tif (run.generated.length > 0 && run.secrets) {\n\t\tawait ctx.secrets.write(run.secrets);\n\t\tctx.logger.info(\n\t\t\t`🔑 Generated for \"${ctx.stage}\" (${ctx.secrets.store}): ${run.generated.join(', ')}`,\n\t\t);\n\t}\n\n\t// Nothing but the stack's own proxy may hold the edge's ports — checked\n\t// before a file is written or a container started.\n\tconst ports = edgePorts(deps.env);\n\tawait assertEdgePorts(deps.docker, {\n\t\tproject: stack.project,\n\t\tproxy: stack.proxy,\n\t\tports,\n\t});\n\n\trun.files = await writeStack(ctx.cwd, run.dir, stack);\n\tprintPlan(ctx, run);\n\n\t// The shared edge, and the network the stack's public services join —\n\t// before any of them, MinIO among them, is started.\n\tif (stack.proxy === 'traefik') {\n\t\tconst dir = edgeDir(deps.env);\n\t\tctx.logger.info(\n\t\t\t`\\n🌐 Starting the shared edge (${EDGE_PROJECT}) from ${dir}…`,\n\t\t);\n\t\trun.files.push(\n\t\t\t...(await ensureEdge(deps.docker, {\n\t\t\t\tdir,\n\t\t\t\tports,\n\t\t\t\tlogging: {\n\t\t\t\t\tdriver: LOG_ROTATION.driver,\n\t\t\t\t\toptions: { ...LOG_ROTATION.options },\n\t\t\t\t},\n\t\t\t\t...(ref.output ? { output: ref.output } : {}),\n\t\t\t\t...(ref.signal ? { signal: ref.signal } : {}),\n\t\t\t})),\n\t\t);\n\t\tapplied(ctx, run, {\n\t\t\tkey: `service:${EDGE_PROJECT}/${EDGE_SERVICE}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t\tid: `${EDGE_PROJECT}/${EDGE_SERVICE}`,\n\t\t\tvia: 'found',\n\t\t});\n\t}\n\n\tif (stack.infra.length > 0) {\n\t\tctx.logger.info(`\\n🗄️ Starting ${stack.infra.join(', ')}…`);\n\t\tawait deps.docker.up(ref, stack.infra);\n\t\tfor (const service of stack.infra) {\n\t\t\tapplied(ctx, run, {\n\t\t\t\tkey: `service:${service}`,\n\t\t\t\tresourceType: 'service',\n\t\t\t\taction: 'ensure',\n\t\t\t\tid: `${stack.project}/${service}`,\n\t\t\t\tvia: Object.keys(run.previous).length > 0 ? 'recorded' : 'created',\n\t\t\t});\n\t\t}\n\t}\n\n\tif (stack.infra.includes('postgres')) {\n\t\tawait prepareDatabases(ctx, run, deps);\n\t}\n\tif (stack.storage && stack.infra.includes('minio')) {\n\t\tawait prepareBuckets(ctx, run, deps);\n\t}\n}\n\n/**\n * Create each bucket the stack's MinIO serves, and the open paths of each\n * one a file server fronts — from this machine, on MinIO's loopback port,\n * the way `gkm dev` creates them.\n */\nasync function prepareBuckets(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst storage = run.stack.storage!;\n\tif (storage.buckets.length === 0) return;\n\n\tconst port = await deps.docker.port(run.ref, 'minio', 9000);\n\tconst client = deps.buckets(port, storage);\n\tconst done = [\n\t\t...(await applyBuckets(client, storage.buckets)),\n\t\t...(await applyPolicies(client, storage.policies)),\n\t];\n\tconst created = done.filter((entry) => entry.created).length;\n\tctx.logger.info(\n\t\t`🪣 Buckets: ${storage.buckets.join(', ')}${created ? ` (${created} change(s))` : ''}`,\n\t);\n}\n\n/** Create what the plan names in the stack's Postgres, then migrate it. */\nasync function prepareDatabases(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\tconst workspace: NormalizedWorkspace = ctx.workspace;\n\tconst port = await deps.docker.port(run.ref, 'postgres', 5432);\n\n\tconst statements = postgresStatements(\n\t\tstack.plan,\n\t\tworkspace.name,\n\t\tstack.credential.seed,\n\t);\n\tif (statements.length > 0) {\n\t\tctx.logger.info('🗄️ Creating databases, roles and grants…');\n\t\tawait applyPostgres(deps.sql(port, stack.credential.master), statements);\n\t}\n\n\t// Migrations run here, with the project's own Kysely, the way `gkm\n\t// migrate` runs them — so the constructs themselves are needed, which\n\t// only an in-process discovery hands back.\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: workspace.root,\n\t\tsources,\n\t});\n\n\t// The owner URLs, on the port published to this machine.\n\tconst env = envFor(stack.plan, {\n\t\tports: { [primaryPortKey('postgres')]: port },\n\t\tproject: workspace.name,\n\t\tmaster: stack.credential.master,\n\t\t...(stack.credential.seed ? { seed: stack.credential.seed } : {}),\n\t});\n\tconst runs = await deps.migrate({\n\t\troot: workspace.root,\n\t\tmanifest,\n\t\tsources,\n\t\tenv,\n\t});\n\tfor (const { target, applied } of runs) {\n\t\tif (applied.length > 0) {\n\t\t\tctx.logger.info(`🗄️ ${target.migrations}: applied ${applied.length}`);\n\t\t}\n\t}\n}\n\n// ============================================================================\n// build\n// ============================================================================\n\n/**\n * Each app's image: built from this checkout — inside Docker, every one of\n * them, from a pruned slice of the build root — or pulled at the tag. Nothing\n * live changes.\n */\nexport async function buildCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack, ref } = run;\n\tconst images = [...stack.apps, ...stack.workers];\n\tconst apps = images.map((image) => image.app);\n\n\t// Nothing was provisioned, so nothing has written the files it builds from.\n\tif (run.push) {\n\t\trun.files = await writeStack(ctx.cwd, run.dir, stack);\n\t\tprintPlan(ctx, run);\n\t}\n\n\tif (run.mode === 'build') {\n\t\tctx.logger.info('\\n🐳 Building images…');\n\t\tawait deps.docker.build(ref, apps);\n\t} else {\n\t\tctx.logger.info(`\\n🐳 Pulling ${ctx.tag}…`);\n\t\tawait deps.docker.pull(ref, apps);\n\t}\n\n\tif (run.push) ctx.logger.info('\\n📤 Pushing images…');\n\n\t// What each tag resolved to: the registry's digest for a pushed or pulled\n\t// image, or — for one built here and never pushed — its content id.\n\tfor (const image of images) {\n\t\tconst digest = run.push\n\t\t\t? await deps.docker.push(ref, image.ref)\n\t\t\t: await deps.docker.digest(image.ref);\n\t\tif (run.push) {\n\t\t\tctx.logger.info(` ${image.app.padEnd(12)} ${image.ref}@${digest}`);\n\t\t}\n\t\trun.images[image.app] = {\n\t\t\tref: image.ref,\n\t\t\ttag: image.tag,\n\t\t\t...(digest ? { digest } : {}),\n\t\t};\n\t\tctx.emit({\n\t\t\ttype: 'artifact.built',\n\t\t\tapp: image.app,\n\t\t\timageRef: image.ref,\n\t\t\t...(digest ? { digest } : {}),\n\t\t});\n\t\trun.changes.push({\n\t\t\tkey: `image:${image.app}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: digest ?? image.ref,\n\t\t});\n\t}\n}\n\n// ============================================================================\n// release\n// ============================================================================\n\n/**\n * The whole stack up — anything it no longer defines removed — and each\n * app's image recorded in the stage's state.\n */\nexport async function releaseCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack, ref } = run;\n\t// A push starts nothing and records nothing: a stage runs what it pulls.\n\tif (run.push) return;\n\n\tctx.logger.info('\\n🚀 Starting the stack…');\n\tawait deps.docker.up(ref);\n\n\t// Registered with the shared edge once its services are up, so the edge\n\t// never routes to a container that is not there yet. A stack on its own\n\t// Caddy leaves nothing behind there from a run on the edge.\n\tconst edge = edgeDir(deps.env);\n\tif (stack.proxy === 'traefik' && stack.traefik) {\n\t\tconst written = await writeEdgeRoutes(\n\t\t\tedge,\n\t\t\tstack.project,\n\t\t\tstack.traefik,\n\t\t\tstack.tls,\n\t\t);\n\t\trun.files.push(...written);\n\t\tctx.logger.info(\n\t\t\t`🌐 Registered ${stack.routes.length} route(s) with ${EDGE_PROJECT}: ${written.at(-1)}`,\n\t\t);\n\t} else {\n\t\tawait removeEdgeRoutes(edge, stack.project);\n\t}\n\n\tif (stack.local) {\n\t\t// Caddy's CA is generated on its first start. Copied out so a process —\n\t\t// `verify` among them — can trust it without installing anything.\n\t\tawait deps.docker\n\t\t\t.copyOut(\n\t\t\t\tref,\n\t\t\t\t'caddy',\n\t\t\t\t'/data/caddy/pki/authorities/local/root.crt',\n\t\t\t\tcaFile(run),\n\t\t\t)\n\t\t\t.catch(() => {});\n\t}\n\n\tawait recordImages(ctx, run);\n\n\tfor (const app of stack.apps) {\n\t\tconst image = run.images[app.name];\n\t\tapplied(ctx, run, {\n\t\t\tkey: `service:${app.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t\tid: `${stack.project}/${app.name}`,\n\t\t\tvia: run.previous[app.name] ? 'recorded' : 'created',\n\t\t});\n\t\tctx.emit({\n\t\t\ttype: 'app.deployed',\n\t\t\tapp: app.name,\n\t\t\tapplicationId: `${stack.project}/${app.name}`,\n\t\t\timageRef: image?.ref ?? app.ref,\n\t\t\turl: app.url,\n\t\t});\n\t}\n\n\t// A worker has no URL, so no `app.deployed`: its service, applied, is it.\n\tfor (const worker of stack.workers) {\n\t\tapplied(ctx, run, {\n\t\t\tkey: `service:${worker.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t\tid: `${stack.project}/${worker.name}`,\n\t\t\tvia: run.previous[worker.name] ? 'recorded' : 'created',\n\t\t});\n\t}\n\n\tctx.logger.info(`\\n✅ ${stack.project} is running:`);\n\tfor (const app of stack.apps) {\n\t\tctx.logger.info(` ${app.name.padEnd(12)} ${app.url}`);\n\t}\n\tfor (const worker of stack.workers) {\n\t\tctx.logger.info(` ${worker.name.padEnd(12)} worker ${worker.id}`);\n\t}\n\tif (stack.local) {\n\t\tctx.logger.info(\n\t\t\t`\\n🔐 Certificates are from Caddy's local CA: NODE_EXTRA_CA_CERTS=${join(stackDir(ctx.stage), 'caddy-root.crt')}`,\n\t\t);\n\t}\n}\n\n/**\n * Each app's image in the stage's state — the same `images` a Dokploy deploy\n * records: the ref it runs, the tag it was released under, and the digest\n * the tag resolved to.\n */\nasync function recordImages(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): Promise<void> {\n\tconst journal = await DeployJournal.open(ctx.state, ctx.stage, () =>\n\t\tcreateEmptyState(ctx.stage, '', ''),\n\t);\n\tfor (const app of [...run.stack.apps, ...run.stack.workers]) {\n\t\tconst image = run.images[app.app] ?? { ref: app.ref, tag: app.tag };\n\t\trecordRelease(journal.state, app.app, image);\n\t}\n\tjournal.state.identity = ctx.identity.key;\n\tawait journal.save();\n}\n\n// ============================================================================\n// verify\n// ============================================================================\n\n/**\n * Each app asked through Caddy, over HTTPS, the certificate verified: an API\n * at `/health`, a site at `/`. On the local stage the edge is this machine and\n * its certificates are Caddy's internal CA's, so the CA `release` copied out\n * is the one trusted and the request goes to 127.0.0.1.\n */\nexport async function verifyCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\tif (run.push) return;\n\tconst ca = stack.local\n\t\t? await readFile(caFile(run), 'utf-8').catch(() => undefined)\n\t\t: undefined;\n\n\tctx.logger.info(\n\t\t`\\n🩺 Checking each app through ${stack.proxy === 'caddy' ? 'Caddy' : 'the shared edge'}…`,\n\t);\n\t// The local stage's edge is this machine. So is the shared edge, by\n\t// construction — compose starts it here — so it is asked directly, on\n\t// its published port, with each host as SNI and Host: what is checked is\n\t// its routing and its certificate, whatever DNS or a NAT in front of\n\t// the server does with a request from the server to itself.\n\tconst edge =\n\t\tstack.local || stack.proxy === 'traefik'\n\t\t\t? {\n\t\t\t\t\tconnectTo: '127.0.0.1',\n\t\t\t\t\t...(stack.local ? {} : { connectPort: edgePorts(deps.env).https }),\n\t\t\t\t}\n\t\t\t: undefined;\n\tconst results = await Promise.all(\n\t\tstack.apps.map((app) => checkApp(ctx, app, deps, { ca, edge })),\n\t);\n\n\t// A worker has no route through the edge: its own health check, as Docker\n\t// reports it, is the answer.\n\tresults.push(\n\t\t...(await Promise.all(\n\t\t\tstack.workers.map((worker) =>\n\t\t\t\tcheckContainer(ctx, run, deps, worker.name),\n\t\t\t),\n\t\t)),\n\t);\n\tif (stack.logs) {\n\t\tresults.push(await checkContainer(ctx, run, deps, LOGS_SERVICE));\n\t}\n\n\tconst down = results\n\t\t.filter((result) => !result.healthy)\n\t\t.map(({ app, url, last }) => ({ app, url, last }));\n\tif (down.length > 0) {\n\t\tthrow new ComposeAppsUnhealthy(stack.project, down, stack.proxy);\n\t}\n\n\tif (stack.logs) reportLogs(ctx, stack.logs, stack.local);\n}\n\n/**\n * A container's own health check, as Docker reports it: a worker's, which\n * has no route through the edge, and OpenObserve's — by default it has no\n * host there, and served publicly it answers only the addresses it allows,\n * which need not include this one.\n */\nasync function checkContainer(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tservice: string,\n): Promise<{ app: string; url: string; last: string; healthy: boolean }> {\n\tconst url = `docker:${service}`;\n\tlet last = 'not asked';\n\n\tfor (let attempt = 1; attempt <= deps.healthAttempts; attempt++) {\n\t\tctx.signal.throwIfAborted();\n\t\tconst health = await deps.docker\n\t\t\t.health(run.ref, service)\n\t\t\t.catch((error: unknown) =>\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t);\n\t\tlast = health ?? 'not running';\n\t\tconst healthy = health === 'healthy';\n\t\tctx.emit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp: service,\n\t\t\turl,\n\t\t\thealthy,\n\t\t\tattempt,\n\t\t});\n\t\tif (healthy) {\n\t\t\tctx.logger.info(` ✓ ${service.padEnd(12)} ${url} (${last})`);\n\t\t\treturn { app: service, url, last, healthy };\n\t\t}\n\t\tif (attempt < deps.healthAttempts) {\n\t\t\tawait new Promise((resolve) =>\n\t\t\t\tsetTimeout(resolve, deps.healthIntervalMs),\n\t\t\t);\n\t\t}\n\t}\n\n\tctx.logger.warn(` ✗ ${service.padEnd(12)} ${url} (${last})`);\n\treturn { app: service, url, last, healthy: false };\n}\n\n/** How to open the logs, printed — and as an event, for a headless caller. */\nfunction reportLogs(\n\tctx: ComposeContext,\n\tlogs: StackLogs,\n\tlocal: boolean,\n): void {\n\tconst lines = logsAccess(logs, {\n\t\tstage: ctx.stage,\n\t\tlocal,\n\t\tuser: currentUser(),\n\t\thostname: hostname(),\n\t});\n\tctx.logger.info(`\\n${lines.join('\\n')}`);\n\tctx.emit({\n\t\ttype: 'logs.ready',\n\t\tservice: LOGS_SERVICE,\n\t\taccess: logs.public ? 'public' : 'tunnel',\n\t\turl: logs.url,\n\t\t...(logs.public ? { allow: [...logs.public.allow] } : { port: logs.port }),\n\t\temail: logs.email,\n\t});\n}\n\n/** This machine's user — a guess at who would SSH in. */\nfunction currentUser(): string {\n\ttry {\n\t\treturn userInfo().username;\n\t} catch {\n\t\treturn process.env.USER ?? 'user';\n\t}\n}\n\nasync function checkApp(\n\tctx: ComposeContext,\n\tapp: StackApp,\n\tdeps: ComposeDeps,\n\toptions: {\n\t\tca: string | undefined;\n\t\tedge?: { connectTo: string; connectPort?: number };\n\t},\n): Promise<{ app: string; url: string; last: string; healthy: boolean }> {\n\tconst url = `${app.url}${app.kind === 'site' ? '/' : '/health'}`;\n\tlet last = 'not asked';\n\n\tfor (let attempt = 1; attempt <= deps.healthAttempts; attempt++) {\n\t\tctx.signal.throwIfAborted();\n\t\tlet status: number | undefined;\n\t\ttry {\n\t\t\tstatus = await deps.probe({\n\t\t\t\turl,\n\t\t\t\t...(options.ca ? { ca: options.ca } : {}),\n\t\t\t\t...options.edge,\n\t\t\t\ttimeoutMs: 10_000,\n\t\t\t\tsignal: ctx.signal,\n\t\t\t});\n\t\t\tlast = `HTTP ${status}`;\n\t\t} catch (error) {\n\t\t\tlast = error instanceof Error ? error.message : String(error);\n\t\t}\n\n\t\tconst healthy = status !== undefined && isHealthy(status);\n\t\tctx.emit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp: app.name,\n\t\t\turl,\n\t\t\thealthy,\n\t\t\t...(status !== undefined ? { status } : {}),\n\t\t\tattempt,\n\t\t});\n\t\tif (healthy) {\n\t\t\tctx.logger.info(` ✓ ${app.name.padEnd(12)} ${url} (${last})`);\n\t\t\treturn { app: app.name, url, last, healthy };\n\t\t}\n\t\tif (attempt < deps.healthAttempts) {\n\t\t\tawait new Promise((resolve) =>\n\t\t\t\tsetTimeout(resolve, deps.healthIntervalMs),\n\t\t\t);\n\t\t}\n\t}\n\n\tctx.logger.warn(` ✗ ${app.name.padEnd(12)} ${url} (${last})`);\n\treturn { app: app.name, url, last, healthy: false };\n}\n\n// ============================================================================\n// result\n// ============================================================================\n\nexport function composeResult(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): DeployResult {\n\tconst apps = [\n\t\t...run.stack.apps.map((app) => {\n\t\t\tconst image = run.images[app.name];\n\t\t\treturn {\n\t\t\t\tappName: app.name,\n\t\t\t\ttype: app.kind === 'site' ? ('web' as const) : ('backend' as const),\n\t\t\t\tsuccess: !ctx.dryRun,\n\t\t\t\tapplicationId: `${run.stack.project}/${app.name}`,\n\t\t\t\timageRef: image?.ref ?? app.ref,\n\t\t\t\t...(image?.digest ? { digest: image.digest } : {}),\n\t\t\t\turl: app.url,\n\t\t\t};\n\t\t}),\n\t\t...run.stack.workers.map((worker) => {\n\t\t\tconst image = run.images[worker.name];\n\t\t\treturn {\n\t\t\t\tappName: worker.name,\n\t\t\t\ttype: 'backend' as const,\n\t\t\t\tsuccess: !ctx.dryRun,\n\t\t\t\tapplicationId: `${run.stack.project}/${worker.name}`,\n\t\t\t\timageRef: image?.ref ?? worker.ref,\n\t\t\t\t...(image?.digest ? { digest: image.digest } : {}),\n\t\t\t};\n\t\t}),\n\t];\n\treturn {\n\t\tapps,\n\t\tprojectId: run.stack.project,\n\t\tsuccessCount: ctx.dryRun ? 0 : apps.length,\n\t\tfailedCount: 0,\n\t\tstage: ctx.stage,\n\t\tidentity: ctx.identity.key,\n\t\ttag: ctx.tag,\n\t\tdryRun: ctx.dryRun,\n\t\tenvironmentId: '',\n\t\tskipped: [...ctx.skipped],\n\t\turls: Object.fromEntries(run.stack.apps.map((app) => [app.name, app.url])),\n\t\tchanges: run.changes,\n\t};\n}\n\n// ============================================================================\n// Files\n// ============================================================================\n\nfunction caFile(run: ComposeRun): string {\n\treturn join(run.dir, 'caddy-root.crt');\n}\n\nfunction applied(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tchange: ResourceChange & {\n\t\tid: string;\n\t\tvia: 'recorded' | 'resumed' | 'found' | 'created';\n\t},\n): void {\n\tconst { via, ...rest } = change;\n\trun.changes.push(rest);\n\tctx.emit({ type: 'resource.applied', ...rest, via });\n}\n\n/** Write the stack's files: owner-only, since the env files hold secrets. */\nasync function writeStack(\n\troot: string,\n\tdir: string,\n\tstack: ComposeStack,\n): Promise<string[]> {\n\tawait mkdir(dir, { recursive: true, mode: 0o700 });\n\tawait chmod(dir, 0o700);\n\n\tconst files: string[] = [];\n\tconst write = async (path: string, content: string, mode = 0o644) => {\n\t\tawait mkdir(dirname(path), { recursive: true });\n\t\tawait writeFile(path, content, { mode });\n\t\tawait chmod(path, mode);\n\t\tfiles.push(path);\n\t};\n\n\tawait write(join(dir, 'docker-compose.yml'), composeYaml(stack));\n\t// The proxy's configuration: the stack's own Caddy's, or — for reading —\n\t// a copy of what the stack registers with the shared edge. The other is\n\t// removed, so the directory never shows a proxy the stack does not use.\n\tif (stack.caddyfile !== undefined) {\n\t\tawait write(join(dir, 'Caddyfile'), stack.caddyfile);\n\t\tawait rm(join(dir, 'traefik.yml'), { force: true });\n\t} else {\n\t\tawait rm(join(dir, 'Caddyfile'), { force: true });\n\t}\n\tif (stack.traefik !== undefined) {\n\t\tawait write(join(dir, 'traefik.yml'), stack.traefik);\n\t}\n\t// The stage's own certificate, where Caddy mounts it.\n\tif (stack.proxy === 'caddy' && stack.tls) {\n\t\tawait mkdir(join(dir, 'tls'), { recursive: true, mode: 0o700 });\n\t\tawait write(\n\t\t\tjoin(dir, 'tls', 'cert.pem'),\n\t\t\tawait readFile(stack.tls.certFile, 'utf-8'),\n\t\t);\n\t\tawait write(\n\t\t\tjoin(dir, 'tls', 'key.pem'),\n\t\t\tawait readFile(stack.tls.keyFile, 'utf-8'),\n\t\t\t0o600,\n\t\t);\n\t} else {\n\t\tawait rm(join(dir, 'tls'), { recursive: true, force: true });\n\t}\n\tfor (const app of [...stack.apps, ...stack.workers]) {\n\t\tif (app.env)\n\t\t\tawait write(join(dir, `${app.name}.env`), envFile(app.env), 0o600);\n\t}\n\t// A stack that only builds reads no env file, so none is written.\n\tif (stack.logs && stack.compose.services[LOGS_SERVICE]?.env_file) {\n\t\tawait write(\n\t\t\tjoin(dir, `${LOGS_SERVICE}.env`),\n\t\t\tenvFile(stack.logs.env),\n\t\t\t0o600,\n\t\t);\n\t}\n\tif (stack.redis && stack.compose.services[REDIS_SERVICE]?.env_file) {\n\t\tawait write(\n\t\t\tjoin(dir, `${REDIS_SERVICE}.env`),\n\t\t\tenvFile(stack.redis.env),\n\t\t\t0o600,\n\t\t);\n\t}\n\t// Images no longer embed a stage's credentials. The ciphertexts an older\n\t// gkm left beside the compose file for them to embed are removed.\n\tfor (const entry of await readdir(dir)) {\n\t\tif (entry.endsWith('.credentials')) await rm(join(dir, entry));\n\t}\n\tfor (const [path, content] of Object.entries(stack.dockerfiles)) {\n\t\tawait write(join(root, path), content);\n\t}\n\n\t// The build context is the build root, and the env files are under it:\n\t// its ignore file is what keeps a stage's secrets out of every image's\n\t// context.\n\tawait ensureDockerignore(findBuildRoot(root));\n\n\treturn files;\n}\n\nfunction composeYaml(stack: ComposeStack): string {\n\tconst stage = ` --stage ${stack.stage}`;\n\treturn `# Generated by gkm compose from the construct manifest — do not edit.\n# The ${stack.stage} stage's APIs and sites behind ${stack.proxy === 'caddy' ? 'one Caddy' : `the shared Traefik edge (${EDGE_PROJECT})`}, and its workers.\n# Each backend and worker reads exactly the keys in its own env file beside\n# this one.\n#\n# gkm compose${stage} start or update it\n# gkm compose${stage} --down stop it\n${stringify(stack.compose, { lineWidth: 0, aliasDuplicateObjects: false })}`;\n}\n\nfunction printPlan(ctx: ComposeContext, run: ComposeRun): void {\n\tconst { stack, mode, files } = run;\n\tctx.logger.info(`\\n🧱 ${stack.project} — stage ${stack.stage}`);\n\tfor (const app of stack.apps) {\n\t\tctx.logger.info(\n\t\t\t` ${app.name.padEnd(12)} ${app.url.padEnd(40)} ${mode} ${app.ref}`,\n\t\t);\n\t}\n\tfor (const worker of stack.workers) {\n\t\tctx.logger.info(\n\t\t\t` ${worker.name.padEnd(12)} ${`worker ${worker.id} (no route)`.padEnd(40)} ${mode} ${worker.ref}`,\n\t\t);\n\t}\n\tif (stack.infra.length > 0) {\n\t\tctx.logger.info(` infrastructure: ${stack.infra.join(', ')}`);\n\t}\n\tctx.logger.info(\n\t\t`\\n📝 Wrote ${files.length} file(s) under ${stackDir(stack.stage)}/`,\n\t);\n}\n","/**\n * The built-in `compose` target: a stage as one Docker Compose stack behind\n * Caddy, on the machine that runs the deploy.\n *\n * ```bash\n * gkm deploy --target compose --stage production --tag v1.4.0 # what CI pushed\n * gkm deploy --target compose --stage production # built from here\n * gkm deploy --target compose --stage development # the local stage\n * ```\n *\n * - `validate`: the stack (`composeStack`, pure) and, for a tag, every image\n * looked up in the registry — `ImageTagNotFound` before anything changes\n * - `plan`: the stack's files and what a run would create or reuse\n * - `provision`: generated secrets kept, files written, infrastructure up,\n * databases, roles, grants and migrations\n * - `build`: each backend bundled on the host and every image built — or, for\n * a tag, pulled\n * - `release`: `up --wait --remove-orphans`, and each app's image, tag and\n * digest in the stage's state\n * - `verify`: each app asked through Caddy over HTTPS\n *\n * With `push` (`gkm compose --build --push`), run with `buildOnly`, it builds\n * every image and pushes it to `deploy.registry`, and does nothing else.\n *\n * `gkm compose` is this target with a few more switches (`--build`, `--pull`,\n * `--down`), run through the same `deploy()`.\n */\n\nimport { defineTarget } from '../define';\nimport type { DeployTarget } from '../types';\nimport {\n\tbuildCompose,\n\ttype ComposeDeps,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tcomposeResult,\n\tdefaultDeps,\n\tplanCompose,\n\tprovisionCompose,\n\treleaseCompose,\n\tvalidateCompose,\n\tverifyCompose,\n} from './phases';\n\nexport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\ttype HealthRequest,\n\tHealthRequestTimedOut,\n} from './health';\nexport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n\tstackOverrideFile,\n} from './phases';\n\nexport interface ComposeTargetOptions\n\textends Partial<ComposeDeps>,\n\t\tComposeRunOptions {\n\t/** Handed the finished run — `gkm compose` prints and returns from it. */\n\treport?: (run: ComposeRun) => void;\n}\n\n/** The compose target, with its Docker, bundler and probe as given. */\nexport function composeTarget(\n\toptions: ComposeTargetOptions = {},\n): DeployTarget<undefined, ComposeRun> {\n\tconst { mode, push, pin, report, ...given } = options;\n\tconst deps: ComposeDeps = { ...defaultDeps, ...given };\n\n\treturn defineTarget<undefined, ComposeRun>({\n\t\tname: 'compose',\n\t\truntime: 'server',\n\t\tcapabilities: {\n\t\t\trollback: false,\n\t\t\tmigrations: 'target',\n\t\t\timages: true,\n\t\t\t// The stack runs where the deploy does, so the local stage is one\n\t\t\t// it can run — the `gkm dev` hostnames, behind Caddy's own CA.\n\t\t\tlocalStage: true,\n\t\t},\n\t\t// Images are pulled with this machine's own `docker login`.\n\t\tcredentials: [],\n\t\t// Built from the checkout, an image is named after its commit.\n\t\ttag: ({ cwd }) => deps.revision(cwd),\n\t\tvalidate: (ctx) =>\n\t\t\tvalidateCompose(ctx, deps, {\n\t\t\t\t...(mode ? { mode } : {}),\n\t\t\t\t...(push ? { push } : {}),\n\t\t\t\t...(pin ? { pin } : {}),\n\t\t\t}),\n\t\tplan: (ctx, run) => planCompose(ctx, run),\n\t\tprovision: (ctx, run) => provisionCompose(ctx, run, deps),\n\t\tbuild: (ctx, run) => buildCompose(ctx, run, deps),\n\t\trelease: (ctx, run) => releaseCompose(ctx, run, deps),\n\t\tverify: (ctx, run) => verifyCompose(ctx, run, deps),\n\t\tresult: (ctx, run) => {\n\t\t\treport?.(run);\n\t\t\treturn composeResult(ctx, run);\n\t\t},\n\t});\n}\n"],"mappings":"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"}