@geekmidas/cli 10.0.0-alpha.93 → 10.0.0-alpha.94

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 (196) hide show
  1. package/dist/{GoDaddyProvider-Mi3vptSR.mjs → GoDaddyProvider-BRZUWD8z.mjs} +3 -3
  2. package/dist/{GoDaddyProvider-Mi3vptSR.mjs.map → GoDaddyProvider-BRZUWD8z.mjs.map} +1 -1
  3. package/dist/{GoDaddyProvider-BZb-V14e.cjs → GoDaddyProvider-DzguxU_a.cjs} +3 -3
  4. package/dist/{GoDaddyProvider-BZb-V14e.cjs.map → GoDaddyProvider-DzguxU_a.cjs.map} +1 -1
  5. package/dist/{HostingerProvider-1mqD6aG8.mjs → HostingerProvider-Cjh_2Ml6.mjs} +9 -4
  6. package/dist/{HostingerProvider-1mqD6aG8.mjs.map → HostingerProvider-Cjh_2Ml6.mjs.map} +1 -1
  7. package/dist/{HostingerProvider-C6t-PSNe.cjs → HostingerProvider-OdQmKXE3.cjs} +9 -4
  8. package/dist/HostingerProvider-OdQmKXE3.cjs.map +1 -0
  9. package/dist/{LegacyStateStore-CtwO7fwy.mjs → LegacyStateStore-BQZb6-j2.mjs} +3 -2
  10. package/dist/{LegacyStateStore-CtwO7fwy.mjs.map → LegacyStateStore-BQZb6-j2.mjs.map} +1 -1
  11. package/dist/{LegacyStateStore-BlYXQQSE.cjs → LegacyStateStore-D50dgUPc.cjs} +10 -9
  12. package/dist/{LegacyStateStore-BlYXQQSE.cjs.map → LegacyStateStore-D50dgUPc.cjs.map} +1 -1
  13. package/dist/{LocalStateStore-D40_SDmJ.mjs → LocalStateStore-BSaS2535.mjs} +2 -2
  14. package/dist/{LocalStateStore-D40_SDmJ.mjs.map → LocalStateStore-BSaS2535.mjs.map} +1 -1
  15. package/dist/{LocalStateStore-oX_zxj9V.cjs → LocalStateStore-EFBUjuMX.cjs} +8 -8
  16. package/dist/{LocalStateStore-oX_zxj9V.cjs.map → LocalStateStore-EFBUjuMX.cjs.map} +1 -1
  17. package/dist/{S3StateStore-DeI7jtvi.cjs → S3StateStore-C5mv8To3.cjs} +5 -5
  18. package/dist/{S3StateStore-DeI7jtvi.cjs.map → S3StateStore-C5mv8To3.cjs.map} +1 -1
  19. package/dist/{S3StateStore-BzS0IeSt.mjs → S3StateStore-CrFq4UZU.mjs} +2 -2
  20. package/dist/{S3StateStore-BzS0IeSt.mjs.map → S3StateStore-CrFq4UZU.mjs.map} +1 -1
  21. package/dist/{SSMStateStore-k_Ew7TWx.mjs → SSMStateStore-D3Z6mZnA.mjs} +2 -2
  22. package/dist/{SSMStateStore-k_Ew7TWx.mjs.map → SSMStateStore-D3Z6mZnA.mjs.map} +1 -1
  23. package/dist/{SSMStateStore-CaCtrzFL.cjs → SSMStateStore-DuZCH7_v.cjs} +9 -9
  24. package/dist/{SSMStateStore-CaCtrzFL.cjs.map → SSMStateStore-DuZCH7_v.cjs.map} +1 -1
  25. package/dist/{add-CP1podDH.mjs → add-C85isXFl.mjs} +4 -4
  26. package/dist/add-C85isXFl.mjs.map +1 -0
  27. package/dist/{add-VcyJnsPX.cjs → add-DsVDdvon.cjs} +4 -4
  28. package/dist/add-DsVDdvon.cjs.map +1 -0
  29. package/dist/{bundler-Dfsr6KXU.cjs → bundler-BEgUKc4j.cjs} +5 -5
  30. package/dist/{bundler-Dfsr6KXU.cjs.map → bundler-BEgUKc4j.cjs.map} +1 -1
  31. package/dist/{bundler-BWrh-AJH.mjs → bundler-BSHog8CH.mjs} +5 -5
  32. package/dist/{bundler-BWrh-AJH.mjs.map → bundler-BSHog8CH.mjs.map} +1 -1
  33. package/dist/{cli-B8otnZfX.mjs → cli-BsFenyaf.mjs} +9 -5
  34. package/dist/cli-BsFenyaf.mjs.map +1 -0
  35. package/dist/{cli-DL19w4OE.cjs → cli-BvBdv660.cjs} +9 -5
  36. package/dist/cli-BvBdv660.cjs.map +1 -0
  37. package/dist/{compose-BHVKLluX.cjs → compose-Cd09gW-n.cjs} +58 -19
  38. package/dist/compose-Cd09gW-n.cjs.map +1 -0
  39. package/dist/{compose-DrEB_4F-.mjs → compose-D2RFYd_f.mjs} +56 -17
  40. package/dist/compose-D2RFYd_f.mjs.map +1 -0
  41. package/dist/{config-DCCcrOSo.d.cts → config-DvHNMoOp.d.cts} +4 -4
  42. package/dist/{config-CHX5GOo3.d.mts.map → config-DvHNMoOp.d.cts.map} +1 -1
  43. package/dist/{config-CHX5GOo3.d.mts → config-Ngesg4O8.d.mts} +4 -4
  44. package/dist/{config-DCCcrOSo.d.cts.map → config-Ngesg4O8.d.mts.map} +1 -1
  45. package/dist/config.cjs +1 -1
  46. package/dist/config.d.cts +3 -3
  47. package/dist/config.d.mts +3 -3
  48. package/dist/config.mjs +1 -1
  49. package/dist/{credentials-QBu7VgaQ.cjs → credentials-D7XJypNd.cjs} +9 -3
  50. package/dist/{credentials-QBu7VgaQ.cjs.map → credentials-D7XJypNd.cjs.map} +1 -1
  51. package/dist/{credentials-C4KII3PD.mjs → credentials-DpfnUvIR.mjs} +9 -3
  52. package/dist/{credentials-C4KII3PD.mjs.map → credentials-DpfnUvIR.mjs.map} +1 -1
  53. package/dist/deploy/public.cjs +13 -13
  54. package/dist/deploy/public.d.cts +24 -9
  55. package/dist/deploy/public.d.cts.map +1 -1
  56. package/dist/deploy/public.d.mts +24 -9
  57. package/dist/deploy/public.d.mts.map +1 -1
  58. package/dist/deploy/public.mjs +10 -10
  59. package/dist/{deploy-C3Mhnmus.cjs → deploy-C911Akkn.cjs} +125 -11
  60. package/dist/deploy-C911Akkn.cjs.map +1 -0
  61. package/dist/{deploy-DYIyIUYd.mjs → deploy-CeJ5D0xn.mjs} +123 -9
  62. package/dist/deploy-CeJ5D0xn.mjs.map +1 -0
  63. package/dist/{discover-vk2r5giK.d.cts → discover-CTzOSGUF.d.cts} +2 -2
  64. package/dist/{discover-DqwlBVyY.d.mts.map → discover-CTzOSGUF.d.cts.map} +1 -1
  65. package/dist/{discover-DqwlBVyY.d.mts → discover-CihAtaoj.d.mts} +2 -2
  66. package/dist/{discover-vk2r5giK.d.cts.map → discover-CihAtaoj.d.mts.map} +1 -1
  67. package/dist/{dokploy-rivb1RFt.cjs → dokploy-CV7GcobZ.cjs} +2 -2
  68. package/dist/{dokploy-rivb1RFt.cjs.map → dokploy-CV7GcobZ.cjs.map} +1 -1
  69. package/dist/{dokploy-o4I6vb9W.mjs → dokploy-D_aat2Xj.mjs} +2 -2
  70. package/dist/{dokploy-o4I6vb9W.mjs.map → dokploy-D_aat2Xj.mjs.map} +1 -1
  71. package/dist/{encryption-D7zmwzWz.cjs → encryption-DFcivJaO.cjs} +3 -3
  72. package/dist/{encryption-D7zmwzWz.cjs.map → encryption-DFcivJaO.cjs.map} +1 -1
  73. package/dist/{encryption-B6ilrT7p.mjs → encryption-_4qKqtTx.mjs} +3 -3
  74. package/dist/{encryption-B6ilrT7p.mjs.map → encryption-_4qKqtTx.mjs.map} +1 -1
  75. package/dist/{engine-Cfx8fEZU.cjs → engine-Bv-LZpmj.cjs} +10 -9
  76. package/dist/{engine-Cfx8fEZU.cjs.map → engine-Bv-LZpmj.cjs.map} +1 -1
  77. package/dist/{engine-DjEcovm-.mjs → engine-DPMHThkg.mjs} +7 -6
  78. package/dist/{engine-DjEcovm-.mjs.map → engine-DPMHThkg.mjs.map} +1 -1
  79. package/dist/{github-zneTMvnO.cjs → github-Br42NMrW.cjs} +94 -6
  80. package/dist/github-Br42NMrW.cjs.map +1 -0
  81. package/dist/{github-CzBbs43W.mjs → github-xsDT19im.mjs} +94 -6
  82. package/dist/github-xsDT19im.mjs.map +1 -0
  83. package/dist/{index-BiYU7cUl.d.mts → index-BlpcClwM.d.mts} +2 -2
  84. package/dist/{index-BiYU7cUl.d.mts.map → index-BlpcClwM.d.mts.map} +1 -1
  85. package/dist/{index-Dm6V9bwh.d.cts → index-CwLvFqtH.d.cts} +2 -2
  86. package/dist/{index-Dm6V9bwh.d.cts.map → index-CwLvFqtH.d.cts.map} +1 -1
  87. package/dist/index.cjs +147 -116
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.mjs +143 -112
  90. package/dist/index.mjs.map +1 -1
  91. package/dist/{local-Otp74ak0.mjs → local-B7Zv1NoA.mjs} +2 -2
  92. package/dist/{local-Otp74ak0.mjs.map → local-B7Zv1NoA.mjs.map} +1 -1
  93. package/dist/{local-B61kUh0w.cjs → local-OPC9BCZt.cjs} +2 -2
  94. package/dist/{local-B61kUh0w.cjs.map → local-OPC9BCZt.cjs.map} +1 -1
  95. package/dist/{migrate-BaC4w0sb.mjs → migrate-B7evHv7O.mjs} +3 -3
  96. package/dist/{migrate-BaC4w0sb.mjs.map → migrate-B7evHv7O.mjs.map} +1 -1
  97. package/dist/{migrate-C8wTpakT.cjs → migrate-D5jUz20_.cjs} +3 -3
  98. package/dist/{migrate-C8wTpakT.cjs.map → migrate-D5jUz20_.cjs.map} +1 -1
  99. package/dist/{migrate-CsBZKALY.mjs → migrate-DhvFPGLi.mjs} +3 -3
  100. package/dist/{migrate-CsBZKALY.mjs.map → migrate-DhvFPGLi.mjs.map} +1 -1
  101. package/dist/{migrate-DFjbGnSr.cjs → migrate-SkWJotn5.cjs} +3 -3
  102. package/dist/{migrate-DFjbGnSr.cjs.map → migrate-SkWJotn5.cjs.map} +1 -1
  103. package/dist/openapi.cjs +1 -1
  104. package/dist/openapi.d.cts +1 -1
  105. package/dist/openapi.d.mts +1 -1
  106. package/dist/openapi.mjs +1 -1
  107. package/dist/providers-BFeP_mYw.cjs +1098 -0
  108. package/dist/providers-BFeP_mYw.cjs.map +1 -0
  109. package/dist/providers-sTj-BG0S.mjs +1079 -0
  110. package/dist/providers-sTj-BG0S.mjs.map +1 -0
  111. package/dist/reconcile/public.d.cts +2 -2
  112. package/dist/reconcile/public.d.mts +2 -2
  113. package/dist/{resolve-g8htuR80.cjs → resolve-CFEOtRsl.cjs} +4 -4
  114. package/dist/{resolve-g8htuR80.cjs.map → resolve-CFEOtRsl.cjs.map} +1 -1
  115. package/dist/{resolve-Ccjlpnd9.mjs → resolve-Dyd1S2wn.mjs} +4 -4
  116. package/dist/{resolve-Ccjlpnd9.mjs.map → resolve-Dyd1S2wn.mjs.map} +1 -1
  117. package/dist/{rollback--ympG9ss.cjs → rollback-D720SFhV.cjs} +11 -9
  118. package/dist/{rollback--ympG9ss.cjs.map → rollback-D720SFhV.cjs.map} +1 -1
  119. package/dist/{rollback-Drbg0OeR.mjs → rollback-NroNbGC0.mjs} +8 -6
  120. package/dist/{rollback-Drbg0OeR.mjs.map → rollback-NroNbGC0.mjs.map} +1 -1
  121. package/dist/{runtime-_wEVtshH.d.mts → runtime-BRCq6dQ7.d.mts} +2 -2
  122. package/dist/{runtime-D_J3ExJn.d.cts.map → runtime-BRCq6dQ7.d.mts.map} +1 -1
  123. package/dist/{runtime-D_J3ExJn.d.cts → runtime-VktAo_8B.d.cts} +2 -2
  124. package/dist/{runtime-_wEVtshH.d.mts.map → runtime-VktAo_8B.d.cts.map} +1 -1
  125. package/dist/{sandbox-CPJq1Kia.d.mts → sandbox-D1gd0iDz.d.cts} +2 -2
  126. package/dist/{sandbox-CPJq1Kia.d.mts.map → sandbox-D1gd0iDz.d.cts.map} +1 -1
  127. package/dist/{sandbox-JwuPAl7I.d.cts → sandbox-zHnRLCj0.d.mts} +2 -2
  128. package/dist/{sandbox-JwuPAl7I.d.cts.map → sandbox-zHnRLCj0.d.mts.map} +1 -1
  129. package/dist/{secrets-DbPmAS4k.mjs → secrets-CwLauUB_.mjs} +3 -3
  130. package/dist/secrets-CwLauUB_.mjs.map +1 -0
  131. package/dist/{secrets-DJteijZo.cjs → secrets-DAvi_O9g.cjs} +3 -3
  132. package/dist/secrets-DAvi_O9g.cjs.map +1 -0
  133. package/dist/{seeds-c-ByX9je.cjs → seeds-BCg8X36S.cjs} +1143 -2645
  134. package/dist/seeds-BCg8X36S.cjs.map +1 -0
  135. package/dist/{seeds-BSL55F6q.mjs → seeds-CTxTZa-R.mjs} +1289 -2760
  136. package/dist/seeds-CTxTZa-R.mjs.map +1 -0
  137. package/dist/{sniffer-Dq5BS98f.cjs → sniffer-C0z3NB2A.cjs} +572 -3
  138. package/dist/sniffer-C0z3NB2A.cjs.map +1 -0
  139. package/dist/{sniffer-BTtGAtm3.mjs → sniffer-DCcuzHz_.mjs} +496 -5
  140. package/dist/sniffer-DCcuzHz_.mjs.map +1 -0
  141. package/dist/{sst-CnKY-CSh.cjs → sst-DKNH243z.cjs} +3 -3
  142. package/dist/{sst-CnKY-CSh.cjs.map → sst-DKNH243z.cjs.map} +1 -1
  143. package/dist/{sst-BaRXp2Dd.mjs → sst-DRDSDwOk.mjs} +3 -3
  144. package/dist/{sst-BaRXp2Dd.mjs.map → sst-DRDSDwOk.mjs.map} +1 -1
  145. package/dist/{stack-1PeLJS2j.cjs → stack-B3fPDTBg.cjs} +3 -3
  146. package/dist/{stack-1PeLJS2j.cjs.map → stack-B3fPDTBg.cjs.map} +1 -1
  147. package/dist/{stack-Co4uZkAo.mjs → stack-NrdH5ngX.mjs} +3 -3
  148. package/dist/{stack-Co4uZkAo.mjs.map → stack-NrdH5ngX.mjs.map} +1 -1
  149. package/dist/{stages-BI8JvPzI.cjs → stages-CkqP1N4S.cjs} +16 -3
  150. package/dist/stages-CkqP1N4S.cjs.map +1 -0
  151. package/dist/{stages-DY-fQKmo.mjs → stages-veC4TcQe.mjs} +16 -3
  152. package/dist/stages-veC4TcQe.mjs.map +1 -0
  153. package/dist/target/public.cjs +1 -1
  154. package/dist/target/public.d.cts +2 -2
  155. package/dist/target/public.d.mts +2 -2
  156. package/dist/target/public.mjs +1 -1
  157. package/dist/{terminal-8XngdSTo.cjs → terminal-CkUYuAPd.cjs} +2 -2
  158. package/dist/{terminal-8XngdSTo.cjs.map → terminal-CkUYuAPd.cjs.map} +1 -1
  159. package/dist/{terminal-C4XRdwnU.mjs → terminal-DAHs2Zko.mjs} +2 -2
  160. package/dist/{terminal-C4XRdwnU.mjs.map → terminal-DAHs2Zko.mjs.map} +1 -1
  161. package/dist/{types-BibpiHKB.d.cts → types-DMoaFrjg.d.mts} +32 -9
  162. package/dist/types-DMoaFrjg.d.mts.map +1 -0
  163. package/dist/{types-B6lmD3en.d.mts → types-DXyaSmqu.d.cts} +33 -8
  164. package/dist/types-DXyaSmqu.d.cts.map +1 -0
  165. package/dist/workspace/index.cjs +1 -1
  166. package/dist/workspace/index.d.cts +2 -2
  167. package/dist/workspace/index.d.mts +2 -2
  168. package/dist/workspace/index.mjs +1 -1
  169. package/dist/{workspace-Bzw7Zs82.mjs → workspace-DWK1PTXP.mjs} +4 -4
  170. package/dist/workspace-DWK1PTXP.mjs.map +1 -0
  171. package/dist/{workspace-CHOB2Xg3.cjs → workspace-cSyi5nb1.cjs} +4 -4
  172. package/dist/workspace-cSyi5nb1.cjs.map +1 -0
  173. package/package.json +15 -15
  174. package/dist/HostingerProvider-C6t-PSNe.cjs.map +0 -1
  175. package/dist/add-CP1podDH.mjs.map +0 -1
  176. package/dist/add-VcyJnsPX.cjs.map +0 -1
  177. package/dist/cli-B8otnZfX.mjs.map +0 -1
  178. package/dist/cli-DL19w4OE.cjs.map +0 -1
  179. package/dist/compose-BHVKLluX.cjs.map +0 -1
  180. package/dist/compose-DrEB_4F-.mjs.map +0 -1
  181. package/dist/deploy-C3Mhnmus.cjs.map +0 -1
  182. package/dist/deploy-DYIyIUYd.mjs.map +0 -1
  183. package/dist/github-CzBbs43W.mjs.map +0 -1
  184. package/dist/github-zneTMvnO.cjs.map +0 -1
  185. package/dist/secrets-DJteijZo.cjs.map +0 -1
  186. package/dist/secrets-DbPmAS4k.mjs.map +0 -1
  187. package/dist/seeds-BSL55F6q.mjs.map +0 -1
  188. package/dist/seeds-c-ByX9je.cjs.map +0 -1
  189. package/dist/sniffer-BTtGAtm3.mjs.map +0 -1
  190. package/dist/sniffer-Dq5BS98f.cjs.map +0 -1
  191. package/dist/stages-BI8JvPzI.cjs.map +0 -1
  192. package/dist/stages-DY-fQKmo.mjs.map +0 -1
  193. package/dist/types-B6lmD3en.d.mts.map +0 -1
  194. package/dist/types-BibpiHKB.d.cts.map +0 -1
  195. package/dist/workspace-Bzw7Zs82.mjs.map +0 -1
  196. package/dist/workspace-CHOB2Xg3.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"compose-DrEB_4F-.mjs","names":[],"sources":["../src/compose/docker.ts","../src/compose/edge.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 { GkmError } from '../errors';\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 GkmError {\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 GkmError {\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 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 { GkmError } from '../errors';\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 GkmError {\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 * 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';\nimport { GkmError } from '../../errors';\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 GkmError {\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 GkmError {\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, its migrations\n * applied and its seeds run from this machine, and only then do the apps\n * 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\tcheckStackDns,\n\ttype HostLookup,\n\tHostNotPointingAtServer,\n\tisLocalHost,\n\trequiredServerAddress,\n\tSERVER_IPV4_KEY,\n\ttype ServerAddress,\n\tserverAddressHint,\n\tstackHosts,\n\tsystemLookup,\n} from '../../compose/dns';\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 { LOGS_SERVICE, logsAccess, type StackLogs } from '../../compose/logs';\nimport { ComposeTlsFileMissing } from '../../compose/proxy';\nimport { REDIS_SERVICE } from '../../compose/redis';\nimport { deployedStackSecrets } from '../../compose/secrets';\nimport {\n\ttype ComposeStack,\n\tcomposeProject,\n\tcomposeStack,\n\tEDGE_PORT_ENV,\n\tenvFile,\n\tLOG_ROTATION,\n\tLOGS_PORT_ENV,\n\ttype StackApp,\n\tstackDir,\n} from '../../compose/stack';\nimport { EDGE_PROJECT, EDGE_SERVICE } from '../../compose/traefik';\nimport { currentActor } from '../../deploy/actor.js';\nimport { reportDevServices } from '../../deploy/devServices';\nimport type { ResourceChange } from '../../deploy/events';\nimport { imageRef } from '../../deploy/identity.js';\nimport { DeployJournal } from '../../deploy/journal';\nimport {\n\tcreateComposeState,\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 { GkmError } from '../../errors';\nimport { installedFrom } from '../../generators/drivers.js';\nimport {\n\tmigrateDatabases,\n\tplannedSeeds,\n\tSeedFailed,\n\tseedDatabases,\n} from '../../migrate/databases.js';\nimport { verifyStageProviders } from '../../providers/index.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 { loadLocalCredentials } from '../../reconcile/localCredentials.js';\nimport {\n\tensurePostgresLogin,\n\tLEGACY_LOCAL_LOGIN,\n} from '../../reconcile/logins.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 type { StageSecrets } from '../../secrets/types.js';\nimport type { NormalizedWorkspace } from '../../workspace/types.js';\nimport {\n\tDeploySeedsFailed,\n\treportDatabaseRuns,\n\treportPlannedSeeds,\n} from '../seeds';\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/** Bring the stack's Postgres onto its superuser — see `logins.ts`. */\n\tlogins: typeof ensurePostgresLogin;\n\t/** Apply the stage's migrations — `migrateDatabases` by default. */\n\tmigrate: typeof migrateDatabases;\n\t/** Run the stage's seeds, after its migrations — `seedDatabases` by default. */\n\tseed: typeof seedDatabases;\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\t/**\n\t * Resolves a public host to every address it has, for the DNS check —\n\t * the system resolver by default.\n\t */\n\tlookup?: HostLookup;\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 GkmError {\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 GkmError {\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 GkmError {\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 GkmError {\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\tlogs?: 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\tconst logs = env[LOGS_PORT_ENV] ? read(LOGS_PORT_ENV, 0) : undefined;\n\treturn {\n\t\thttps: read(EDGE_PORT_ENV.https, 443),\n\t\thttp: read(EDGE_PORT_ENV.http, 80),\n\t\t...(logs ? { logs } : {}),\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\tlogins: ensurePostgresLogin,\n\tmigrate: migrateDatabases,\n\tseed: seedDatabases,\n\tprobe: httpsProbe,\n\thealthAttempts: 90,\n\thealthIntervalMs: 2_000,\n\tenv: process.env,\n\tlookup: systemLookup,\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 stage that serves real domains names its server — before anything\n\t// else is checked, built or started.\n\tconst server =\n\t\tpush || stage === workspace.stages.local\n\t\t\t? undefined\n\t\t\t: requiredServerAddress(\n\t\t\t\t\tstage,\n\t\t\t\t\tworkspace.domains?.[stage],\n\t\t\t\t\tsecrets?.custom,\n\t\t\t\t);\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\t...(stage === workspace.stages.local\n\t\t\t? {\n\t\t\t\t\tlocalCredentials: (await loadLocalCredentials(workspace)).credentials,\n\t\t\t\t}\n\t\t\t: {}),\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// What the stage's providers created is still there, and the stage's key\n\t// reaches it. A push runs nothing, and the local stage has no providers.\n\tif (!push && stage !== workspace.stages.local) {\n\t\tconst verified = await verifyStageProviders({\n\t\t\tworkspace,\n\t\t\tmanifest,\n\t\t\tstage,\n\t\t\tsecrets: secrets?.custom ?? {},\n\t\t});\n\t\tfor (const line of verified) ctx.logger.info(`✓ ${line} verified`);\n\t}\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\t// Every public host resolves to the stage's server — before Caddy or\n\t// Traefik ask Let's Encrypt for a certificate it could not issue.\n\tif (!push && !stack.local) {\n\t\tawait checkDns(\n\t\t\tctx,\n\t\t\tdeps,\n\t\t\tstackHosts(stack).filter((host) => !isLocalHost(host)),\n\t\t\tserver,\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 GkmError {\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 */\n/**\n * The deploy-time DNS check: each public host resolved with the system\n * resolver and compared with the server's address from the stage's secrets.\n * A dry run warns rather than stops.\n */\nasync function checkDns(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n\thosts: readonly string[],\n\tserver: ServerAddress | undefined,\n): Promise<void> {\n\tconst { workspace, stage } = ctx;\n\tif (hosts.length === 0) return;\n\tif (ctx.skipDnsCheck) {\n\t\tctx.logger.info('🌐 DNS check skipped (--skip-dns-check)');\n\t\treturn;\n\t}\n\tif (!server) {\n\t\tctx.logger.info(\n\t\t\t`🌐 DNS check skipped: no ${SERVER_IPV4_KEY} in '${stage}''s secrets — ${serverAddressHint(stage)}`,\n\t\t);\n\t\treturn;\n\t}\n\ttry {\n\t\tconst ok = await checkStackDns({\n\t\t\tstage,\n\t\t\thosts,\n\t\t\tserver,\n\t\t\tdns: workspace.dns,\n\t\t\tlookup: deps.lookup ?? systemLookup,\n\t\t});\n\t\tctx.logger.info(\n\t\t\t`🌐 ${ok.length} host${ok.length === 1 ? '' : 's'} resolve${ok.length === 1 ? 's' : ''} to ${server.ipv4}`,\n\t\t);\n\t} catch (error) {\n\t\tif (ctx.dryRun && error instanceof HostNotPointingAtServer) {\n\t\t\tctx.logger.warn(`⚠ ${error.message}`);\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n}\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\t// The local stage's logins are this machine's, generated once with\n\t\t// `gkm dev`'s — not the stage's secrets.\n\t\treturn { secrets: stored, generated: [] };\n\t}\n\n\tconst { secrets, generated } = deployedStackSecrets(\n\t\tctx.workspace,\n\t\tctx.stage,\n\t\tstored,\n\t\tmanifest,\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\t// A push migrates and seeds nothing; a release runs every seed, every\n\t// time, so the list is the same whatever the database holds.\n\tif (!run.push && run.stack.infra.includes('postgres')) {\n\t\treportPlannedSeeds(\n\t\t\t(\n\t\t\t\tawait plannedSeeds({ root: ctx.workspace.root, manifest: ctx.manifest })\n\t\t\t).map(({ target, seeds }) => ({ folder: target.seeds, seeds })),\n\t\t\t(line) => ctx.logger.info(line),\n\t\t);\n\t}\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/**\n * Create what the plan names in the stack's Postgres, migrate it, then run\n * its seeds — every one, every time, as each construct's owner.\n */\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\t// A stack an older gkm started made its superuser under the old fixed\n\t// name, with the password this stage derives; it is moved to the\n\t// superuser named now — the local stage's from the old fixed login too.\n\tconst superuser = stack.credential.containers.postgres;\n\tconst login = await deps.logins({\n\t\tport,\n\t\tlogin: superuser,\n\t\tlegacy: [\n\t\t\t{ user: LEGACY_LOCAL_LOGIN.user, password: superuser.password },\n\t\t\t...(stack.local ? [LEGACY_LOCAL_LOGIN] : []),\n\t\t],\n\t});\n\tif (login.notice) ctx.logger.info(login.notice);\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, login.login), 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\tcredentials: {\n\t\t\t...stack.credential.containers,\n\t\t\tpostgres: login.login,\n\t\t},\n\t\tseed: stack.credential.seed,\n\t});\n\tconst options = { root: workspace.root, manifest, sources, env };\n\tconst runs = await deps.migrate(options);\n\n\t// Seeds after migrations, before any app starts: an app that boots with\n\t// its reference data missing fails on the first request that needs it.\n\tconst seeds = await deps\n\t\t.seed({ ...options, stage: ctx.stage })\n\t\t.catch((error: unknown) => {\n\t\t\tif (error instanceof SeedFailed) {\n\t\t\t\tthrow new DeploySeedsFailed(\n\t\t\t\t\tctx.stage,\n\t\t\t\t\terror.construct,\n\t\t\t\t\terror.seed,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\n\treportDatabaseRuns(\n\t\truns.map(({ target, applied }) => ({\n\t\t\tconstruct: target.id,\n\t\t\tfolder: target.migrations,\n\t\t\tapplied,\n\t\t})),\n\t\tseeds.map(({ target, seeded }) => ({\n\t\t\tconstruct: target.id,\n\t\t\tfolder: target.seeds,\n\t\t\tseeded,\n\t\t})),\n\t\t(line) => ctx.logger.info(line),\n\t\t(event) => ctx.emit(event),\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\tcreateComposeState(ctx.stage),\n\t);\n\tconst by = currentActor();\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, by);\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\t// OpenObserve, in the stack, on loopback.\n\t\t\tselfHostedTelemetry: 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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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy-C3Mhnmus.cjs","names":["secretsStoreFor","GkmError","builtinTarget","eventError","resolveTarget","parseTargetOptions","DevServicesNeedServerTarget","discover","constructGlobs","usesTelemetry","derivedApps","deployIdentity","getAppBuildOrder","createStateStore","applicationName","storedCredentials","gkmHome","withOutput","LocalSandbox","findWorkspaceRoot","resolve","withSandbox","eventError","loadWorkspaceConfig"],"sources":["../src/target/secrets.ts","../src/deploy/orchestrate.ts","../src/deploy/deploy.ts"],"sourcesContent":["/**\n * A stage's secrets as a target sees them: read and written through the\n * stage's own store, and masked in everything the run prints once read.\n */\n\nimport { secretsStoreFor } from '../secrets/store';\nimport type { StageSecrets } from '../secrets/types';\nimport type { NormalizedWorkspace } from '../workspace/types';\nimport type { DeploySecrets } from './types';\n\n/**\n * Shorter values are left alone: what a progress line legitimately prints —\n * a port, a stage, an app name — would otherwise come out as `***` wherever\n * a secret happened to share it.\n */\nconst SHORTEST_MASKED = 6;\n\n/** The values a run must never print, and the rewrite that keeps it so. */\nexport class Redactor {\n\tprivate readonly values = new Set<string>();\n\n\tadd(value: string | undefined): void {\n\t\tif (value && value.length >= SHORTEST_MASKED) this.values.add(value);\n\t}\n\n\t/** `text` with every masked value replaced by `***`, longest first. */\n\tredact(text: string): string {\n\t\tif (this.values.size === 0) return text;\n\t\tlet out = text;\n\t\tconst longestFirst = [...this.values].sort((a, b) => b.length - a.length);\n\t\tfor (const value of longestFirst) out = out.replaceAll(value, '***');\n\t\treturn out;\n\t}\n}\n\n/** Every value in `secrets` that is a secret rather than a label. */\nfunction secretValues(secrets: StageSecrets): string[] {\n\treturn [\n\t\tsecrets.seed,\n\t\t...Object.values(secrets.custom ?? {}),\n\t\t...Object.values(secrets.urls ?? {}),\n\t\t...Object.values(secrets.services ?? {}).map(\n\t\t\t(service) => service?.password,\n\t\t),\n\t].filter((value): value is string => typeof value === 'string');\n}\n\n/**\n * The stage's secrets through the store `secrets.store` names for it. Opening\n * one builds a client and makes no request, so a target that never reads them\n * costs nothing.\n */\nexport async function deploySecrets(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\tredactor: Redactor,\n\toptions: { home?: string } = {},\n): Promise<DeploySecrets> {\n\tconst store = await secretsStoreFor(workspace, stage, options);\n\tconst mask = (secrets: StageSecrets) => {\n\t\tfor (const value of secretValues(secrets)) redactor.add(value);\n\t};\n\n\treturn {\n\t\tstore: store.name,\n\t\tasync read() {\n\t\t\tconst secrets = await store.read(stage);\n\t\t\tif (secrets) mask(secrets);\n\t\t\treturn secrets;\n\t\t},\n\t\tasync write(secrets) {\n\t\t\tmask(secrets);\n\t\t\tawait store.write(stage, secrets);\n\t\t},\n\t\tmask: (value) => redactor.add(value),\n\t};\n}\n","/**\n * The run around a target: what every deploy does whatever it deploys\n * through.\n *\n * It loads the workspace, resolves the target, works out the apps and the\n * identity, takes the stage's lock, and calls the target's phases in order,\n * reporting each as it starts, finishes or fails. Everything that is about\n * *where* the stage goes is the target's.\n */\n\nimport { GkmError } from '../errors';\nimport { discover } from '../reconcile/discover.js';\nimport { constructGlobs } from '../reconcile/workspace.js';\nimport { builtinTarget } from '../target/builtins';\nimport {\n\tparseTargetOptions,\n\ttype ResolvedTarget,\n\tresolveTarget,\n} from '../target/resolve';\nimport { deploySecrets, Redactor } from '../target/secrets';\nimport type {\n\tAnyDeployTarget,\n\tDeployPhaseContext,\n\tDeployTargetLogger,\n} from '../target/types';\nimport { resolveStageTelemetry } from '../telemetry/config';\nimport { usesTelemetry } from '../telemetry/edges';\nimport { derivedApps } from '../workspace/derive.js';\nimport { getAppBuildOrder } from '../workspace/index.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { CredentialProvider } from './credentials';\nimport { DevServicesNeedServerTarget } from './devServices';\nimport { type DeployEvent, type DeployPhase, eventError } from './events';\nimport { applicationName, deployIdentity } from './identity.js';\nimport { assertStateOutlivesRun, createStateStore } from './StateStore.js';\nimport type { DeployResult } from './types';\n\n/** What a run deploys, once the workspace is loaded. */\nexport interface DeployRequest {\n\t/** Deployment stage (e.g., 'production', 'staging') */\n\tstage: string;\n\t/** Image tag (default: stage-timestamp) */\n\ttag?: string;\n\t/** Specific apps to deploy (default: all) */\n\tapps?: string[];\n\t/** The target to deploy through. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** On a failed release, roll back every app rather than the failed ones. */\n\tatomic?: boolean;\n\t/**\n\t * `--allow-dev-services`: a deployed stage runs the dev service for every\n\t * bucket and mail it does not account for. Server targets only.\n\t */\n\tallowDevServices?: boolean;\n\t/** `--skip-dns-check`: a server target checks no host's DNS. */\n\tskipDnsCheck?: boolean;\n}\n\n/**\n * What a run is handed by whoever started it: where its events go, where it\n * gets credentials, and whether it may change anything. Nothing in a run\n * reads a terminal or exits the process — that is its caller's business.\n */\nexport interface DeployContext {\n\temit: (event: DeployEvent) => void;\n\tcredentials: CredentialProvider;\n\tsignal?: AbortSignal;\n\t/** Look everything up, create, build and push nothing. */\n\tdryRun: boolean;\n\t/**\n\t * Validate and build — the target's images built, and pushed where it\n\t * pushes them — and nothing else: no lock, nothing provisioned, released,\n\t * verified or recorded. What a CI job runs before a server pulls.\n\t */\n\tbuildOnly?: boolean;\n\t/** The CLI's home, for the stage's keys. Defaults to `GKM_HOME`. */\n\thome?: string;\n\t/** Where spawned processes' output goes. Defaults to the terminal. */\n\tchildOutput?: 'inherit' | 'stderr' | 'ignore';\n\t/** The host's own targets, which win over every other by the same name. */\n\ttargets?: Record<string, AnyDeployTarget>;\n\t/**\n\t * What the run masks in what it prints. `deploy()` passes the one its\n\t * progress lines go through; a run without one masks only its events.\n\t */\n\tredactor?: Redactor;\n}\n\n/** Apps were asked for by name that the workspace does not have. */\nexport class UnknownDeployApps extends GkmError {\n\tconstructor(\n\t\treadonly apps: readonly string[],\n\t\treadonly available: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Unknown apps: ${apps.join(', ')}\\n` +\n\t\t\t\t`Available apps: ${available.join(', ')}`,\n\t\t);\n\t\tthis.name = 'UnknownDeployApps';\n\t}\n}\n\n/** Every app asked for deploys through some other target. */\nexport class NoDeployableApps extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`No apps to deploy through \"${target}\": every selected app deploys somewhere else. Pick the target with --target, or set each app's deploy in gkm.config.ts.`,\n\t\t);\n\t\tthis.name = 'NoDeployableApps';\n\t}\n}\n\n/** A build-only run through a target with no build phase. */\nexport class TargetBuildsNothing extends GkmError {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`\"${target}\" has no build phase, so a build-only run would do nothing. Deploy it in full, or build through a target that builds images (compose).`,\n\t\t);\n\t\tthis.name = 'TargetBuildsNothing';\n\t}\n}\n\n/** A failed rollback, after the failure that called for it. */\nexport class RollbackFailed extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** What failed first, and was being rolled back. */\n\t\treadonly failure: unknown,\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Deploying through \"${target}\" failed, and so did rolling it back: ${cause instanceof Error ? cause.message : String(cause)}. The stage may be part-released; deploy again, or roll it back by hand. The first failure: ${failure instanceof Error ? failure.message : String(failure)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'RollbackFailed';\n\t}\n}\n\n/**\n * Generate image tag from stage and timestamp\n */\nexport function generateTag(stage: string): string {\n\tconst timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\treturn `${stage}-${timestamp}`;\n}\n\n/** Why an app that deploys through another target is left out. */\nfunction elsewhere(target: string, stage: string): string {\n\tconst instead = builtinTarget(target)?.instead?.(stage);\n\tif (instead) return `it deploys through \"${target}\" — ${instead}`;\n\treturn `it deploys through \"${target}\" — run \\`gkm deploy --target ${target} --stage ${stage}\\``;\n}\n\n/**\n * Deploy a workspace's stage through its target.\n *\n * The engine under `deploy()` and `gkm deploy`. It never prompts and never\n * exits: credentials come from `ctx.credentials`, progress goes to\n * `ctx.emit` and to `output`, and every failure is thrown.\n *\n * @internal\n */\nexport async function runDeploy(\n\tsource: NormalizedWorkspace | (() => Promise<NormalizedWorkspace>),\n\trequest: DeployRequest,\n\tctx: DeployContext,\n): Promise<DeployResult> {\n\tconst { stage } = request;\n\tconst redactor = ctx.redactor ?? new Redactor();\n\tconst emit = (event: DeployEvent) =>\n\t\tctx.emit(\n\t\t\tevent.type === 'log'\n\t\t\t\t? { ...event, message: redactor.redact(event.message) }\n\t\t\t\t: event,\n\t\t);\n\n\t/** Run one phase between its events. */\n\tconst phase = async <T>(name: DeployPhase, body: () => Promise<T>) => {\n\t\tctx.signal?.throwIfAborted();\n\t\temit({ type: 'phase.started', phase: name });\n\t\ttry {\n\t\t\tconst value = await body();\n\t\t\temit({ type: 'phase.finished', phase: name });\n\t\t\treturn value;\n\t\t} catch (error) {\n\t\t\temit({ type: 'phase.failed', phase: name, error: eventError(error) });\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tctx.signal?.throwIfAborted();\n\temit({ type: 'phase.started', phase: 'validate' });\n\n\tlet prepared: Prepared;\n\ttry {\n\t\tprepared = await prepare(source, request, ctx, emit, redactor);\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n\tconst { resolved, phaseCtx, store } = prepared;\n\tconst { target } = resolved;\n\n\t// A dry run takes no lock: it writes nothing a lock would protect, and it\n\t// should not stop a real deploy that starts while it is looking.\n\tif (ctx.dryRun) {\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tawait phase('plan', () => target.plan(phaseCtx, run));\n\t\treturn target.result(phaseCtx, run);\n\t}\n\n\t// Building changes no stage — nothing is provisioned, released or\n\t// recorded — so it takes no lock: a CI job building the next release must\n\t// not fail because a server is deploying the last one.\n\tif (ctx.buildOnly) {\n\t\tif (!target.build) throw new TargetBuildsNothing(resolved.name);\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tawait phase('build', () => target.build!(phaseCtx, run));\n\t\treturn target.result(phaseCtx, run);\n\t}\n\n\t// One deploy of a stage at a time. Taken before the target generates,\n\t// provisions or records anything, and held until the run ends however it\n\t// ends. A second run of the stage — another CI job, a laptop — gets\n\t// `StateLocked` naming this one instead of racing it; a run killed with\n\t// the lock held is released with `gkm state:unlock`.\n\tlet lock: Awaited<ReturnType<typeof store.lock>>;\n\ttry {\n\t\t// A CI runner's disk is gone when the job ends; state kept on it is\n\t\t// lost with it, and the next run recreates every resource.\n\t\tassertStateOutlivesRun(phaseCtx.workspace, stage, 'deploy');\n\t\tlock = await store.lock(stage, { operation: 'deploy' });\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n\n\ttry {\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tif (target.provision) {\n\t\t\tawait phase('provision', () => target.provision!(phaseCtx, run));\n\t\t}\n\t\tif (target.build) {\n\t\t\tawait phase('build', () => target.build!(phaseCtx, run));\n\t\t}\n\n\t\tlet releasing: 'release' | 'verify' = 'release';\n\t\ttry {\n\t\t\tawait phase('release', () => target.release(phaseCtx, run));\n\t\t\treleasing = 'verify';\n\t\t\tif (target.verify) {\n\t\t\t\tawait phase('verify', () => target.verify!(phaseCtx, run));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// The caller stopping the run is not a release to undo.\n\t\t\tif (ctx.signal?.aborted || !target.capabilities.rollback) throw error;\n\t\t\tif (!target.rollback) throw error;\n\t\t\ttry {\n\t\t\t\tawait phase('rollback', () =>\n\t\t\t\t\ttarget.rollback!(phaseCtx, run, { phase: releasing, error }),\n\t\t\t\t);\n\t\t\t} catch (rollbackError) {\n\t\t\t\tthrow new RollbackFailed(resolved.name, error, rollbackError);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn await target.result(phaseCtx, run);\n\t} finally {\n\t\tawait lock.release();\n\t}\n}\n\n/** `validate`, then the run's `deploy.started`, inside the validate phase. */\nasync function validate(\n\ttarget: AnyDeployTarget,\n\tphaseCtx: DeployPhaseContext<unknown>,\n\temit: (event: DeployEvent) => void,\n): Promise<unknown> {\n\ttry {\n\t\tconst run = await target.validate(phaseCtx);\n\t\tconst skipped = new Set(phaseCtx.skipped.map((s) => s.app));\n\t\temit({\n\t\t\ttype: 'deploy.started',\n\t\t\tstage: phaseCtx.stage,\n\t\t\ttarget: phaseCtx.target,\n\t\t\tidentity: phaseCtx.identity.key,\n\t\t\ttag: phaseCtx.tag,\n\t\t\tapps: phaseCtx.apps.filter((app) => !skipped.has(app)),\n\t\t\tdryRun: phaseCtx.dryRun,\n\t\t});\n\t\temit({ type: 'phase.finished', phase: 'validate' });\n\t\treturn run;\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n}\n\ninterface Prepared {\n\tresolved: ResolvedTarget;\n\tphaseCtx: DeployPhaseContext<unknown>;\n\tstore: Awaited<ReturnType<typeof createStateStore>>;\n}\n\n/** Everything the phases are handed, worked out before the first of them. */\nasync function prepare(\n\tsource: NormalizedWorkspace | (() => Promise<NormalizedWorkspace>),\n\trequest: DeployRequest,\n\tctx: DeployContext,\n\temit: (event: DeployEvent) => void,\n\tredactor: Redactor,\n): Promise<Prepared> {\n\tconst { stage } = request;\n\tconst configured = typeof source === 'function' ? await source() : source;\n\n\t// Before anything is provisioned: a typo'd stage would otherwise create a\n\t// whole second environment under the wrong name. The local stage is left\n\t// to the target, which says whether it can run it.\n\tconst local = stage === configured.stages.local;\n\tif (!local) assertDeployedStage(configured.stages, stage);\n\n\t// Before anything is discovered or derived: a target that cannot be found\n\t// — or a package that would not load — fails a deploy that has done\n\t// nothing yet.\n\tconst targetName = request.target ?? configured.deploy?.default ?? 'dokploy';\n\tconst resolved = await resolveTarget(targetName, {\n\t\tworkspace: configured,\n\t\tstage,\n\t\t...(ctx.targets ? { host: ctx.targets } : {}),\n\t});\n\tif (local && !resolved.target.capabilities.localStage) {\n\t\tassertDeployedStage(configured.stages, stage);\n\t}\n\tconst options = await parseTargetOptions(resolved);\n\n\t// Before anything is discovered: dev services asked of a target that runs\n\t// no containers fail a deploy that has done nothing.\n\tconst allowDevServices = request.allowDevServices === true;\n\tif (allowDevServices && resolved.target.runtime === 'aws') {\n\t\tthrow new DevServicesNeedServerTarget(targetName);\n\t}\n\n\t// What to deploy comes from the manifest.\n\t//\n\t// Discovered here rather than by the target, because the list of things\n\t// to deploy is the *declarations* — one `rest-api` is one server, one\n\t// `site` is one site — and the config only says how to run each. A project\n\t// that declares no surfaces keeps its configured apps, so adopting\n\t// constructs stays something you do a piece at a time.\n\tconst runnables: Record<string, string[]> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(configured),\n\t\tcwd: configured.root,\n\t\trunnables,\n\t\tbackground,\n\t});\n\t// Where the stage's telemetry goes, settled before anything is built: a\n\t// stage that uses a `Telemetry` node on a target that cannot choose for it\n\t// — AWS has no self-hosted provider — fails here, naming the config.\n\tresolveStageTelemetry({\n\t\t...(configured.deploy?.telemetry\n\t\t\t? { telemetry: configured.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal,\n\t\ttarget: targetName,\n\t\truntime: resolved.target.runtime,\n\t\tselfHosted: resolved.target.capabilities.selfHostedTelemetry === true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\n\tconst units = derivedApps(manifest, configured);\n\tconst workspace: NormalizedWorkspace =\n\t\tObject.keys(units).length > 0 ? { ...configured, apps: units } : configured;\n\n\t// What every resource this deploy touches is named and claimed by —\n\t// resolved first, so a namespace that cannot be a name fails before\n\t// anything is built.\n\tconst identity = deployIdentity(workspace, stage);\n\tconst tag =\n\t\trequest.tag ??\n\t\t(resolved.target.tag\n\t\t\t? await resolved.target.tag({ cwd: workspace.root, stage })\n\t\t\t: generateTag(stage));\n\n\t// The apps asked for, in dependency order.\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlet selected = buildOrder;\n\tif (request.apps && request.apps.length > 0) {\n\t\tconst unknown = request.apps.filter((name) => !workspace.apps[name]);\n\t\tif (unknown.length > 0) {\n\t\t\tthrow new UnknownDeployApps(unknown, Object.keys(workspace.apps));\n\t\t}\n\t\tselected = buildOrder.filter((name) => request.apps!.includes(name));\n\t}\n\n\tconst skipped: { app: string; reason: string }[] = [];\n\tconst skip = (app: string, reason: string) => {\n\t\tskipped.push({ app, reason });\n\t\temit({ type: 'app.skipped', app, reason });\n\t};\n\n\t// An app that names another target deploys there, in a run of its own.\n\t// One on the default follows the run, so `--target` moves the stage\n\t// without every app having to be told.\n\tconst byDefault = configured.deploy?.default ?? 'dokploy';\n\tconst apps = selected.filter((name) => {\n\t\tconst own = workspace.apps[name]!.resolvedDeployTarget;\n\t\tconst deploysThrough = own === byDefault ? targetName : own;\n\t\tif (deploysThrough === targetName) return true;\n\t\tskip(name, elsewhere(deploysThrough, stage));\n\t\treturn false;\n\t});\n\tif (apps.length === 0) throw new NoDeployableApps(stage, targetName);\n\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\tconst secrets = await deploySecrets(workspace, stage, redactor, {\n\t\t...(ctx.home ? { home: ctx.home } : {}),\n\t});\n\n\tconst line =\n\t\t(level: 'info' | 'warn' | 'error') =>\n\t\t(message: string): void =>\n\t\t\temit({ type: 'log', level, message });\n\tconst logger: DeployTargetLogger = {\n\t\tinfo: line('info'),\n\t\twarn: line('warn'),\n\t\terror: line('error'),\n\t};\n\n\tconst phaseCtx: DeployPhaseContext<unknown> = {\n\t\ttarget: targetName,\n\t\tcwd: workspace.root,\n\t\tstage,\n\t\ttag,\n\t\ttagGiven: request.tag !== undefined,\n\t\tapps,\n\t\tskipped,\n\t\tidentity,\n\t\tworkspace,\n\t\tmanifest,\n\t\trunnables,\n\t\tbackground,\n\t\toptions,\n\t\tdryRun: ctx.dryRun,\n\t\tatomic: request.atomic ?? false,\n\t\tallowDevServices,\n\t\t...(request.skipDnsCheck ? { skipDnsCheck: true } : {}),\n\t\tcredentials: ctx.credentials,\n\t\tstate: store,\n\t\tsecrets,\n\t\tlogger,\n\t\tsignal: ctx.signal ?? new AbortController().signal,\n\t\tchildOutput: ctx.childOutput ?? 'inherit',\n\t\temit,\n\t\tskip,\n\t\tname: (resource) => applicationName(identity, resource),\n\t};\n\n\treturn { resolved, phaseCtx, store };\n}\n","/**\n * `deploy()`: a deploy as a library call.\n *\n * `gkm deploy` could only be driven from an interactive terminal: it prompted\n * for what it lacked and exited the process on failure, worked out of\n * `process.cwd()`, and reported progress by printing. Here the caller says\n * where the project is, hands over the credentials and a signal, and gets back\n * a run — events to iterate while it goes, and a structured result at the end.\n * Nothing below this asks a person anything or ends the process; `gkm deploy`\n * is a thin wrapper that does both.\n */\n\nimport { resolve } from 'node:path';\nimport { findWorkspaceRoot, loadWorkspaceConfig } from '../config';\nimport { gkmHome } from '../home';\nimport { type OutputLevel, withOutput } from '../output';\nimport { LocalSandbox } from '../sandbox/local';\nimport { type Sandbox, withSandbox } from '../sandbox/sandbox';\nimport { Redactor } from '../target/secrets';\nimport type { AnyDeployTarget } from '../target/types';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { type CredentialProvider, storedCredentials } from './credentials';\nimport { type DeployEvent, eventError } from './events';\nimport { type DeployContext, runDeploy } from './orchestrate';\nimport type { DeployResult } from './types';\n\n/**\n * Where a run's progress lines go, besides its events. `@geekmidas/logger`'s\n * `Logger` is one.\n */\nexport interface DeployLogger {\n\tinfo(message: string): void;\n\twarn(message: string): void;\n\terror?(message: string): void;\n}\n\nexport interface DeployInput {\n\t/**\n\t * The project to deploy: the directory holding `gkm.config.ts`, or any\n\t * directory inside it. Never assumed to be `process.cwd()`.\n\t */\n\tcwd: string;\n\t/**\n\t * The stage to deploy — one of the config's deployed stages, or its local\n\t * stage through a target that runs one (`compose`).\n\t */\n\tstage: string;\n\t/**\n\t * The target to deploy through, by name. Defaults to `deploy.default`,\n\t * else `dokploy`.\n\t */\n\ttarget?: string;\n\t/**\n\t * The host's own targets, by name. Consulted before the built-ins and the\n\t * config's `deploy.targets`, so a host can deploy through an\n\t * implementation of its own — `{ dokploy: myDokploy }` included.\n\t */\n\ttargets?: Record<string, AnyDeployTarget>;\n\t/** The image tag. Defaults to `<stage>-<timestamp>`. */\n\ttag?: string;\n\t/** Deploy only these apps (in dependency order). Defaults to all. */\n\tapps?: string[];\n\t/**\n\t * Look everything up and report what would happen — as `resource.planned`\n\t * events — without taking the lock, writing state, generating secrets,\n\t * changing Dokploy or building and pushing images.\n\t */\n\tdryRun?: boolean;\n\t/**\n\t * Validate and build only: the target's images built — and pushed, where\n\t * it pushes them — with no lock taken and nothing provisioned, released,\n\t * verified or recorded. `gkm compose --build --push` runs this way.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * When a release or its verification fails, roll back every app the run\n\t * released rather than only the ones that failed — on a target that can\n\t * roll back. For apps that must move together.\n\t */\n\tatomic?: boolean;\n\t/**\n\t * Where credentials come from. Defaults to the environment, then the\n\t * logins `gkm login` stored. A credential no provider has stops the run\n\t * with `MissingCredential`; nothing prompts.\n\t */\n\tcredentials?: CredentialProvider;\n\t/**\n\t * On a server target, run a dev service for every construct a deployed\n\t * stage does not account for — no key in its secrets, and no provider\n\t * (`deploy.objects`) backing its kind: MinIO for a bucket, Mailpit for\n\t * mail. Neither is production-grade — Mailpit delivers no mail — and every\n\t * run that uses one emits `dev-service.used`. Without it, a deployed stage\n\t * missing a mail or storage key fails with `ExternalServicesNotConfigured`;\n\t * on an AWS target it fails with `DevServicesNeedServerTarget`.\n\t */\n\tallowDevServices?: boolean;\n\t/**\n\t * Do not check, on a server target, that each public host resolves to\n\t * the stage's server (`GKM_SERVER_IPV4`) before the stack starts — for a CDN\n\t * or proxy in front of the server.\n\t */\n\tskipDnsCheck?: boolean;\n\t/** Receives each progress line as it is written. Defaults to none. */\n\tlogger?: DeployLogger;\n\t/**\n\t * Stops the run: in-flight Dokploy requests and docker children are\n\t * cancelled, the stage's lock is released, and `result` rejects with the\n\t * signal's reason.\n\t */\n\tsignal?: AbortSignal;\n\t/**\n\t * The CLI's home: stage keys and stored logins. Defaults to `GKM_HOME`,\n\t * else `~/.gkm`.\n\t */\n\thome?: string;\n\t/**\n\t * Where docker's own output goes: the host's terminal (`inherit`, the\n\t * default), its stderr, or nowhere.\n\t */\n\tchildOutput?: 'inherit' | 'stderr' | 'ignore';\n\t/**\n\t * Where the project's own code runs: loading `gkm.config.ts`, discovering\n\t * its constructs, sniffing each app's environment. Defaults to a\n\t * `LocalSandbox` on the project — a child process here with an\n\t * allowlisted environment, for a project the host trusts.\n\t *\n\t * A host deploying repositories it does not trust passes one that\n\t * isolates — a container per build — and the config then reaches the\n\t * deploy only as data. Credentials never enter a sandbox: they go from\n\t * `credentials` to the steps that provision, push and release.\n\t */\n\tsandbox?: Sandbox;\n}\n\n/** A deploy in progress. */\nexport interface DeployRun extends AsyncIterable<DeployEvent> {\n\t/**\n\t * What the deploy did, once it is done. Rejects with the error that\n\t * stopped it — `MissingCredential`, `StateLocked`, `ProjectNotOwned`, … —\n\t * after a `deploy.failed` event carrying the same.\n\t */\n\treadonly result: Promise<DeployResult>;\n}\n\n/**\n * Every event a run emits, kept so that each iteration — however late it\n * starts — sees the run from its first event to its last.\n */\nclass EventLog {\n\tprivate readonly events: DeployEvent[] = [];\n\tprivate closed = false;\n\tprivate waiting: (() => void)[] = [];\n\n\tpush(event: DeployEvent): void {\n\t\tthis.events.push(event);\n\t\tthis.wake();\n\t}\n\n\tclose(): void {\n\t\tthis.closed = true;\n\t\tthis.wake();\n\t}\n\n\tprivate wake(): void {\n\t\tconst waiting = this.waiting;\n\t\tthis.waiting = [];\n\t\tfor (const resume of waiting) resume();\n\t}\n\n\tasync *iterate(): AsyncGenerator<DeployEvent> {\n\t\tlet next = 0;\n\t\twhile (true) {\n\t\t\tif (next < this.events.length) {\n\t\t\t\tyield this.events[next++]!;\n\t\t\t} else if (this.closed) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tawait new Promise<void>((resume) => this.waiting.push(resume));\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction forward(\n\tlogger: DeployLogger | undefined,\n\tlevel: OutputLevel,\n\tmessage: string,\n): void {\n\tif (!logger) return;\n\tif (level === 'info') logger.info(message);\n\telse if (level === 'error' && logger.error) logger.error(message);\n\telse logger.warn(message);\n}\n\n/**\n * Deploy a project's stage.\n *\n * ```ts\n * import { deploy } from '@geekmidas/cli/deploy';\n *\n * const run = deploy({ cwd: '/srv/checkouts/shop', stage: 'production' });\n * for await (const event of run) {\n * if (event.type === 'app.deployed') console.log(event.app, event.url);\n * }\n * const result = await run.result;\n * ```\n *\n * The run starts at once; iterating it is optional, and an iteration started\n * late still sees every event from the first.\n */\nexport function deploy(input: DeployInput): DeployRun {\n\tconst log = new EventLog();\n\t// Every secret the run reads is masked in every line it reports — in the\n\t// events and in what the logger is handed.\n\tconst redactor = new Redactor();\n\tconst emit = (event: DeployEvent) => {\n\t\tconst masked =\n\t\t\tevent.type === 'log'\n\t\t\t\t? { ...event, message: redactor.redact(event.message) }\n\t\t\t\t: event;\n\t\tlog.push(masked);\n\t\tif (masked.type === 'log') {\n\t\t\tforward(input.logger, masked.level, masked.message);\n\t\t}\n\t};\n\n\tconst ctx: DeployContext = {\n\t\temit,\n\t\tcredentials:\n\t\t\tinput.credentials ?? storedCredentials({ home: input.home ?? gkmHome() }),\n\t\tdryRun: input.dryRun ?? false,\n\t\t...(input.buildOnly ? { buildOnly: true } : {}),\n\t\thome: input.home ?? gkmHome(),\n\t\tredactor,\n\t\t...(input.signal ? { signal: input.signal } : {}),\n\t\t...(input.childOutput ? { childOutput: input.childOutput } : {}),\n\t\t...(input.targets ? { targets: input.targets } : {}),\n\t};\n\n\t// Every line anything in the run writes through `output` — the deploy's\n\t// own, the Dockerfile generator's, discovery's warnings — becomes an event\n\t// of this run, and of no other.\n\tconst result = withOutput(\n\t\t(level, message) => emit({ type: 'log', level, message }),\n\t\tasync () => {\n\t\t\ttry {\n\t\t\t\tinput.signal?.throwIfAborted();\n\t\t\t\tconst sandbox =\n\t\t\t\t\tinput.sandbox ??\n\t\t\t\t\tnew LocalSandbox({ root: findWorkspaceRoot(resolve(input.cwd)) });\n\t\t\t\t// Every step of the run that executes the project's code — the\n\t\t\t\t// engine's own discoveries and sniffs included — runs in it.\n\t\t\t\tconst deployed = await withSandbox(sandbox, () =>\n\t\t\t\t\trunDeploy(\n\t\t\t\t\t\t() => load(input, sandbox),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstage: input.stage,\n\t\t\t\t\t\t\t...(input.target ? { target: input.target } : {}),\n\t\t\t\t\t\t\t...(input.tag ? { tag: input.tag } : {}),\n\t\t\t\t\t\t\t...(input.apps ? { apps: input.apps } : {}),\n\t\t\t\t\t\t\t...(input.atomic ? { atomic: true } : {}),\n\t\t\t\t\t\t\t...(input.allowDevServices\n\t\t\t\t\t\t\t\t? { allowDevServices: input.allowDevServices }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(input.skipDnsCheck ? { skipDnsCheck: true } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\temit({ type: 'deploy.finished', result: deployed });\n\t\t\t\treturn deployed;\n\t\t\t} catch (error) {\n\t\t\t\temit({ type: 'deploy.failed', error: eventError(error) });\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tlog.close();\n\t\t\t}\n\t\t},\n\t);\n\n\t// A caller that only iterates still learns of the failure from the\n\t// `deploy.failed` event; the rejection must not also crash its process as\n\t// unhandled. Awaiting `result` still rejects.\n\tresult.catch(() => {});\n\n\treturn {\n\t\tresult,\n\t\t[Symbol.asyncIterator]: () => log.iterate(),\n\t};\n}\n\n/**\n * The workspace at `input.cwd`. The stage is checked by the run, once it\n * knows the target: one that runs on this machine may take the local stage.\n */\nasync function load(\n\tinput: DeployInput,\n\tsandbox: Sandbox,\n): Promise<NormalizedWorkspace> {\n\tconst { workspace } = await loadWorkspaceConfig(resolve(input.cwd), {\n\t\tsandbox,\n\t});\n\treturn workspace;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy-DYIyIUYd.mjs","names":[],"sources":["../src/target/secrets.ts","../src/deploy/orchestrate.ts","../src/deploy/deploy.ts"],"sourcesContent":["/**\n * A stage's secrets as a target sees them: read and written through the\n * stage's own store, and masked in everything the run prints once read.\n */\n\nimport { secretsStoreFor } from '../secrets/store';\nimport type { StageSecrets } from '../secrets/types';\nimport type { NormalizedWorkspace } from '../workspace/types';\nimport type { DeploySecrets } from './types';\n\n/**\n * Shorter values are left alone: what a progress line legitimately prints —\n * a port, a stage, an app name — would otherwise come out as `***` wherever\n * a secret happened to share it.\n */\nconst SHORTEST_MASKED = 6;\n\n/** The values a run must never print, and the rewrite that keeps it so. */\nexport class Redactor {\n\tprivate readonly values = new Set<string>();\n\n\tadd(value: string | undefined): void {\n\t\tif (value && value.length >= SHORTEST_MASKED) this.values.add(value);\n\t}\n\n\t/** `text` with every masked value replaced by `***`, longest first. */\n\tredact(text: string): string {\n\t\tif (this.values.size === 0) return text;\n\t\tlet out = text;\n\t\tconst longestFirst = [...this.values].sort((a, b) => b.length - a.length);\n\t\tfor (const value of longestFirst) out = out.replaceAll(value, '***');\n\t\treturn out;\n\t}\n}\n\n/** Every value in `secrets` that is a secret rather than a label. */\nfunction secretValues(secrets: StageSecrets): string[] {\n\treturn [\n\t\tsecrets.seed,\n\t\t...Object.values(secrets.custom ?? {}),\n\t\t...Object.values(secrets.urls ?? {}),\n\t\t...Object.values(secrets.services ?? {}).map(\n\t\t\t(service) => service?.password,\n\t\t),\n\t].filter((value): value is string => typeof value === 'string');\n}\n\n/**\n * The stage's secrets through the store `secrets.store` names for it. Opening\n * one builds a client and makes no request, so a target that never reads them\n * costs nothing.\n */\nexport async function deploySecrets(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\tredactor: Redactor,\n\toptions: { home?: string } = {},\n): Promise<DeploySecrets> {\n\tconst store = await secretsStoreFor(workspace, stage, options);\n\tconst mask = (secrets: StageSecrets) => {\n\t\tfor (const value of secretValues(secrets)) redactor.add(value);\n\t};\n\n\treturn {\n\t\tstore: store.name,\n\t\tasync read() {\n\t\t\tconst secrets = await store.read(stage);\n\t\t\tif (secrets) mask(secrets);\n\t\t\treturn secrets;\n\t\t},\n\t\tasync write(secrets) {\n\t\t\tmask(secrets);\n\t\t\tawait store.write(stage, secrets);\n\t\t},\n\t\tmask: (value) => redactor.add(value),\n\t};\n}\n","/**\n * The run around a target: what every deploy does whatever it deploys\n * through.\n *\n * It loads the workspace, resolves the target, works out the apps and the\n * identity, takes the stage's lock, and calls the target's phases in order,\n * reporting each as it starts, finishes or fails. Everything that is about\n * *where* the stage goes is the target's.\n */\n\nimport { GkmError } from '../errors';\nimport { discover } from '../reconcile/discover.js';\nimport { constructGlobs } from '../reconcile/workspace.js';\nimport { builtinTarget } from '../target/builtins';\nimport {\n\tparseTargetOptions,\n\ttype ResolvedTarget,\n\tresolveTarget,\n} from '../target/resolve';\nimport { deploySecrets, Redactor } from '../target/secrets';\nimport type {\n\tAnyDeployTarget,\n\tDeployPhaseContext,\n\tDeployTargetLogger,\n} from '../target/types';\nimport { resolveStageTelemetry } from '../telemetry/config';\nimport { usesTelemetry } from '../telemetry/edges';\nimport { derivedApps } from '../workspace/derive.js';\nimport { getAppBuildOrder } from '../workspace/index.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { CredentialProvider } from './credentials';\nimport { DevServicesNeedServerTarget } from './devServices';\nimport { type DeployEvent, type DeployPhase, eventError } from './events';\nimport { applicationName, deployIdentity } from './identity.js';\nimport { assertStateOutlivesRun, createStateStore } from './StateStore.js';\nimport type { DeployResult } from './types';\n\n/** What a run deploys, once the workspace is loaded. */\nexport interface DeployRequest {\n\t/** Deployment stage (e.g., 'production', 'staging') */\n\tstage: string;\n\t/** Image tag (default: stage-timestamp) */\n\ttag?: string;\n\t/** Specific apps to deploy (default: all) */\n\tapps?: string[];\n\t/** The target to deploy through. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** On a failed release, roll back every app rather than the failed ones. */\n\tatomic?: boolean;\n\t/**\n\t * `--allow-dev-services`: a deployed stage runs the dev service for every\n\t * bucket and mail it does not account for. Server targets only.\n\t */\n\tallowDevServices?: boolean;\n\t/** `--skip-dns-check`: a server target checks no host's DNS. */\n\tskipDnsCheck?: boolean;\n}\n\n/**\n * What a run is handed by whoever started it: where its events go, where it\n * gets credentials, and whether it may change anything. Nothing in a run\n * reads a terminal or exits the process — that is its caller's business.\n */\nexport interface DeployContext {\n\temit: (event: DeployEvent) => void;\n\tcredentials: CredentialProvider;\n\tsignal?: AbortSignal;\n\t/** Look everything up, create, build and push nothing. */\n\tdryRun: boolean;\n\t/**\n\t * Validate and build — the target's images built, and pushed where it\n\t * pushes them — and nothing else: no lock, nothing provisioned, released,\n\t * verified or recorded. What a CI job runs before a server pulls.\n\t */\n\tbuildOnly?: boolean;\n\t/** The CLI's home, for the stage's keys. Defaults to `GKM_HOME`. */\n\thome?: string;\n\t/** Where spawned processes' output goes. Defaults to the terminal. */\n\tchildOutput?: 'inherit' | 'stderr' | 'ignore';\n\t/** The host's own targets, which win over every other by the same name. */\n\ttargets?: Record<string, AnyDeployTarget>;\n\t/**\n\t * What the run masks in what it prints. `deploy()` passes the one its\n\t * progress lines go through; a run without one masks only its events.\n\t */\n\tredactor?: Redactor;\n}\n\n/** Apps were asked for by name that the workspace does not have. */\nexport class UnknownDeployApps extends GkmError {\n\tconstructor(\n\t\treadonly apps: readonly string[],\n\t\treadonly available: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Unknown apps: ${apps.join(', ')}\\n` +\n\t\t\t\t`Available apps: ${available.join(', ')}`,\n\t\t);\n\t\tthis.name = 'UnknownDeployApps';\n\t}\n}\n\n/** Every app asked for deploys through some other target. */\nexport class NoDeployableApps extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`No apps to deploy through \"${target}\": every selected app deploys somewhere else. Pick the target with --target, or set each app's deploy in gkm.config.ts.`,\n\t\t);\n\t\tthis.name = 'NoDeployableApps';\n\t}\n}\n\n/** A build-only run through a target with no build phase. */\nexport class TargetBuildsNothing extends GkmError {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`\"${target}\" has no build phase, so a build-only run would do nothing. Deploy it in full, or build through a target that builds images (compose).`,\n\t\t);\n\t\tthis.name = 'TargetBuildsNothing';\n\t}\n}\n\n/** A failed rollback, after the failure that called for it. */\nexport class RollbackFailed extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** What failed first, and was being rolled back. */\n\t\treadonly failure: unknown,\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Deploying through \"${target}\" failed, and so did rolling it back: ${cause instanceof Error ? cause.message : String(cause)}. The stage may be part-released; deploy again, or roll it back by hand. The first failure: ${failure instanceof Error ? failure.message : String(failure)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'RollbackFailed';\n\t}\n}\n\n/**\n * Generate image tag from stage and timestamp\n */\nexport function generateTag(stage: string): string {\n\tconst timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\treturn `${stage}-${timestamp}`;\n}\n\n/** Why an app that deploys through another target is left out. */\nfunction elsewhere(target: string, stage: string): string {\n\tconst instead = builtinTarget(target)?.instead?.(stage);\n\tif (instead) return `it deploys through \"${target}\" — ${instead}`;\n\treturn `it deploys through \"${target}\" — run \\`gkm deploy --target ${target} --stage ${stage}\\``;\n}\n\n/**\n * Deploy a workspace's stage through its target.\n *\n * The engine under `deploy()` and `gkm deploy`. It never prompts and never\n * exits: credentials come from `ctx.credentials`, progress goes to\n * `ctx.emit` and to `output`, and every failure is thrown.\n *\n * @internal\n */\nexport async function runDeploy(\n\tsource: NormalizedWorkspace | (() => Promise<NormalizedWorkspace>),\n\trequest: DeployRequest,\n\tctx: DeployContext,\n): Promise<DeployResult> {\n\tconst { stage } = request;\n\tconst redactor = ctx.redactor ?? new Redactor();\n\tconst emit = (event: DeployEvent) =>\n\t\tctx.emit(\n\t\t\tevent.type === 'log'\n\t\t\t\t? { ...event, message: redactor.redact(event.message) }\n\t\t\t\t: event,\n\t\t);\n\n\t/** Run one phase between its events. */\n\tconst phase = async <T>(name: DeployPhase, body: () => Promise<T>) => {\n\t\tctx.signal?.throwIfAborted();\n\t\temit({ type: 'phase.started', phase: name });\n\t\ttry {\n\t\t\tconst value = await body();\n\t\t\temit({ type: 'phase.finished', phase: name });\n\t\t\treturn value;\n\t\t} catch (error) {\n\t\t\temit({ type: 'phase.failed', phase: name, error: eventError(error) });\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tctx.signal?.throwIfAborted();\n\temit({ type: 'phase.started', phase: 'validate' });\n\n\tlet prepared: Prepared;\n\ttry {\n\t\tprepared = await prepare(source, request, ctx, emit, redactor);\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n\tconst { resolved, phaseCtx, store } = prepared;\n\tconst { target } = resolved;\n\n\t// A dry run takes no lock: it writes nothing a lock would protect, and it\n\t// should not stop a real deploy that starts while it is looking.\n\tif (ctx.dryRun) {\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tawait phase('plan', () => target.plan(phaseCtx, run));\n\t\treturn target.result(phaseCtx, run);\n\t}\n\n\t// Building changes no stage — nothing is provisioned, released or\n\t// recorded — so it takes no lock: a CI job building the next release must\n\t// not fail because a server is deploying the last one.\n\tif (ctx.buildOnly) {\n\t\tif (!target.build) throw new TargetBuildsNothing(resolved.name);\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tawait phase('build', () => target.build!(phaseCtx, run));\n\t\treturn target.result(phaseCtx, run);\n\t}\n\n\t// One deploy of a stage at a time. Taken before the target generates,\n\t// provisions or records anything, and held until the run ends however it\n\t// ends. A second run of the stage — another CI job, a laptop — gets\n\t// `StateLocked` naming this one instead of racing it; a run killed with\n\t// the lock held is released with `gkm state:unlock`.\n\tlet lock: Awaited<ReturnType<typeof store.lock>>;\n\ttry {\n\t\t// A CI runner's disk is gone when the job ends; state kept on it is\n\t\t// lost with it, and the next run recreates every resource.\n\t\tassertStateOutlivesRun(phaseCtx.workspace, stage, 'deploy');\n\t\tlock = await store.lock(stage, { operation: 'deploy' });\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n\n\ttry {\n\t\tconst run = await validate(target, phaseCtx, emit);\n\t\tif (target.provision) {\n\t\t\tawait phase('provision', () => target.provision!(phaseCtx, run));\n\t\t}\n\t\tif (target.build) {\n\t\t\tawait phase('build', () => target.build!(phaseCtx, run));\n\t\t}\n\n\t\tlet releasing: 'release' | 'verify' = 'release';\n\t\ttry {\n\t\t\tawait phase('release', () => target.release(phaseCtx, run));\n\t\t\treleasing = 'verify';\n\t\t\tif (target.verify) {\n\t\t\t\tawait phase('verify', () => target.verify!(phaseCtx, run));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// The caller stopping the run is not a release to undo.\n\t\t\tif (ctx.signal?.aborted || !target.capabilities.rollback) throw error;\n\t\t\tif (!target.rollback) throw error;\n\t\t\ttry {\n\t\t\t\tawait phase('rollback', () =>\n\t\t\t\t\ttarget.rollback!(phaseCtx, run, { phase: releasing, error }),\n\t\t\t\t);\n\t\t\t} catch (rollbackError) {\n\t\t\t\tthrow new RollbackFailed(resolved.name, error, rollbackError);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn await target.result(phaseCtx, run);\n\t} finally {\n\t\tawait lock.release();\n\t}\n}\n\n/** `validate`, then the run's `deploy.started`, inside the validate phase. */\nasync function validate(\n\ttarget: AnyDeployTarget,\n\tphaseCtx: DeployPhaseContext<unknown>,\n\temit: (event: DeployEvent) => void,\n): Promise<unknown> {\n\ttry {\n\t\tconst run = await target.validate(phaseCtx);\n\t\tconst skipped = new Set(phaseCtx.skipped.map((s) => s.app));\n\t\temit({\n\t\t\ttype: 'deploy.started',\n\t\t\tstage: phaseCtx.stage,\n\t\t\ttarget: phaseCtx.target,\n\t\t\tidentity: phaseCtx.identity.key,\n\t\t\ttag: phaseCtx.tag,\n\t\t\tapps: phaseCtx.apps.filter((app) => !skipped.has(app)),\n\t\t\tdryRun: phaseCtx.dryRun,\n\t\t});\n\t\temit({ type: 'phase.finished', phase: 'validate' });\n\t\treturn run;\n\t} catch (error) {\n\t\temit({ type: 'phase.failed', phase: 'validate', error: eventError(error) });\n\t\tthrow error;\n\t}\n}\n\ninterface Prepared {\n\tresolved: ResolvedTarget;\n\tphaseCtx: DeployPhaseContext<unknown>;\n\tstore: Awaited<ReturnType<typeof createStateStore>>;\n}\n\n/** Everything the phases are handed, worked out before the first of them. */\nasync function prepare(\n\tsource: NormalizedWorkspace | (() => Promise<NormalizedWorkspace>),\n\trequest: DeployRequest,\n\tctx: DeployContext,\n\temit: (event: DeployEvent) => void,\n\tredactor: Redactor,\n): Promise<Prepared> {\n\tconst { stage } = request;\n\tconst configured = typeof source === 'function' ? await source() : source;\n\n\t// Before anything is provisioned: a typo'd stage would otherwise create a\n\t// whole second environment under the wrong name. The local stage is left\n\t// to the target, which says whether it can run it.\n\tconst local = stage === configured.stages.local;\n\tif (!local) assertDeployedStage(configured.stages, stage);\n\n\t// Before anything is discovered or derived: a target that cannot be found\n\t// — or a package that would not load — fails a deploy that has done\n\t// nothing yet.\n\tconst targetName = request.target ?? configured.deploy?.default ?? 'dokploy';\n\tconst resolved = await resolveTarget(targetName, {\n\t\tworkspace: configured,\n\t\tstage,\n\t\t...(ctx.targets ? { host: ctx.targets } : {}),\n\t});\n\tif (local && !resolved.target.capabilities.localStage) {\n\t\tassertDeployedStage(configured.stages, stage);\n\t}\n\tconst options = await parseTargetOptions(resolved);\n\n\t// Before anything is discovered: dev services asked of a target that runs\n\t// no containers fail a deploy that has done nothing.\n\tconst allowDevServices = request.allowDevServices === true;\n\tif (allowDevServices && resolved.target.runtime === 'aws') {\n\t\tthrow new DevServicesNeedServerTarget(targetName);\n\t}\n\n\t// What to deploy comes from the manifest.\n\t//\n\t// Discovered here rather than by the target, because the list of things\n\t// to deploy is the *declarations* — one `rest-api` is one server, one\n\t// `site` is one site — and the config only says how to run each. A project\n\t// that declares no surfaces keeps its configured apps, so adopting\n\t// constructs stays something you do a piece at a time.\n\tconst runnables: Record<string, string[]> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(configured),\n\t\tcwd: configured.root,\n\t\trunnables,\n\t\tbackground,\n\t});\n\t// Where the stage's telemetry goes, settled before anything is built: a\n\t// stage that uses a `Telemetry` node on a target that cannot choose for it\n\t// — AWS has no self-hosted provider — fails here, naming the config.\n\tresolveStageTelemetry({\n\t\t...(configured.deploy?.telemetry\n\t\t\t? { telemetry: configured.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal,\n\t\ttarget: targetName,\n\t\truntime: resolved.target.runtime,\n\t\tselfHosted: resolved.target.capabilities.selfHostedTelemetry === true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\n\tconst units = derivedApps(manifest, configured);\n\tconst workspace: NormalizedWorkspace =\n\t\tObject.keys(units).length > 0 ? { ...configured, apps: units } : configured;\n\n\t// What every resource this deploy touches is named and claimed by —\n\t// resolved first, so a namespace that cannot be a name fails before\n\t// anything is built.\n\tconst identity = deployIdentity(workspace, stage);\n\tconst tag =\n\t\trequest.tag ??\n\t\t(resolved.target.tag\n\t\t\t? await resolved.target.tag({ cwd: workspace.root, stage })\n\t\t\t: generateTag(stage));\n\n\t// The apps asked for, in dependency order.\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlet selected = buildOrder;\n\tif (request.apps && request.apps.length > 0) {\n\t\tconst unknown = request.apps.filter((name) => !workspace.apps[name]);\n\t\tif (unknown.length > 0) {\n\t\t\tthrow new UnknownDeployApps(unknown, Object.keys(workspace.apps));\n\t\t}\n\t\tselected = buildOrder.filter((name) => request.apps!.includes(name));\n\t}\n\n\tconst skipped: { app: string; reason: string }[] = [];\n\tconst skip = (app: string, reason: string) => {\n\t\tskipped.push({ app, reason });\n\t\temit({ type: 'app.skipped', app, reason });\n\t};\n\n\t// An app that names another target deploys there, in a run of its own.\n\t// One on the default follows the run, so `--target` moves the stage\n\t// without every app having to be told.\n\tconst byDefault = configured.deploy?.default ?? 'dokploy';\n\tconst apps = selected.filter((name) => {\n\t\tconst own = workspace.apps[name]!.resolvedDeployTarget;\n\t\tconst deploysThrough = own === byDefault ? targetName : own;\n\t\tif (deploysThrough === targetName) return true;\n\t\tskip(name, elsewhere(deploysThrough, stage));\n\t\treturn false;\n\t});\n\tif (apps.length === 0) throw new NoDeployableApps(stage, targetName);\n\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\tconst secrets = await deploySecrets(workspace, stage, redactor, {\n\t\t...(ctx.home ? { home: ctx.home } : {}),\n\t});\n\n\tconst line =\n\t\t(level: 'info' | 'warn' | 'error') =>\n\t\t(message: string): void =>\n\t\t\temit({ type: 'log', level, message });\n\tconst logger: DeployTargetLogger = {\n\t\tinfo: line('info'),\n\t\twarn: line('warn'),\n\t\terror: line('error'),\n\t};\n\n\tconst phaseCtx: DeployPhaseContext<unknown> = {\n\t\ttarget: targetName,\n\t\tcwd: workspace.root,\n\t\tstage,\n\t\ttag,\n\t\ttagGiven: request.tag !== undefined,\n\t\tapps,\n\t\tskipped,\n\t\tidentity,\n\t\tworkspace,\n\t\tmanifest,\n\t\trunnables,\n\t\tbackground,\n\t\toptions,\n\t\tdryRun: ctx.dryRun,\n\t\tatomic: request.atomic ?? false,\n\t\tallowDevServices,\n\t\t...(request.skipDnsCheck ? { skipDnsCheck: true } : {}),\n\t\tcredentials: ctx.credentials,\n\t\tstate: store,\n\t\tsecrets,\n\t\tlogger,\n\t\tsignal: ctx.signal ?? new AbortController().signal,\n\t\tchildOutput: ctx.childOutput ?? 'inherit',\n\t\temit,\n\t\tskip,\n\t\tname: (resource) => applicationName(identity, resource),\n\t};\n\n\treturn { resolved, phaseCtx, store };\n}\n","/**\n * `deploy()`: a deploy as a library call.\n *\n * `gkm deploy` could only be driven from an interactive terminal: it prompted\n * for what it lacked and exited the process on failure, worked out of\n * `process.cwd()`, and reported progress by printing. Here the caller says\n * where the project is, hands over the credentials and a signal, and gets back\n * a run — events to iterate while it goes, and a structured result at the end.\n * Nothing below this asks a person anything or ends the process; `gkm deploy`\n * is a thin wrapper that does both.\n */\n\nimport { resolve } from 'node:path';\nimport { findWorkspaceRoot, loadWorkspaceConfig } from '../config';\nimport { gkmHome } from '../home';\nimport { type OutputLevel, withOutput } from '../output';\nimport { LocalSandbox } from '../sandbox/local';\nimport { type Sandbox, withSandbox } from '../sandbox/sandbox';\nimport { Redactor } from '../target/secrets';\nimport type { AnyDeployTarget } from '../target/types';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { type CredentialProvider, storedCredentials } from './credentials';\nimport { type DeployEvent, eventError } from './events';\nimport { type DeployContext, runDeploy } from './orchestrate';\nimport type { DeployResult } from './types';\n\n/**\n * Where a run's progress lines go, besides its events. `@geekmidas/logger`'s\n * `Logger` is one.\n */\nexport interface DeployLogger {\n\tinfo(message: string): void;\n\twarn(message: string): void;\n\terror?(message: string): void;\n}\n\nexport interface DeployInput {\n\t/**\n\t * The project to deploy: the directory holding `gkm.config.ts`, or any\n\t * directory inside it. Never assumed to be `process.cwd()`.\n\t */\n\tcwd: string;\n\t/**\n\t * The stage to deploy — one of the config's deployed stages, or its local\n\t * stage through a target that runs one (`compose`).\n\t */\n\tstage: string;\n\t/**\n\t * The target to deploy through, by name. Defaults to `deploy.default`,\n\t * else `dokploy`.\n\t */\n\ttarget?: string;\n\t/**\n\t * The host's own targets, by name. Consulted before the built-ins and the\n\t * config's `deploy.targets`, so a host can deploy through an\n\t * implementation of its own — `{ dokploy: myDokploy }` included.\n\t */\n\ttargets?: Record<string, AnyDeployTarget>;\n\t/** The image tag. Defaults to `<stage>-<timestamp>`. */\n\ttag?: string;\n\t/** Deploy only these apps (in dependency order). Defaults to all. */\n\tapps?: string[];\n\t/**\n\t * Look everything up and report what would happen — as `resource.planned`\n\t * events — without taking the lock, writing state, generating secrets,\n\t * changing Dokploy or building and pushing images.\n\t */\n\tdryRun?: boolean;\n\t/**\n\t * Validate and build only: the target's images built — and pushed, where\n\t * it pushes them — with no lock taken and nothing provisioned, released,\n\t * verified or recorded. `gkm compose --build --push` runs this way.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * When a release or its verification fails, roll back every app the run\n\t * released rather than only the ones that failed — on a target that can\n\t * roll back. For apps that must move together.\n\t */\n\tatomic?: boolean;\n\t/**\n\t * Where credentials come from. Defaults to the environment, then the\n\t * logins `gkm login` stored. A credential no provider has stops the run\n\t * with `MissingCredential`; nothing prompts.\n\t */\n\tcredentials?: CredentialProvider;\n\t/**\n\t * On a server target, run a dev service for every construct a deployed\n\t * stage does not account for — no key in its secrets, and no provider\n\t * (`deploy.objects`) backing its kind: MinIO for a bucket, Mailpit for\n\t * mail. Neither is production-grade — Mailpit delivers no mail — and every\n\t * run that uses one emits `dev-service.used`. Without it, a deployed stage\n\t * missing a mail or storage key fails with `ExternalServicesNotConfigured`;\n\t * on an AWS target it fails with `DevServicesNeedServerTarget`.\n\t */\n\tallowDevServices?: boolean;\n\t/**\n\t * Do not check, on a server target, that each public host resolves to\n\t * the stage's server (`GKM_SERVER_IPV4`) before the stack starts — for a CDN\n\t * or proxy in front of the server.\n\t */\n\tskipDnsCheck?: boolean;\n\t/** Receives each progress line as it is written. Defaults to none. */\n\tlogger?: DeployLogger;\n\t/**\n\t * Stops the run: in-flight Dokploy requests and docker children are\n\t * cancelled, the stage's lock is released, and `result` rejects with the\n\t * signal's reason.\n\t */\n\tsignal?: AbortSignal;\n\t/**\n\t * The CLI's home: stage keys and stored logins. Defaults to `GKM_HOME`,\n\t * else `~/.gkm`.\n\t */\n\thome?: string;\n\t/**\n\t * Where docker's own output goes: the host's terminal (`inherit`, the\n\t * default), its stderr, or nowhere.\n\t */\n\tchildOutput?: 'inherit' | 'stderr' | 'ignore';\n\t/**\n\t * Where the project's own code runs: loading `gkm.config.ts`, discovering\n\t * its constructs, sniffing each app's environment. Defaults to a\n\t * `LocalSandbox` on the project — a child process here with an\n\t * allowlisted environment, for a project the host trusts.\n\t *\n\t * A host deploying repositories it does not trust passes one that\n\t * isolates — a container per build — and the config then reaches the\n\t * deploy only as data. Credentials never enter a sandbox: they go from\n\t * `credentials` to the steps that provision, push and release.\n\t */\n\tsandbox?: Sandbox;\n}\n\n/** A deploy in progress. */\nexport interface DeployRun extends AsyncIterable<DeployEvent> {\n\t/**\n\t * What the deploy did, once it is done. Rejects with the error that\n\t * stopped it — `MissingCredential`, `StateLocked`, `ProjectNotOwned`, … —\n\t * after a `deploy.failed` event carrying the same.\n\t */\n\treadonly result: Promise<DeployResult>;\n}\n\n/**\n * Every event a run emits, kept so that each iteration — however late it\n * starts — sees the run from its first event to its last.\n */\nclass EventLog {\n\tprivate readonly events: DeployEvent[] = [];\n\tprivate closed = false;\n\tprivate waiting: (() => void)[] = [];\n\n\tpush(event: DeployEvent): void {\n\t\tthis.events.push(event);\n\t\tthis.wake();\n\t}\n\n\tclose(): void {\n\t\tthis.closed = true;\n\t\tthis.wake();\n\t}\n\n\tprivate wake(): void {\n\t\tconst waiting = this.waiting;\n\t\tthis.waiting = [];\n\t\tfor (const resume of waiting) resume();\n\t}\n\n\tasync *iterate(): AsyncGenerator<DeployEvent> {\n\t\tlet next = 0;\n\t\twhile (true) {\n\t\t\tif (next < this.events.length) {\n\t\t\t\tyield this.events[next++]!;\n\t\t\t} else if (this.closed) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tawait new Promise<void>((resume) => this.waiting.push(resume));\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction forward(\n\tlogger: DeployLogger | undefined,\n\tlevel: OutputLevel,\n\tmessage: string,\n): void {\n\tif (!logger) return;\n\tif (level === 'info') logger.info(message);\n\telse if (level === 'error' && logger.error) logger.error(message);\n\telse logger.warn(message);\n}\n\n/**\n * Deploy a project's stage.\n *\n * ```ts\n * import { deploy } from '@geekmidas/cli/deploy';\n *\n * const run = deploy({ cwd: '/srv/checkouts/shop', stage: 'production' });\n * for await (const event of run) {\n * if (event.type === 'app.deployed') console.log(event.app, event.url);\n * }\n * const result = await run.result;\n * ```\n *\n * The run starts at once; iterating it is optional, and an iteration started\n * late still sees every event from the first.\n */\nexport function deploy(input: DeployInput): DeployRun {\n\tconst log = new EventLog();\n\t// Every secret the run reads is masked in every line it reports — in the\n\t// events and in what the logger is handed.\n\tconst redactor = new Redactor();\n\tconst emit = (event: DeployEvent) => {\n\t\tconst masked =\n\t\t\tevent.type === 'log'\n\t\t\t\t? { ...event, message: redactor.redact(event.message) }\n\t\t\t\t: event;\n\t\tlog.push(masked);\n\t\tif (masked.type === 'log') {\n\t\t\tforward(input.logger, masked.level, masked.message);\n\t\t}\n\t};\n\n\tconst ctx: DeployContext = {\n\t\temit,\n\t\tcredentials:\n\t\t\tinput.credentials ?? storedCredentials({ home: input.home ?? gkmHome() }),\n\t\tdryRun: input.dryRun ?? false,\n\t\t...(input.buildOnly ? { buildOnly: true } : {}),\n\t\thome: input.home ?? gkmHome(),\n\t\tredactor,\n\t\t...(input.signal ? { signal: input.signal } : {}),\n\t\t...(input.childOutput ? { childOutput: input.childOutput } : {}),\n\t\t...(input.targets ? { targets: input.targets } : {}),\n\t};\n\n\t// Every line anything in the run writes through `output` — the deploy's\n\t// own, the Dockerfile generator's, discovery's warnings — becomes an event\n\t// of this run, and of no other.\n\tconst result = withOutput(\n\t\t(level, message) => emit({ type: 'log', level, message }),\n\t\tasync () => {\n\t\t\ttry {\n\t\t\t\tinput.signal?.throwIfAborted();\n\t\t\t\tconst sandbox =\n\t\t\t\t\tinput.sandbox ??\n\t\t\t\t\tnew LocalSandbox({ root: findWorkspaceRoot(resolve(input.cwd)) });\n\t\t\t\t// Every step of the run that executes the project's code — the\n\t\t\t\t// engine's own discoveries and sniffs included — runs in it.\n\t\t\t\tconst deployed = await withSandbox(sandbox, () =>\n\t\t\t\t\trunDeploy(\n\t\t\t\t\t\t() => load(input, sandbox),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstage: input.stage,\n\t\t\t\t\t\t\t...(input.target ? { target: input.target } : {}),\n\t\t\t\t\t\t\t...(input.tag ? { tag: input.tag } : {}),\n\t\t\t\t\t\t\t...(input.apps ? { apps: input.apps } : {}),\n\t\t\t\t\t\t\t...(input.atomic ? { atomic: true } : {}),\n\t\t\t\t\t\t\t...(input.allowDevServices\n\t\t\t\t\t\t\t\t? { allowDevServices: input.allowDevServices }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(input.skipDnsCheck ? { skipDnsCheck: true } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\temit({ type: 'deploy.finished', result: deployed });\n\t\t\t\treturn deployed;\n\t\t\t} catch (error) {\n\t\t\t\temit({ type: 'deploy.failed', error: eventError(error) });\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tlog.close();\n\t\t\t}\n\t\t},\n\t);\n\n\t// A caller that only iterates still learns of the failure from the\n\t// `deploy.failed` event; the rejection must not also crash its process as\n\t// unhandled. Awaiting `result` still rejects.\n\tresult.catch(() => {});\n\n\treturn {\n\t\tresult,\n\t\t[Symbol.asyncIterator]: () => log.iterate(),\n\t};\n}\n\n/**\n * The workspace at `input.cwd`. The stage is checked by the run, once it\n * knows the target: one that runs on this machine may take the local stage.\n */\nasync function load(\n\tinput: DeployInput,\n\tsandbox: Sandbox,\n): Promise<NormalizedWorkspace> {\n\tconst { workspace } = await loadWorkspaceConfig(resolve(input.cwd), {\n\t\tsandbox,\n\t});\n\treturn workspace;\n}\n"],"mappings":"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"}