@geekmidas/cli 10.0.0-alpha.94 → 10.0.0-alpha.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{GoDaddyProvider-BRZUWD8z.mjs → GoDaddyProvider-BsUKjGcg.mjs} +3 -3
- package/dist/{GoDaddyProvider-BRZUWD8z.mjs.map → GoDaddyProvider-BsUKjGcg.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-DzguxU_a.cjs → GoDaddyProvider-DyHXHDHe.cjs} +3 -3
- package/dist/{GoDaddyProvider-DzguxU_a.cjs.map → GoDaddyProvider-DyHXHDHe.cjs.map} +1 -1
- package/dist/{HostingerProvider-Cjh_2Ml6.mjs → HostingerProvider-BNpS9aRJ.mjs} +2 -2
- package/dist/{HostingerProvider-Cjh_2Ml6.mjs.map → HostingerProvider-BNpS9aRJ.mjs.map} +1 -1
- package/dist/{HostingerProvider-OdQmKXE3.cjs → HostingerProvider-DR1iws1P.cjs} +2 -2
- package/dist/{HostingerProvider-OdQmKXE3.cjs.map → HostingerProvider-DR1iws1P.cjs.map} +1 -1
- package/dist/{LegacyStateStore-BQZb6-j2.mjs → LegacyStateStore-B6SOqRFi.mjs} +3 -3
- package/dist/{LegacyStateStore-BQZb6-j2.mjs.map → LegacyStateStore-B6SOqRFi.mjs.map} +1 -1
- package/dist/{LegacyStateStore-D50dgUPc.cjs → LegacyStateStore-BnMcONE0.cjs} +3 -3
- package/dist/{LegacyStateStore-D50dgUPc.cjs.map → LegacyStateStore-BnMcONE0.cjs.map} +1 -1
- package/dist/{LocalStateStore-BSaS2535.mjs → LocalStateStore-6CrsZzqI.mjs} +2 -2
- package/dist/{LocalStateStore-BSaS2535.mjs.map → LocalStateStore-6CrsZzqI.mjs.map} +1 -1
- package/dist/{LocalStateStore-EFBUjuMX.cjs → LocalStateStore-pd4bbdJJ.cjs} +2 -2
- package/dist/{LocalStateStore-EFBUjuMX.cjs.map → LocalStateStore-pd4bbdJJ.cjs.map} +1 -1
- package/dist/{S3StateStore-C5mv8To3.cjs → S3StateStore-CoGk6ZKU.cjs} +2 -2
- package/dist/{S3StateStore-C5mv8To3.cjs.map → S3StateStore-CoGk6ZKU.cjs.map} +1 -1
- package/dist/{S3StateStore-CrFq4UZU.mjs → S3StateStore-DP_7Q4yb.mjs} +2 -2
- package/dist/{S3StateStore-CrFq4UZU.mjs.map → S3StateStore-DP_7Q4yb.mjs.map} +1 -1
- package/dist/{SSMStateStore-D3Z6mZnA.mjs → SSMStateStore-Bo6_KDYY.mjs} +2 -2
- package/dist/{SSMStateStore-D3Z6mZnA.mjs.map → SSMStateStore-Bo6_KDYY.mjs.map} +1 -1
- package/dist/{SSMStateStore-DuZCH7_v.cjs → SSMStateStore-D9s4_Do3.cjs} +2 -2
- package/dist/{SSMStateStore-DuZCH7_v.cjs.map → SSMStateStore-D9s4_Do3.cjs.map} +1 -1
- package/dist/{add-C85isXFl.mjs → add-BQS2QZHp.mjs} +22 -51
- package/dist/add-BQS2QZHp.mjs.map +1 -0
- package/dist/{add-DsVDdvon.cjs → add-CjURJ-vI.cjs} +23 -52
- package/dist/add-CjURJ-vI.cjs.map +1 -0
- package/dist/{bundler-BSHog8CH.mjs → bundler-BMM3UsGm.mjs} +5 -5
- package/dist/{bundler-BSHog8CH.mjs.map → bundler-BMM3UsGm.mjs.map} +1 -1
- package/dist/{bundler-BEgUKc4j.cjs → bundler-DmLJQ7AY.cjs} +5 -5
- package/dist/{bundler-BEgUKc4j.cjs.map → bundler-DmLJQ7AY.cjs.map} +1 -1
- package/dist/{cli-BvBdv660.cjs → cli-C2c-jOVK.cjs} +4 -4
- package/dist/{cli-BvBdv660.cjs.map → cli-C2c-jOVK.cjs.map} +1 -1
- package/dist/{cli-BsFenyaf.mjs → cli-Ce6NgaQF.mjs} +4 -4
- package/dist/{cli-BsFenyaf.mjs.map → cli-Ce6NgaQF.mjs.map} +1 -1
- package/dist/{compose-D2RFYd_f.mjs → compose-BJDPFBAN.mjs} +43 -47
- package/dist/compose-BJDPFBAN.mjs.map +1 -0
- package/dist/{compose-Cd09gW-n.cjs → compose-ETFKqkTu.cjs} +60 -64
- package/dist/compose-ETFKqkTu.cjs.map +1 -0
- package/dist/{config-Ngesg4O8.d.mts → config-4yirvxS8.d.cts} +4 -4
- package/dist/{config-DvHNMoOp.d.cts.map → config-4yirvxS8.d.cts.map} +1 -1
- package/dist/{config-DvHNMoOp.d.cts → config-C8NPCn1l.d.mts} +4 -4
- package/dist/{config-Ngesg4O8.d.mts.map → config-C8NPCn1l.d.mts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/{credentials-DpfnUvIR.mjs → credentials-B5N5yKk6.mjs} +4 -132
- package/dist/credentials-B5N5yKk6.mjs.map +1 -0
- package/dist/{credentials-D7XJypNd.cjs → credentials-Zqr3QQYB.cjs} +3 -173
- package/dist/credentials-Zqr3QQYB.cjs.map +1 -0
- package/dist/deploy/public.cjs +16 -15
- package/dist/deploy/public.cjs.map +1 -1
- package/dist/deploy/public.d.cts +5 -5
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +5 -5
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +11 -10
- package/dist/deploy/public.mjs.map +1 -1
- package/dist/deploy-BdN0ym2i.cjs +2057 -0
- package/dist/deploy-BdN0ym2i.cjs.map +1 -0
- package/dist/deploy-DktQl7ti.mjs +2008 -0
- package/dist/deploy-DktQl7ti.mjs.map +1 -0
- package/dist/{discover-CTzOSGUF.d.cts → discover-BtFofyQB.d.cts} +2 -2
- package/dist/{discover-CTzOSGUF.d.cts.map → discover-BtFofyQB.d.cts.map} +1 -1
- package/dist/{discover-CihAtaoj.d.mts → discover-D-MdXZgm.d.mts} +2 -2
- package/dist/{discover-CihAtaoj.d.mts.map → discover-D-MdXZgm.d.mts.map} +1 -1
- package/dist/dns-BjHECDO7.mjs +44 -0
- package/dist/dns-BjHECDO7.mjs.map +1 -0
- package/dist/dns-C-X6PLkV.cjs +663 -0
- package/dist/dns-C-X6PLkV.cjs.map +1 -0
- package/dist/dns-C2EeR6n2.mjs +610 -0
- package/dist/dns-C2EeR6n2.mjs.map +1 -0
- package/dist/dns-ClI7-d5g.cjs +55 -0
- package/dist/dns-ClI7-d5g.cjs.map +1 -0
- package/dist/{dokploy-CV7GcobZ.cjs → dokploy-CD_Bc4EV.cjs} +2 -2
- package/dist/{dokploy-CV7GcobZ.cjs.map → dokploy-CD_Bc4EV.cjs.map} +1 -1
- package/dist/{dokploy-D_aat2Xj.mjs → dokploy-CxtkS5hl.mjs} +2 -2
- package/dist/{dokploy-D_aat2Xj.mjs.map → dokploy-CxtkS5hl.mjs.map} +1 -1
- package/dist/{encryption-_4qKqtTx.mjs → encryption-BgQd4f2S.mjs} +3 -3
- package/dist/{encryption-_4qKqtTx.mjs.map → encryption-BgQd4f2S.mjs.map} +1 -1
- package/dist/{encryption-DFcivJaO.cjs → encryption-CqVfz-m7.cjs} +3 -3
- package/dist/{encryption-DFcivJaO.cjs.map → encryption-CqVfz-m7.cjs.map} +1 -1
- package/dist/{engine-Bv-LZpmj.cjs → engine-OVVKtPmW.cjs} +18 -36
- package/dist/engine-OVVKtPmW.cjs.map +1 -0
- package/dist/{engine-DPMHThkg.mjs → engine-YlXzlTUl.mjs} +14 -32
- package/dist/{engine-DPMHThkg.mjs.map → engine-YlXzlTUl.mjs.map} +1 -1
- package/dist/{github-Br42NMrW.cjs → github-CsMloeSL.cjs} +9 -7
- package/dist/{github-Br42NMrW.cjs.map → github-CsMloeSL.cjs.map} +1 -1
- package/dist/{github-xsDT19im.mjs → github-DuuvqI3Z.mjs} +5 -3
- package/dist/{github-xsDT19im.mjs.map → github-DuuvqI3Z.mjs.map} +1 -1
- package/dist/{index-CwLvFqtH.d.cts → index-5eL8rM6H.d.mts} +2 -2
- package/dist/{index-BlpcClwM.d.mts.map → index-5eL8rM6H.d.mts.map} +1 -1
- package/dist/{index-BlpcClwM.d.mts → index-Dz-gyjm_.d.cts} +2 -2
- package/dist/{index-CwLvFqtH.d.cts.map → index-Dz-gyjm_.d.cts.map} +1 -1
- package/dist/index.cjs +54 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +52 -51
- package/dist/index.mjs.map +1 -1
- package/dist/{local-B7Zv1NoA.mjs → local-BwC2v2Y8.mjs} +2 -2
- package/dist/{local-B7Zv1NoA.mjs.map → local-BwC2v2Y8.mjs.map} +1 -1
- package/dist/{local-OPC9BCZt.cjs → local-DNhnkugT.cjs} +3 -3
- package/dist/{local-OPC9BCZt.cjs.map → local-DNhnkugT.cjs.map} +1 -1
- package/dist/{migrate-D5jUz20_.cjs → migrate-BAmJeVq1.cjs} +3 -3
- package/dist/{migrate-D5jUz20_.cjs.map → migrate-BAmJeVq1.cjs.map} +1 -1
- package/dist/{migrate-SkWJotn5.cjs → migrate-BdkoNdIu.cjs} +3 -3
- package/dist/{migrate-SkWJotn5.cjs.map → migrate-BdkoNdIu.cjs.map} +1 -1
- package/dist/{migrate-DhvFPGLi.mjs → migrate-CB8B6W9y.mjs} +3 -3
- package/dist/{migrate-DhvFPGLi.mjs.map → migrate-CB8B6W9y.mjs.map} +1 -1
- package/dist/{migrate-B7evHv7O.mjs → migrate-CsPFHgTs.mjs} +3 -3
- package/dist/{migrate-B7evHv7O.mjs.map → migrate-CsPFHgTs.mjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/reconcile/public.d.cts +2 -2
- package/dist/reconcile/public.d.mts +2 -2
- package/dist/{resolve-CFEOtRsl.cjs → resolve-BDatNOoG.cjs} +4 -4
- package/dist/{resolve-CFEOtRsl.cjs.map → resolve-BDatNOoG.cjs.map} +1 -1
- package/dist/{resolve-Dyd1S2wn.mjs → resolve-CUne0qOm.mjs} +4 -4
- package/dist/{resolve-Dyd1S2wn.mjs.map → resolve-CUne0qOm.mjs.map} +1 -1
- package/dist/{rollback-NroNbGC0.mjs → rollback-CCdEEEcF.mjs} +7 -8
- package/dist/{rollback-NroNbGC0.mjs.map → rollback-CCdEEEcF.mjs.map} +1 -1
- package/dist/{rollback-D720SFhV.cjs → rollback-CuG3DkTY.cjs} +8 -9
- package/dist/{rollback-D720SFhV.cjs.map → rollback-CuG3DkTY.cjs.map} +1 -1
- package/dist/run-BJLIerMM.mjs +133 -0
- package/dist/run-BJLIerMM.mjs.map +1 -0
- package/dist/run-fVZ-rLnc.cjs +174 -0
- package/dist/run-fVZ-rLnc.cjs.map +1 -0
- package/dist/{runtime-VktAo_8B.d.cts → runtime-DUQdM-mW.d.cts} +2 -2
- package/dist/{runtime-BRCq6dQ7.d.mts.map → runtime-DUQdM-mW.d.cts.map} +1 -1
- package/dist/{runtime-BRCq6dQ7.d.mts → runtime-Vr6mleo2.d.mts} +2 -2
- package/dist/{runtime-VktAo_8B.d.cts.map → runtime-Vr6mleo2.d.mts.map} +1 -1
- package/dist/{sandbox-D1gd0iDz.d.cts → sandbox-BbJmh2rI.d.cts} +2 -2
- package/dist/{sandbox-D1gd0iDz.d.cts.map → sandbox-BbJmh2rI.d.cts.map} +1 -1
- package/dist/{sandbox-zHnRLCj0.d.mts → sandbox-DGOsMPMf.d.mts} +2 -2
- package/dist/{sandbox-zHnRLCj0.d.mts.map → sandbox-DGOsMPMf.d.mts.map} +1 -1
- package/dist/{secrets-DAvi_O9g.cjs → secrets-C5qROlbp.cjs} +3 -3
- package/dist/{secrets-DAvi_O9g.cjs.map → secrets-C5qROlbp.cjs.map} +1 -1
- package/dist/{secrets-CwLauUB_.mjs → secrets-ZikTIxEm.mjs} +3 -3
- package/dist/{secrets-CwLauUB_.mjs.map → secrets-ZikTIxEm.mjs.map} +1 -1
- package/dist/{seeds-BCg8X36S.cjs → seeds-BjXW-Krf.cjs} +193 -946
- package/dist/seeds-BjXW-Krf.cjs.map +1 -0
- package/dist/{seeds-CTxTZa-R.mjs → seeds-CbJSne1A.mjs} +156 -825
- package/dist/seeds-CbJSne1A.mjs.map +1 -0
- package/dist/{sniffer-DCcuzHz_.mjs → sniffer-DQGBYY8i.mjs} +8 -8
- package/dist/{sniffer-DCcuzHz_.mjs.map → sniffer-DQGBYY8i.mjs.map} +1 -1
- package/dist/{sniffer-C0z3NB2A.cjs → sniffer-NPD1dyab.cjs} +8 -8
- package/dist/{sniffer-C0z3NB2A.cjs.map → sniffer-NPD1dyab.cjs.map} +1 -1
- package/dist/{sst-DRDSDwOk.mjs → sst-CGdjHn2A.mjs} +4 -3
- package/dist/{sst-DRDSDwOk.mjs.map → sst-CGdjHn2A.mjs.map} +1 -1
- package/dist/{sst-DKNH243z.cjs → sst-DGuHDxVU.cjs} +5 -4
- package/dist/{sst-DKNH243z.cjs.map → sst-DGuHDxVU.cjs.map} +1 -1
- package/dist/{stack-NrdH5ngX.mjs → stack-BFq3K-_z.mjs} +14 -52
- package/dist/stack-BFq3K-_z.mjs.map +1 -0
- package/dist/{stack-B3fPDTBg.cjs → stack-DOVvEd1T.cjs} +14 -52
- package/dist/stack-DOVvEd1T.cjs.map +1 -0
- package/dist/{stages-veC4TcQe.mjs → stages-BEn2ArJZ.mjs} +4 -3
- package/dist/{stages-veC4TcQe.mjs.map → stages-BEn2ArJZ.mjs.map} +1 -1
- package/dist/{stages-CkqP1N4S.cjs → stages-Cw6urZyJ.cjs} +5 -4
- package/dist/{stages-CkqP1N4S.cjs.map → stages-Cw6urZyJ.cjs.map} +1 -1
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{terminal-CkUYuAPd.cjs → terminal-CPHuH4S1.cjs} +2 -2
- package/dist/{terminal-CkUYuAPd.cjs.map → terminal-CPHuH4S1.cjs.map} +1 -1
- package/dist/{terminal-DAHs2Zko.mjs → terminal-iNmAXXjs.mjs} +2 -2
- package/dist/{terminal-DAHs2Zko.mjs.map → terminal-iNmAXXjs.mjs.map} +1 -1
- package/dist/{types-DMoaFrjg.d.mts → types-bkqVscdN.d.mts} +12 -3
- package/dist/types-bkqVscdN.d.mts.map +1 -0
- package/dist/{types-DXyaSmqu.d.cts → types-dipJRmKV.d.cts} +12 -3
- package/dist/types-dipJRmKV.d.cts.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-DWK1PTXP.mjs → workspace-CqFUjObk.mjs} +54 -2
- package/dist/workspace-CqFUjObk.mjs.map +1 -0
- package/dist/{workspace-cSyi5nb1.cjs → workspace-DDkm4y6D.cjs} +71 -1
- package/dist/workspace-DDkm4y6D.cjs.map +1 -0
- package/package.json +15 -15
- package/dist/add-C85isXFl.mjs.map +0 -1
- package/dist/add-DsVDdvon.cjs.map +0 -1
- package/dist/compose-Cd09gW-n.cjs.map +0 -1
- package/dist/compose-D2RFYd_f.mjs.map +0 -1
- package/dist/credentials-D7XJypNd.cjs.map +0 -1
- package/dist/credentials-DpfnUvIR.mjs.map +0 -1
- package/dist/deploy-C911Akkn.cjs +0 -670
- package/dist/deploy-C911Akkn.cjs.map +0 -1
- package/dist/deploy-CeJ5D0xn.mjs +0 -641
- package/dist/deploy-CeJ5D0xn.mjs.map +0 -1
- package/dist/engine-Bv-LZpmj.cjs.map +0 -1
- package/dist/providers-BFeP_mYw.cjs +0 -1098
- package/dist/providers-BFeP_mYw.cjs.map +0 -1
- package/dist/providers-sTj-BG0S.mjs +0 -1079
- package/dist/providers-sTj-BG0S.mjs.map +0 -1
- package/dist/seeds-BCg8X36S.cjs.map +0 -1
- package/dist/seeds-CTxTZa-R.mjs.map +0 -1
- package/dist/stack-B3fPDTBg.cjs.map +0 -1
- package/dist/stack-NrdH5ngX.mjs.map +0 -1
- package/dist/types-DMoaFrjg.d.mts.map +0 -1
- package/dist/types-DXyaSmqu.d.cts.map +0 -1
- package/dist/workspace-DWK1PTXP.mjs.map +0 -1
- package/dist/workspace-cSyi5nb1.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compose-D2RFYd_f.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\ttype HostLookup,\n\tHostNotPointingAtServer,\n\tisLocalHost,\n\trequiredServerAddress,\n\tSERVER_IPV4_KEY,\n\ttype ServerAddress,\n\tserverAddressHint,\n\tstackHosts,\n\tstageDns,\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 { recordDnsChanges } from '../../deploy/dnsResources.js';\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 {\n\tDnsProvider as DnsProviderConfig,\n\tNormalizedWorkspace,\n} from '../../workspace/types.js';\nimport type { DnsProvider } from '../dokploy/dns/DnsProvider';\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\t/** The DNS provider for a `dns` domain — `createDnsProvider` by default. */\n\tdnsProviderFor?: (config: DnsProviderConfig) => Promise<DnsProvider | null>;\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 points at the stage's server — its records written\n\t// where a provider holds them, then confirmed — before Caddy or Traefik\n\t// ask Let's Encrypt for a certificate it could not issue.\n\tif (!push && !stack.local) {\n\t\tawait deployDns(\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's DNS step: the stage's own hosts written through each domain's\n * provider in `dns` where they differ, read back from it, and recorded in the\n * stage's state; hosts no provider writes resolved with the system resolver.\n * A dry run prints the plan and writes nothing, and warns rather than stops.\n */\nasync function deployDns(\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.skipDns) {\n\t\tctx.logger.info(\n\t\t\t'🌐 DNS skipped (--skip-dns): no record is written or checked',\n\t\t);\n\t\treturn;\n\t}\n\tif (ctx.skipResources) {\n\t\tctx.logger.info(\n\t\t\t'🌐 DNS skipped (--skip-resources): the --resources-only run wrote and confirmed the records',\n\t\t);\n\t\treturn;\n\t}\n\tif (!server) {\n\t\tctx.logger.info(\n\t\t\t`🌐 DNS skipped: no ${SERVER_IPV4_KEY} in '${stage}''s secrets — ${serverAddressHint(stage)}`,\n\t\t);\n\t\treturn;\n\t}\n\tconst log = (line: string) => ctx.logger.info(line);\n\tif (workspace.dns) {\n\t\tlog(\n\t\t\t`🌐 DNS for '${stage}' → ${server.ipv4}${server.ipv6 ? ` / ${server.ipv6}` : ''}${ctx.dryRun ? ' (dry run — nothing is written)' : ''}`,\n\t\t);\n\t}\n\ttry {\n\t\tconst result = await stageDns({\n\t\t\tstage,\n\t\t\thosts,\n\t\t\tserver,\n\t\t\tdns: workspace.dns,\n\t\t\tcredentials: ctx.credentials,\n\t\t\tlog,\n\t\t\tlookup: deps.lookup ?? systemLookup,\n\t\t\t...(ctx.dryRun ? { dryRun: true } : {}),\n\t\t\t...(deps.dnsProviderFor ? { providerFor: deps.dnsProviderFor } : {}),\n\t\t});\n\t\t// What it wrote, kept in the stage's state; what it deleted, forgotten.\n\t\tif (!ctx.dryRun) {\n\t\t\tconst journal = await DeployJournal.open(ctx.state, stage, () =>\n\t\t\t\tcreateComposeState(stage),\n\t\t\t);\n\t\t\tconst providers = new Map(\n\t\t\t\tresult.plan.domains.map((d) => [d.domain, d.provider]),\n\t\t\t);\n\t\t\tawait recordDnsChanges(journal, result.changes, (domain) =>\n\t\t\t\tproviders.get(domain),\n\t\t\t);\n\t\t}\n\t\tconst parts = [\n\t\t\tresult.confirmed.length > 0\n\t\t\t\t? `${result.confirmed.length} host${result.confirmed.length === 1 ? '' : 's'} confirmed by the DNS provider`\n\t\t\t\t: '',\n\t\t\tresult.resolved.length > 0\n\t\t\t\t? `${result.resolved.length} host${result.resolved.length === 1 ? '' : 's'} resolve${result.resolved.length === 1 ? 's' : ''} to ${server.ipv4}`\n\t\t\t\t: '',\n\t\t].filter(Boolean);\n\t\tif (parts.length > 0) log(`🌐 ${parts.join(', ')}`);\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\n/**\n * `--resources-only`: the stage's DNS records, from the hosts its stack would\n * serve — composed in memory, nothing written, no image asked for. What a CI\n * runner runs with the DNS provider's token, so the server never holds it.\n */\nexport async function resourcesCompose(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { workspace, stage } = ctx;\n\tif (stage === workspace.stages.local) return;\n\t// The DNS token was asked for before the providers ran.\n\tconst stored = await ctx.secrets.read();\n\tconst server = requiredServerAddress(\n\t\tstage,\n\t\tworkspace.domains?.[stage],\n\t\tstored?.custom,\n\t);\n\tconst { composeStageHosts } = await import('../../providers/dns.js');\n\tconst hosts = await composeStageHosts({\n\t\tworkspace,\n\t\tstage,\n\t\tstored,\n\t\tmanifest: ctx.manifest,\n\t\trunnables: (ctx.runnables ?? {}) as Record<string, string[]>,\n\t\tbackground: (ctx.background ?? {}) as Record<string, string[]>,\n\t});\n\tawait deployDns(\n\t\tctx,\n\t\tdeps,\n\t\thosts.filter((host) => !isLocalHost(host)),\n\t\tserver,\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\tresourcesCompose,\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\tresources: (ctx) => resourcesCompose(ctx, deps),\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":"credentials-D7XJypNd.cjs","names":["resolve","join","homedir","join","existsSync","readFile","writeFile","spawn","GkmError"],"sources":["../src/home.ts","../src/auth/credentials.ts","../src/run.ts","../src/deploy/credentials.ts"],"sourcesContent":["/**\n * Where the CLI keeps what belongs to a person rather than a project: stage\n * keys and stored provider credentials.\n *\n * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give\n * every run its own instead of reaching into whoever's home directory the\n * process happens to have. Unset, it is `~/.gkm`, where it has always been.\n */\n\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** The environment variable that moves the CLI's home. */\nexport const GKM_HOME_ENV = 'GKM_HOME';\n\n/** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */\nexport function gkmHome(env: NodeJS.ProcessEnv = process.env): string {\n\tconst configured = env[GKM_HOME_ENV];\n\treturn configured ? resolve(configured) : join(homedir(), '.gkm');\n}\n","import { existsSync, mkdirSync } from 'node:fs';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { gkmHome } from '../home';\n\n/**\n * Stored credentials for various services\n */\nexport interface StoredCredentials {\n\tdokploy?: {\n\t\t/** API token */\n\t\ttoken: string;\n\t\t/** Dokploy endpoint URL */\n\t\tendpoint: string;\n\t\t/** Registry ID in Dokploy (for Docker image pulls) */\n\t\tregistryId?: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n\thostinger?: {\n\t\t/** API token from hpanel.hostinger.com/profile/api */\n\t\ttoken: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n\tgodaddy?: {\n\t\t/** A Personal Access Token, scoped to domains.dns:update */\n\t\ttoken: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n}\n\n/**\n * Options for credential operations\n */\nexport interface CredentialOptions {\n\t/**\n\t * A directory whose `.gkm` holds the credentials. Default: the CLI's home\n\t * (`GKM_HOME`, else `~/.gkm`).\n\t */\n\troot?: string;\n\t/** The CLI's home itself, holding `credentials.json`. Wins over `root`. */\n\thome?: string;\n}\n\n/**\n * Get the path to the credentials directory\n */\nexport function getCredentialsDir(options?: CredentialOptions): string {\n\tif (options?.home) return options.home;\n\treturn options?.root ? join(options.root, '.gkm') : gkmHome();\n}\n\n/**\n * Get the path to the credentials file\n */\nexport function getCredentialsPath(options?: CredentialOptions): string {\n\treturn join(getCredentialsDir(options), 'credentials.json');\n}\n\n/**\n * Ensure the credentials directory exists\n */\nfunction ensureCredentialsDir(options?: CredentialOptions): void {\n\tconst dir = getCredentialsDir(options);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n}\n\n/**\n * Read stored credentials from disk\n */\nexport async function readCredentials(\n\toptions?: CredentialOptions,\n): Promise<StoredCredentials> {\n\tconst path = getCredentialsPath(options);\n\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\ttry {\n\t\tconst content = await readFile(path, 'utf-8');\n\t\treturn JSON.parse(content) as StoredCredentials;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n/**\n * Write credentials to disk\n */\nexport async function writeCredentials(\n\tcredentials: StoredCredentials,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tensureCredentialsDir(options);\n\tconst path = getCredentialsPath(options);\n\n\tawait writeFile(path, JSON.stringify(credentials, null, 2), {\n\t\tmode: 0o600, // Owner read/write only\n\t});\n}\n\n/**\n * Store Dokploy credentials\n */\nexport async function storeDokployCredentials(\n\ttoken: string,\n\tendpoint: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.dokploy = {\n\t\ttoken,\n\t\tendpoint,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get stored Dokploy credentials\n */\nexport async function getDokployCredentials(\n\toptions?: CredentialOptions,\n): Promise<{\n\ttoken: string;\n\tendpoint: string;\n\tregistryId?: string;\n} | null> {\n\tconst credentials = await readCredentials(options);\n\n\t// The environment first, and each half independently.\n\t//\n\t// `getDokployToken` has always read `DOKPLOY_API_TOKEN` while this — the\n\t// function the deploy path actually calls — read only the file. So a CI job\n\t// given the token as a secret had a token and nowhere to send it, and the\n\t// only way through was committing a credentials file or running an\n\t// interactive login on the runner.\n\t//\n\t// Read separately rather than as a pair because they arrive separately: a\n\t// token is a secret and belongs in the environment, while an endpoint is\n\t// configuration and usually belongs in `deploy.dokploy.endpoint`. Requiring\n\t// both from the same place is what made either one useless alone.\n\tconst token = process.env.DOKPLOY_API_TOKEN ?? credentials.dokploy?.token;\n\tconst endpoint =\n\t\tprocess.env.DOKPLOY_ENDPOINT ?? credentials.dokploy?.endpoint;\n\n\tif (!token || !endpoint) return null;\n\n\treturn {\n\t\ttoken,\n\t\tendpoint: endpoint.replace(/\\/$/, ''),\n\t\t...(credentials.dokploy?.registryId\n\t\t\t? { registryId: credentials.dokploy.registryId }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Remove Dokploy credentials\n */\nexport async function removeDokployCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.dokploy) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.dokploy;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n\n/**\n * Remove all stored credentials\n */\nexport async function removeAllCredentials(\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst path = getCredentialsPath(options);\n\n\tif (existsSync(path)) {\n\t\tawait unlink(path);\n\t}\n}\n\n/**\n * Get Dokploy API token, checking stored credentials first, then environment\n */\nexport async function getDokployToken(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\t// First check environment variable (takes precedence)\n\tconst envToken = process.env.DOKPLOY_API_TOKEN;\n\tif (envToken) {\n\t\treturn envToken;\n\t}\n\n\t// Then check stored credentials\n\tconst stored = await getDokployCredentials(options);\n\tif (stored) {\n\t\treturn stored.token;\n\t}\n\n\treturn null;\n}\n\n/**\n * Get Dokploy endpoint from stored credentials\n */\nexport async function getDokployEndpoint(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\tconst stored = await getDokployCredentials(options);\n\treturn stored?.endpoint ?? null;\n}\n\n/**\n * Store Dokploy registry ID\n */\nexport async function storeDokployRegistryId(\n\tregistryId: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.dokploy) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found. Run \"gkm login --service dokploy\" first.',\n\t\t);\n\t}\n\n\tcredentials.dokploy.registryId = registryId;\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get Dokploy registry ID from stored credentials\n */\nexport async function getDokployRegistryId(\n\toptions?: CredentialOptions,\n): Promise<string | undefined> {\n\tconst stored = await getDokployCredentials(options);\n\treturn stored?.registryId ?? undefined;\n}\n\n// ============================================\n// Hostinger credentials\n// ============================================\n\n/**\n * Store Hostinger API token\n *\n * @param token - API token from hpanel.hostinger.com/profile/api\n */\nexport async function storeHostingerToken(\n\ttoken: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.hostinger = {\n\t\ttoken,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get stored Hostinger API token\n *\n * Checks environment variable first (HOSTINGER_API_TOKEN),\n * then falls back to stored credentials.\n */\nexport async function getHostingerToken(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\t// First check environment variable (takes precedence)\n\tconst envToken = process.env.HOSTINGER_API_TOKEN;\n\tif (envToken) {\n\t\treturn envToken;\n\t}\n\n\t// Then check stored credentials\n\tconst credentials = await readCredentials(options);\n\treturn credentials.hostinger?.token ?? null;\n}\n\n/**\n * Remove Hostinger credentials\n */\nexport async function removeHostingerCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.hostinger) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.hostinger;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n\n// ============================================\n// GoDaddy credentials\n// ============================================\n\n/**\n * Store a GoDaddy Personal Access Token.\n */\nexport async function storeGoDaddyToken(\n\ttoken: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.godaddy = {\n\t\ttoken,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Remove GoDaddy credentials\n */\nexport async function removeGoDaddyCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.godaddy) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.godaddy;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n","/**\n * Start a program with an argument array, never a shell string.\n *\n * `gkm build`, `gkm docker` and `gkm deploy` pass values that come from the\n * workspace — image refs, tags, build args, package names — to `docker` and\n * `turbo`. Joined into a string and handed to a shell, a package named\n * `x;curl …|sh` or a tag holding `$(…)` became part of the command line, which\n * matters most where the CLI builds a repository it didn't write: a CI job for a\n * fork, a shared build runner. Here every value reaches the program as one\n * `argv` element, whatever it contains.\n */\n\nimport { type SpawnOptions, spawn } from 'node:child_process';\n\n/** Long enough for a cold image build; short enough that a hung one ends. */\nexport const DEFAULT_TIMEOUT_MS = 30 * 60_000;\n\n/** How long a timed-out child has to exit on SIGTERM before it is killed. */\nconst KILL_GRACE_MS = 5_000;\n\nexport interface RunOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tstdio?: SpawnOptions['stdio'];\n\t/** Kill the child after this long. Defaults to {@link DEFAULT_TIMEOUT_MS}. */\n\ttimeoutMs?: number;\n\t/**\n\t * Kills the child when aborted, and rejects with the signal's reason — the\n\t * same as a stopped deploy's other calls.\n\t */\n\tsignal?: AbortSignal;\n}\n\n/** The command line as a person would read it — for messages, never to run. */\nfunction display(command: string, args: readonly string[]): string {\n\treturn [command, ...args].join(' ');\n}\n\n/** The program ran and exited unsuccessfully; its own output said why. */\nexport class CommandFailed extends Error {\n\tconstructor(\n\t\treadonly command: string,\n\t\treadonly args: readonly string[],\n\t\treadonly exitCode: number | null,\n\t\treadonly signal: NodeJS.Signals | null,\n\t) {\n\t\tsuper(\n\t\t\t`\\`${display(command, args)}\\` ${exitCode === null ? `was stopped by ${signal ?? 'a signal'}` : `exited with code ${exitCode}`}. Its output above says why; run it by hand to see it again.`,\n\t\t);\n\t\tthis.name = 'CommandFailed';\n\t}\n}\n\n/** The program ran past its timeout and was killed. */\nexport class CommandTimedOut extends Error {\n\tconstructor(\n\t\treadonly command: string,\n\t\treadonly args: readonly string[],\n\t\treadonly timeoutMs: number,\n\t) {\n\t\tsuper(\n\t\t\t`\\`${display(command, args)}\\` was still running after ${Math.round(timeoutMs / 1000)}s and was stopped. Check what it was waiting on — a registry, the Docker daemon, a prompt — and run it again.`,\n\t\t);\n\t\tthis.name = 'CommandTimedOut';\n\t}\n}\n\n/**\n * Run `command` with `args`, resolving when it exits 0.\n *\n * Rejects with {@link CommandFailed} on any other exit, {@link CommandTimedOut}\n * once `timeoutMs` passes (after the child is gone), and with the spawn error\n * itself when the program cannot be started at all — `ENOENT` already names it.\n */\nexport async function run(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: RunOptions = {},\n): Promise<void> {\n\tawait spawnChild(command, args, options, false);\n}\n\n/**\n * {@link run}, resolving with what the program wrote to stdout — for a value\n * the CLI reads back, such as the digest `docker inspect` reports. stderr still\n * reaches the terminal, so a failure explains itself the same way.\n */\nexport function runOutput(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: Omit<RunOptions, 'stdio'> = {},\n): Promise<string> {\n\treturn spawnChild(command, args, options, true);\n}\n\nfunction spawnChild(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: RunOptions,\n\tcapture: boolean,\n): Promise<string> {\n\tconst { timeoutMs = DEFAULT_TIMEOUT_MS, ...spawnOptions } = options;\n\n\treturn new Promise<string>((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: 'inherit',\n\t\t\t...spawnOptions,\n\t\t\t...(capture ? { stdio: ['ignore', 'pipe', 'inherit'] } : {}),\n\t\t\tshell: false,\n\t\t});\n\n\t\tlet stdout = '';\n\t\tchild.stdout?.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString();\n\t\t});\n\n\t\tlet timedOut = false;\n\t\tlet killer: NodeJS.Timeout | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tchild.kill('SIGTERM');\n\t\t\t// A child that ignores SIGTERM would hold the deploy open forever.\n\t\t\tkiller = setTimeout(() => child.kill('SIGKILL'), KILL_GRACE_MS);\n\t\t\tkiller.unref?.();\n\t\t}, timeoutMs);\n\t\ttimer.unref?.();\n\n\t\tconst settle = () => {\n\t\t\tclearTimeout(timer);\n\t\t\tif (killer) clearTimeout(killer);\n\t\t};\n\n\t\tchild.on('error', (error) => {\n\t\t\tsettle();\n\t\t\t// Node reports an abort as its own `AbortError`; the caller asked\n\t\t\t// with a reason, and that is what it should get back.\n\t\t\treject(spawnOptions.signal?.aborted ? spawnOptions.signal.reason : error);\n\t\t});\n\n\t\tchild.on('close', (code: number | null, signal: NodeJS.Signals | null) => {\n\t\t\tsettle();\n\t\t\tif (spawnOptions.signal?.aborted) reject(spawnOptions.signal.reason);\n\t\t\telse if (timedOut) reject(new CommandTimedOut(command, args, timeoutMs));\n\t\t\telse if (code === 0) resolve(stdout);\n\t\t\telse reject(new CommandFailed(command, args, code, signal));\n\t\t});\n\t});\n}\n","/**\n * How a deploy gets the credentials it acts with.\n *\n * `deploy()` never prompts and never reads a terminal: it asks a\n * `CredentialProvider` and, when the provider has nothing, stops with\n * `MissingCredential` naming what it needed and how to supply it. Whether to\n * ask a person, read a vault or fail is the caller's decision — `gkm deploy`\n * prompts at a terminal and stores what was typed; a CI job sets the\n * environment; a host passes its own provider.\n */\n\nimport { readCredentials } from '../auth/credentials';\nimport { GkmError } from '../errors';\n\n/**\n * What each kind of credential is asked for with, and what it is.\n *\n * A target that needs a kind the CLI does not know declares it by augmenting\n * this interface, and lists it in its `credentials`:\n *\n * ```ts\n * declare module '@geekmidas/cli/target' {\n * interface CredentialKinds {\n * fly: { request: { org: string }; value: { token: string } };\n * }\n * }\n * ```\n */\nexport interface CredentialKinds {\n\t/** The Dokploy API a stage deploys through. */\n\tdokploy: {\n\t\t/** `deploy.dokploy.endpoint`, when the config names one. */\n\t\trequest: { endpoint?: string };\n\t\tvalue: { endpoint: string; token: string };\n\t};\n\t/**\n\t * A container registry login, for Dokploy to pull with. Asked for only when\n\t * Dokploy has no registry for `deploy.registry` and one has to be\n\t * created.\n\t */\n\tregistry: {\n\t\t/** `deploy.registry`. */\n\t\trequest: { url: string };\n\t\tvalue: { username: string; password: string };\n\t};\n\t/**\n\t * The AWS account a stage deploys to, for the SST target's `sst deploy`.\n\t * Handed to that one command's environment and to nothing else.\n\t */\n\taws: {\n\t\t/** The stage, for a provider that keeps one account per stage. */\n\t\trequest: { stage: string };\n\t\tvalue: AwsCredential;\n\t};\n\t/**\n\t * A GoDaddy Personal Access Token, for a `dns` domain whose provider is\n\t * `godaddy`. Read on the machine that writes the records — never the\n\t * server's.\n\t */\n\tgodaddy: {\n\t\trequest: Record<never, never>;\n\t\tvalue: GoDaddyCredential;\n\t};\n\t/**\n\t * A Hostinger API token, for a `dns` domain whose provider is\n\t * `hostinger`. Like GoDaddy's, read where the records are written.\n\t */\n\thostinger: {\n\t\trequest: Record<never, never>;\n\t\tvalue: HostingerCredential;\n\t};\n}\n\n/** A Hostinger API token, from hpanel.hostinger.com/profile/api. */\nexport interface HostingerCredential {\n\ttoken: string;\n}\n\n/** A GoDaddy Personal Access Token, sent as `Authorization: Bearer <token>`. */\nexport interface GoDaddyCredential {\n\ttoken: string;\n}\n\n/**\n * Who to act as on AWS: a named profile, or keys.\n *\n * Never both. Given both, every AWS SDK takes the keys and ignores the\n * profile, so `--profile prod` with staging's keys still exported would deploy\n * production's stack into staging's account — the reason `secretsStoreFor`\n * resolves a named profile on its own, and why this cannot express the mix.\n */\nexport type AwsCredential =\n\t| {\n\t\t\t/** A profile in `~/.aws/config` — keys, SSO, an assumed role. */\n\t\t\tprofile: string;\n\t\t\tregion?: string;\n\t }\n\t| {\n\t\t\taccessKeyId: string;\n\t\t\tsecretAccessKey: string;\n\t\t\t/** Present for temporary keys: an assumed role, GitHub's OIDC. */\n\t\t\tsessionToken?: string;\n\t\t\tregion?: string;\n\t };\n\nexport type CredentialKind = keyof CredentialKinds;\n\n/** What a deploy asks a provider for. */\nexport type CredentialRequest<K extends CredentialKind = CredentialKind> = {\n\t[P in K]: { kind: P } & CredentialKinds[P]['request'];\n}[K];\n\n/** What a provider answers with. */\nexport type Credential<K extends CredentialKind> = CredentialKinds[K]['value'];\n\nexport interface CredentialProvider {\n\t/**\n\t * The credential `request` asks for, or `undefined` when this provider has\n\t * none — the deploy then raises {@link MissingCredential}.\n\t */\n\tget<K extends CredentialKind>(\n\t\trequest: CredentialRequest<K>,\n\t\toptions?: { signal?: AbortSignal },\n\t): Promise<Credential<K> | undefined>;\n}\n\n/**\n * How to supply each kind the CLI knows, for the error that says it is\n * missing. A target's own kinds are its to explain.\n */\nconst HOW_TO_PROVIDE: Partial<Record<CredentialKind, string>> = {\n\tdokploy:\n\t\t\"Set DOKPLOY_API_TOKEN (and DOKPLOY_ENDPOINT, or deploy.dokploy.endpoint in gkm.config.ts), run `gkm login --provider dokploy`, or pass them through the deploy's CredentialProvider.\",\n\tregistry:\n\t\t'Add the registry in Dokploy (Settings → Docker Registry) and set deploy.dokploy.registryId, set DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD, or run `gkm deploy` at a terminal to be asked for them.',\n\tgodaddy:\n\t\t'Set GODADDY_API_TOKEN to a Personal Access Token scoped to domains.dns:update (create one in the GoDaddy developer dashboard), or run `gkm login --provider godaddy`.',\n\thostinger:\n\t\t'Set HOSTINGER_API_TOKEN to a token from hpanel.hostinger.com/profile/api, or run `gkm login --provider hostinger`.',\n\taws: \"Set AWS_PROFILE to the stage account's profile, or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (and AWS_SESSION_TOKEN) — in CI, the keys aws-actions/configure-aws-credentials exports — or pass them through the deploy's CredentialProvider.\",\n};\n\n/** A deploy needed a credential, and its provider had none. */\nexport class MissingCredential extends GkmError {\n\tconstructor(\n\t\treadonly kind: CredentialKind,\n\t\t/** What it was for: the Dokploy endpoint or the registry URL. */\n\t\treadonly target: string | undefined,\n\t\t/** How to supply it. */\n\t\treadonly howToProvide: string = HOW_TO_PROVIDE[kind] ??\n\t\t\t\"Pass it through the deploy's CredentialProvider.\",\n\t) {\n\t\tconst what =\n\t\t\tkind === 'dokploy'\n\t\t\t\t? `No Dokploy credentials${target ? ` for ${target}` : ''}.`\n\t\t\t\t: kind === 'registry'\n\t\t\t\t\t? `Dokploy has no registry for ${target ?? 'the configured registry'}, and there are no credentials to create one with.`\n\t\t\t\t\t: kind === 'aws'\n\t\t\t\t\t\t? `No AWS credentials${target ? ` for the \"${target}\" stage` : ''}.`\n\t\t\t\t\t\t: kind === 'godaddy'\n\t\t\t\t\t\t\t? `No GoDaddy API token${target ? ` for ${target}` : ''}.`\n\t\t\t\t\t\t\t: kind === 'hostinger'\n\t\t\t\t\t\t\t\t? `No Hostinger API token${target ? ` for ${target}` : ''}.`\n\t\t\t\t\t\t\t\t: `No \"${String(kind)}\" credentials${target ? ` for ${target}` : ''}.`;\n\t\tsuper(`${what} ${howToProvide}`);\n\t\tthis.name = 'MissingCredential';\n\t}\n}\n\n/** Whatever was asked for, from the first provider that has it. */\nexport function chainCredentials(\n\t...providers: CredentialProvider[]\n): CredentialProvider {\n\treturn {\n\t\tasync get(request, options) {\n\t\t\tfor (const provider of providers) {\n\t\t\t\tconst found = await provider.get(request, options);\n\t\t\t\tif (found) return found;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\nexport interface StoredCredentialsOptions {\n\t/** Where to read the variables from. Defaults to `process.env`. */\n\tenv?: NodeJS.ProcessEnv;\n\t/**\n\t * The CLI's home, whose `credentials.json` holds stored logins. Defaults\n\t * to `GKM_HOME`, else `~/.gkm`.\n\t */\n\thome?: string;\n}\n\n/**\n * Credentials from the environment, then from what `gkm login` stored. What\n * `deploy()` uses when it is handed no provider.\n *\n * - Dokploy: `DOKPLOY_API_TOKEN` / `DOKPLOY_ENDPOINT`, each falling back to\n * the stored login, and the endpoint finally to `deploy.dokploy.endpoint`.\n * Each half is read on its own: a token is a secret and belongs in the\n * environment, an endpoint is configuration and belongs in the config.\n * - Registry: `DOCKER_REGISTRY_USERNAME` / `DOCKER_REGISTRY_PASSWORD`.\n * - AWS: `AWS_PROFILE` when it is set, and then nothing else; otherwise\n * `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`. The\n * profile winning is `secretsStoreFor`'s rule: a profile is a choice of\n * account someone made, exported keys may be left over from another.\n * Read here, by name, and handed only to the command that deploys — the\n * sandbox every other step runs in passes no `AWS_*` on.\n */\nexport function storedCredentials(\n\toptions: StoredCredentialsOptions = {},\n): CredentialProvider {\n\tconst env = options.env ?? process.env;\n\n\treturn {\n\t\tasync get(asked) {\n\t\t\t// The union, so a switch on `kind` narrows it: `K` itself never is.\n\t\t\tconst request = asked as CredentialRequest;\n\t\t\tswitch (request.kind) {\n\t\t\t\tcase 'dokploy': {\n\t\t\t\t\tconst stored = (\n\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t)\n\t\t\t\t\t).dokploy;\n\t\t\t\t\tconst token = env.DOKPLOY_API_TOKEN ?? stored?.token;\n\t\t\t\t\tconst endpoint =\n\t\t\t\t\t\tenv.DOKPLOY_ENDPOINT ?? stored?.endpoint ?? request.endpoint;\n\t\t\t\t\tif (!token || !endpoint) return undefined;\n\t\t\t\t\treturn { endpoint: endpoint.replace(/\\/$/, ''), token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'registry': {\n\t\t\t\t\tconst username = env.DOCKER_REGISTRY_USERNAME;\n\t\t\t\t\tconst password = env.DOCKER_REGISTRY_PASSWORD;\n\t\t\t\t\tif (!username || !password) return undefined;\n\t\t\t\t\treturn { username, password } as never;\n\t\t\t\t}\n\t\t\t\tcase 'godaddy': {\n\t\t\t\t\t// The environment first, then the stored login.\n\t\t\t\t\tconst token =\n\t\t\t\t\t\tenv.GODADDY_API_TOKEN ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).godaddy?.token;\n\t\t\t\t\tif (!token) return undefined;\n\t\t\t\t\treturn { token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'hostinger': {\n\t\t\t\t\tconst token =\n\t\t\t\t\t\tenv.HOSTINGER_API_TOKEN ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).hostinger?.token;\n\t\t\t\t\tif (!token) return undefined;\n\t\t\t\t\treturn { token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'aws': {\n\t\t\t\t\tconst region = env.AWS_REGION ?? env.AWS_DEFAULT_REGION;\n\t\t\t\t\tconst where = region ? { region } : {};\n\t\t\t\t\tif (env.AWS_PROFILE) {\n\t\t\t\t\t\treturn { profile: env.AWS_PROFILE, ...where } as never;\n\t\t\t\t\t}\n\t\t\t\t\tconst accessKeyId = env.AWS_ACCESS_KEY_ID;\n\t\t\t\t\tconst secretAccessKey = env.AWS_SECRET_ACCESS_KEY;\n\t\t\t\t\tif (!accessKeyId || !secretAccessKey) return undefined;\n\t\t\t\t\treturn {\n\t\t\t\t\t\taccessKeyId,\n\t\t\t\t\t\tsecretAccessKey,\n\t\t\t\t\t\t...(env.AWS_SESSION_TOKEN\n\t\t\t\t\t\t\t? { sessionToken: env.AWS_SESSION_TOKEN }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t...where,\n\t\t\t\t\t} as never;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A kind a target declared: nothing stored here can answer it.\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"credentials-DpfnUvIR.mjs","names":[],"sources":["../src/home.ts","../src/auth/credentials.ts","../src/run.ts","../src/deploy/credentials.ts"],"sourcesContent":["/**\n * Where the CLI keeps what belongs to a person rather than a project: stage\n * keys and stored provider credentials.\n *\n * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give\n * every run its own instead of reaching into whoever's home directory the\n * process happens to have. Unset, it is `~/.gkm`, where it has always been.\n */\n\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** The environment variable that moves the CLI's home. */\nexport const GKM_HOME_ENV = 'GKM_HOME';\n\n/** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */\nexport function gkmHome(env: NodeJS.ProcessEnv = process.env): string {\n\tconst configured = env[GKM_HOME_ENV];\n\treturn configured ? resolve(configured) : join(homedir(), '.gkm');\n}\n","import { existsSync, mkdirSync } from 'node:fs';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { gkmHome } from '../home';\n\n/**\n * Stored credentials for various services\n */\nexport interface StoredCredentials {\n\tdokploy?: {\n\t\t/** API token */\n\t\ttoken: string;\n\t\t/** Dokploy endpoint URL */\n\t\tendpoint: string;\n\t\t/** Registry ID in Dokploy (for Docker image pulls) */\n\t\tregistryId?: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n\thostinger?: {\n\t\t/** API token from hpanel.hostinger.com/profile/api */\n\t\ttoken: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n\tgodaddy?: {\n\t\t/** A Personal Access Token, scoped to domains.dns:update */\n\t\ttoken: string;\n\t\t/** When the credentials were stored */\n\t\tstoredAt: string;\n\t};\n}\n\n/**\n * Options for credential operations\n */\nexport interface CredentialOptions {\n\t/**\n\t * A directory whose `.gkm` holds the credentials. Default: the CLI's home\n\t * (`GKM_HOME`, else `~/.gkm`).\n\t */\n\troot?: string;\n\t/** The CLI's home itself, holding `credentials.json`. Wins over `root`. */\n\thome?: string;\n}\n\n/**\n * Get the path to the credentials directory\n */\nexport function getCredentialsDir(options?: CredentialOptions): string {\n\tif (options?.home) return options.home;\n\treturn options?.root ? join(options.root, '.gkm') : gkmHome();\n}\n\n/**\n * Get the path to the credentials file\n */\nexport function getCredentialsPath(options?: CredentialOptions): string {\n\treturn join(getCredentialsDir(options), 'credentials.json');\n}\n\n/**\n * Ensure the credentials directory exists\n */\nfunction ensureCredentialsDir(options?: CredentialOptions): void {\n\tconst dir = getCredentialsDir(options);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n}\n\n/**\n * Read stored credentials from disk\n */\nexport async function readCredentials(\n\toptions?: CredentialOptions,\n): Promise<StoredCredentials> {\n\tconst path = getCredentialsPath(options);\n\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\ttry {\n\t\tconst content = await readFile(path, 'utf-8');\n\t\treturn JSON.parse(content) as StoredCredentials;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n/**\n * Write credentials to disk\n */\nexport async function writeCredentials(\n\tcredentials: StoredCredentials,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tensureCredentialsDir(options);\n\tconst path = getCredentialsPath(options);\n\n\tawait writeFile(path, JSON.stringify(credentials, null, 2), {\n\t\tmode: 0o600, // Owner read/write only\n\t});\n}\n\n/**\n * Store Dokploy credentials\n */\nexport async function storeDokployCredentials(\n\ttoken: string,\n\tendpoint: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.dokploy = {\n\t\ttoken,\n\t\tendpoint,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get stored Dokploy credentials\n */\nexport async function getDokployCredentials(\n\toptions?: CredentialOptions,\n): Promise<{\n\ttoken: string;\n\tendpoint: string;\n\tregistryId?: string;\n} | null> {\n\tconst credentials = await readCredentials(options);\n\n\t// The environment first, and each half independently.\n\t//\n\t// `getDokployToken` has always read `DOKPLOY_API_TOKEN` while this — the\n\t// function the deploy path actually calls — read only the file. So a CI job\n\t// given the token as a secret had a token and nowhere to send it, and the\n\t// only way through was committing a credentials file or running an\n\t// interactive login on the runner.\n\t//\n\t// Read separately rather than as a pair because they arrive separately: a\n\t// token is a secret and belongs in the environment, while an endpoint is\n\t// configuration and usually belongs in `deploy.dokploy.endpoint`. Requiring\n\t// both from the same place is what made either one useless alone.\n\tconst token = process.env.DOKPLOY_API_TOKEN ?? credentials.dokploy?.token;\n\tconst endpoint =\n\t\tprocess.env.DOKPLOY_ENDPOINT ?? credentials.dokploy?.endpoint;\n\n\tif (!token || !endpoint) return null;\n\n\treturn {\n\t\ttoken,\n\t\tendpoint: endpoint.replace(/\\/$/, ''),\n\t\t...(credentials.dokploy?.registryId\n\t\t\t? { registryId: credentials.dokploy.registryId }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Remove Dokploy credentials\n */\nexport async function removeDokployCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.dokploy) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.dokploy;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n\n/**\n * Remove all stored credentials\n */\nexport async function removeAllCredentials(\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst path = getCredentialsPath(options);\n\n\tif (existsSync(path)) {\n\t\tawait unlink(path);\n\t}\n}\n\n/**\n * Get Dokploy API token, checking stored credentials first, then environment\n */\nexport async function getDokployToken(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\t// First check environment variable (takes precedence)\n\tconst envToken = process.env.DOKPLOY_API_TOKEN;\n\tif (envToken) {\n\t\treturn envToken;\n\t}\n\n\t// Then check stored credentials\n\tconst stored = await getDokployCredentials(options);\n\tif (stored) {\n\t\treturn stored.token;\n\t}\n\n\treturn null;\n}\n\n/**\n * Get Dokploy endpoint from stored credentials\n */\nexport async function getDokployEndpoint(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\tconst stored = await getDokployCredentials(options);\n\treturn stored?.endpoint ?? null;\n}\n\n/**\n * Store Dokploy registry ID\n */\nexport async function storeDokployRegistryId(\n\tregistryId: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.dokploy) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found. Run \"gkm login --service dokploy\" first.',\n\t\t);\n\t}\n\n\tcredentials.dokploy.registryId = registryId;\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get Dokploy registry ID from stored credentials\n */\nexport async function getDokployRegistryId(\n\toptions?: CredentialOptions,\n): Promise<string | undefined> {\n\tconst stored = await getDokployCredentials(options);\n\treturn stored?.registryId ?? undefined;\n}\n\n// ============================================\n// Hostinger credentials\n// ============================================\n\n/**\n * Store Hostinger API token\n *\n * @param token - API token from hpanel.hostinger.com/profile/api\n */\nexport async function storeHostingerToken(\n\ttoken: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.hostinger = {\n\t\ttoken,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Get stored Hostinger API token\n *\n * Checks environment variable first (HOSTINGER_API_TOKEN),\n * then falls back to stored credentials.\n */\nexport async function getHostingerToken(\n\toptions?: CredentialOptions,\n): Promise<string | null> {\n\t// First check environment variable (takes precedence)\n\tconst envToken = process.env.HOSTINGER_API_TOKEN;\n\tif (envToken) {\n\t\treturn envToken;\n\t}\n\n\t// Then check stored credentials\n\tconst credentials = await readCredentials(options);\n\treturn credentials.hostinger?.token ?? null;\n}\n\n/**\n * Remove Hostinger credentials\n */\nexport async function removeHostingerCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.hostinger) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.hostinger;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n\n// ============================================\n// GoDaddy credentials\n// ============================================\n\n/**\n * Store a GoDaddy Personal Access Token.\n */\nexport async function storeGoDaddyToken(\n\ttoken: string,\n\toptions?: CredentialOptions,\n): Promise<void> {\n\tconst credentials = await readCredentials(options);\n\n\tcredentials.godaddy = {\n\t\ttoken,\n\t\tstoredAt: new Date().toISOString(),\n\t};\n\n\tawait writeCredentials(credentials, options);\n}\n\n/**\n * Remove GoDaddy credentials\n */\nexport async function removeGoDaddyCredentials(\n\toptions?: CredentialOptions,\n): Promise<boolean> {\n\tconst credentials = await readCredentials(options);\n\n\tif (!credentials.godaddy) {\n\t\treturn false;\n\t}\n\n\tdelete credentials.godaddy;\n\tawait writeCredentials(credentials, options);\n\treturn true;\n}\n","/**\n * Start a program with an argument array, never a shell string.\n *\n * `gkm build`, `gkm docker` and `gkm deploy` pass values that come from the\n * workspace — image refs, tags, build args, package names — to `docker` and\n * `turbo`. Joined into a string and handed to a shell, a package named\n * `x;curl …|sh` or a tag holding `$(…)` became part of the command line, which\n * matters most where the CLI builds a repository it didn't write: a CI job for a\n * fork, a shared build runner. Here every value reaches the program as one\n * `argv` element, whatever it contains.\n */\n\nimport { type SpawnOptions, spawn } from 'node:child_process';\n\n/** Long enough for a cold image build; short enough that a hung one ends. */\nexport const DEFAULT_TIMEOUT_MS = 30 * 60_000;\n\n/** How long a timed-out child has to exit on SIGTERM before it is killed. */\nconst KILL_GRACE_MS = 5_000;\n\nexport interface RunOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tstdio?: SpawnOptions['stdio'];\n\t/** Kill the child after this long. Defaults to {@link DEFAULT_TIMEOUT_MS}. */\n\ttimeoutMs?: number;\n\t/**\n\t * Kills the child when aborted, and rejects with the signal's reason — the\n\t * same as a stopped deploy's other calls.\n\t */\n\tsignal?: AbortSignal;\n}\n\n/** The command line as a person would read it — for messages, never to run. */\nfunction display(command: string, args: readonly string[]): string {\n\treturn [command, ...args].join(' ');\n}\n\n/** The program ran and exited unsuccessfully; its own output said why. */\nexport class CommandFailed extends Error {\n\tconstructor(\n\t\treadonly command: string,\n\t\treadonly args: readonly string[],\n\t\treadonly exitCode: number | null,\n\t\treadonly signal: NodeJS.Signals | null,\n\t) {\n\t\tsuper(\n\t\t\t`\\`${display(command, args)}\\` ${exitCode === null ? `was stopped by ${signal ?? 'a signal'}` : `exited with code ${exitCode}`}. Its output above says why; run it by hand to see it again.`,\n\t\t);\n\t\tthis.name = 'CommandFailed';\n\t}\n}\n\n/** The program ran past its timeout and was killed. */\nexport class CommandTimedOut extends Error {\n\tconstructor(\n\t\treadonly command: string,\n\t\treadonly args: readonly string[],\n\t\treadonly timeoutMs: number,\n\t) {\n\t\tsuper(\n\t\t\t`\\`${display(command, args)}\\` was still running after ${Math.round(timeoutMs / 1000)}s and was stopped. Check what it was waiting on — a registry, the Docker daemon, a prompt — and run it again.`,\n\t\t);\n\t\tthis.name = 'CommandTimedOut';\n\t}\n}\n\n/**\n * Run `command` with `args`, resolving when it exits 0.\n *\n * Rejects with {@link CommandFailed} on any other exit, {@link CommandTimedOut}\n * once `timeoutMs` passes (after the child is gone), and with the spawn error\n * itself when the program cannot be started at all — `ENOENT` already names it.\n */\nexport async function run(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: RunOptions = {},\n): Promise<void> {\n\tawait spawnChild(command, args, options, false);\n}\n\n/**\n * {@link run}, resolving with what the program wrote to stdout — for a value\n * the CLI reads back, such as the digest `docker inspect` reports. stderr still\n * reaches the terminal, so a failure explains itself the same way.\n */\nexport function runOutput(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: Omit<RunOptions, 'stdio'> = {},\n): Promise<string> {\n\treturn spawnChild(command, args, options, true);\n}\n\nfunction spawnChild(\n\tcommand: string,\n\targs: readonly string[],\n\toptions: RunOptions,\n\tcapture: boolean,\n): Promise<string> {\n\tconst { timeoutMs = DEFAULT_TIMEOUT_MS, ...spawnOptions } = options;\n\n\treturn new Promise<string>((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: 'inherit',\n\t\t\t...spawnOptions,\n\t\t\t...(capture ? { stdio: ['ignore', 'pipe', 'inherit'] } : {}),\n\t\t\tshell: false,\n\t\t});\n\n\t\tlet stdout = '';\n\t\tchild.stdout?.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString();\n\t\t});\n\n\t\tlet timedOut = false;\n\t\tlet killer: NodeJS.Timeout | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tchild.kill('SIGTERM');\n\t\t\t// A child that ignores SIGTERM would hold the deploy open forever.\n\t\t\tkiller = setTimeout(() => child.kill('SIGKILL'), KILL_GRACE_MS);\n\t\t\tkiller.unref?.();\n\t\t}, timeoutMs);\n\t\ttimer.unref?.();\n\n\t\tconst settle = () => {\n\t\t\tclearTimeout(timer);\n\t\t\tif (killer) clearTimeout(killer);\n\t\t};\n\n\t\tchild.on('error', (error) => {\n\t\t\tsettle();\n\t\t\t// Node reports an abort as its own `AbortError`; the caller asked\n\t\t\t// with a reason, and that is what it should get back.\n\t\t\treject(spawnOptions.signal?.aborted ? spawnOptions.signal.reason : error);\n\t\t});\n\n\t\tchild.on('close', (code: number | null, signal: NodeJS.Signals | null) => {\n\t\t\tsettle();\n\t\t\tif (spawnOptions.signal?.aborted) reject(spawnOptions.signal.reason);\n\t\t\telse if (timedOut) reject(new CommandTimedOut(command, args, timeoutMs));\n\t\t\telse if (code === 0) resolve(stdout);\n\t\t\telse reject(new CommandFailed(command, args, code, signal));\n\t\t});\n\t});\n}\n","/**\n * How a deploy gets the credentials it acts with.\n *\n * `deploy()` never prompts and never reads a terminal: it asks a\n * `CredentialProvider` and, when the provider has nothing, stops with\n * `MissingCredential` naming what it needed and how to supply it. Whether to\n * ask a person, read a vault or fail is the caller's decision — `gkm deploy`\n * prompts at a terminal and stores what was typed; a CI job sets the\n * environment; a host passes its own provider.\n */\n\nimport { readCredentials } from '../auth/credentials';\nimport { GkmError } from '../errors';\n\n/**\n * What each kind of credential is asked for with, and what it is.\n *\n * A target that needs a kind the CLI does not know declares it by augmenting\n * this interface, and lists it in its `credentials`:\n *\n * ```ts\n * declare module '@geekmidas/cli/target' {\n * interface CredentialKinds {\n * fly: { request: { org: string }; value: { token: string } };\n * }\n * }\n * ```\n */\nexport interface CredentialKinds {\n\t/** The Dokploy API a stage deploys through. */\n\tdokploy: {\n\t\t/** `deploy.dokploy.endpoint`, when the config names one. */\n\t\trequest: { endpoint?: string };\n\t\tvalue: { endpoint: string; token: string };\n\t};\n\t/**\n\t * A container registry login, for Dokploy to pull with. Asked for only when\n\t * Dokploy has no registry for `deploy.registry` and one has to be\n\t * created.\n\t */\n\tregistry: {\n\t\t/** `deploy.registry`. */\n\t\trequest: { url: string };\n\t\tvalue: { username: string; password: string };\n\t};\n\t/**\n\t * The AWS account a stage deploys to, for the SST target's `sst deploy`.\n\t * Handed to that one command's environment and to nothing else.\n\t */\n\taws: {\n\t\t/** The stage, for a provider that keeps one account per stage. */\n\t\trequest: { stage: string };\n\t\tvalue: AwsCredential;\n\t};\n\t/**\n\t * A GoDaddy Personal Access Token, for a `dns` domain whose provider is\n\t * `godaddy`. Read on the machine that writes the records — never the\n\t * server's.\n\t */\n\tgodaddy: {\n\t\trequest: Record<never, never>;\n\t\tvalue: GoDaddyCredential;\n\t};\n\t/**\n\t * A Hostinger API token, for a `dns` domain whose provider is\n\t * `hostinger`. Like GoDaddy's, read where the records are written.\n\t */\n\thostinger: {\n\t\trequest: Record<never, never>;\n\t\tvalue: HostingerCredential;\n\t};\n}\n\n/** A Hostinger API token, from hpanel.hostinger.com/profile/api. */\nexport interface HostingerCredential {\n\ttoken: string;\n}\n\n/** A GoDaddy Personal Access Token, sent as `Authorization: Bearer <token>`. */\nexport interface GoDaddyCredential {\n\ttoken: string;\n}\n\n/**\n * Who to act as on AWS: a named profile, or keys.\n *\n * Never both. Given both, every AWS SDK takes the keys and ignores the\n * profile, so `--profile prod` with staging's keys still exported would deploy\n * production's stack into staging's account — the reason `secretsStoreFor`\n * resolves a named profile on its own, and why this cannot express the mix.\n */\nexport type AwsCredential =\n\t| {\n\t\t\t/** A profile in `~/.aws/config` — keys, SSO, an assumed role. */\n\t\t\tprofile: string;\n\t\t\tregion?: string;\n\t }\n\t| {\n\t\t\taccessKeyId: string;\n\t\t\tsecretAccessKey: string;\n\t\t\t/** Present for temporary keys: an assumed role, GitHub's OIDC. */\n\t\t\tsessionToken?: string;\n\t\t\tregion?: string;\n\t };\n\nexport type CredentialKind = keyof CredentialKinds;\n\n/** What a deploy asks a provider for. */\nexport type CredentialRequest<K extends CredentialKind = CredentialKind> = {\n\t[P in K]: { kind: P } & CredentialKinds[P]['request'];\n}[K];\n\n/** What a provider answers with. */\nexport type Credential<K extends CredentialKind> = CredentialKinds[K]['value'];\n\nexport interface CredentialProvider {\n\t/**\n\t * The credential `request` asks for, or `undefined` when this provider has\n\t * none — the deploy then raises {@link MissingCredential}.\n\t */\n\tget<K extends CredentialKind>(\n\t\trequest: CredentialRequest<K>,\n\t\toptions?: { signal?: AbortSignal },\n\t): Promise<Credential<K> | undefined>;\n}\n\n/**\n * How to supply each kind the CLI knows, for the error that says it is\n * missing. A target's own kinds are its to explain.\n */\nconst HOW_TO_PROVIDE: Partial<Record<CredentialKind, string>> = {\n\tdokploy:\n\t\t\"Set DOKPLOY_API_TOKEN (and DOKPLOY_ENDPOINT, or deploy.dokploy.endpoint in gkm.config.ts), run `gkm login --provider dokploy`, or pass them through the deploy's CredentialProvider.\",\n\tregistry:\n\t\t'Add the registry in Dokploy (Settings → Docker Registry) and set deploy.dokploy.registryId, set DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD, or run `gkm deploy` at a terminal to be asked for them.',\n\tgodaddy:\n\t\t'Set GODADDY_API_TOKEN to a Personal Access Token scoped to domains.dns:update (create one in the GoDaddy developer dashboard), or run `gkm login --provider godaddy`.',\n\thostinger:\n\t\t'Set HOSTINGER_API_TOKEN to a token from hpanel.hostinger.com/profile/api, or run `gkm login --provider hostinger`.',\n\taws: \"Set AWS_PROFILE to the stage account's profile, or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (and AWS_SESSION_TOKEN) — in CI, the keys aws-actions/configure-aws-credentials exports — or pass them through the deploy's CredentialProvider.\",\n};\n\n/** A deploy needed a credential, and its provider had none. */\nexport class MissingCredential extends GkmError {\n\tconstructor(\n\t\treadonly kind: CredentialKind,\n\t\t/** What it was for: the Dokploy endpoint or the registry URL. */\n\t\treadonly target: string | undefined,\n\t\t/** How to supply it. */\n\t\treadonly howToProvide: string = HOW_TO_PROVIDE[kind] ??\n\t\t\t\"Pass it through the deploy's CredentialProvider.\",\n\t) {\n\t\tconst what =\n\t\t\tkind === 'dokploy'\n\t\t\t\t? `No Dokploy credentials${target ? ` for ${target}` : ''}.`\n\t\t\t\t: kind === 'registry'\n\t\t\t\t\t? `Dokploy has no registry for ${target ?? 'the configured registry'}, and there are no credentials to create one with.`\n\t\t\t\t\t: kind === 'aws'\n\t\t\t\t\t\t? `No AWS credentials${target ? ` for the \"${target}\" stage` : ''}.`\n\t\t\t\t\t\t: kind === 'godaddy'\n\t\t\t\t\t\t\t? `No GoDaddy API token${target ? ` for ${target}` : ''}.`\n\t\t\t\t\t\t\t: kind === 'hostinger'\n\t\t\t\t\t\t\t\t? `No Hostinger API token${target ? ` for ${target}` : ''}.`\n\t\t\t\t\t\t\t\t: `No \"${String(kind)}\" credentials${target ? ` for ${target}` : ''}.`;\n\t\tsuper(`${what} ${howToProvide}`);\n\t\tthis.name = 'MissingCredential';\n\t}\n}\n\n/** Whatever was asked for, from the first provider that has it. */\nexport function chainCredentials(\n\t...providers: CredentialProvider[]\n): CredentialProvider {\n\treturn {\n\t\tasync get(request, options) {\n\t\t\tfor (const provider of providers) {\n\t\t\t\tconst found = await provider.get(request, options);\n\t\t\t\tif (found) return found;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\nexport interface StoredCredentialsOptions {\n\t/** Where to read the variables from. Defaults to `process.env`. */\n\tenv?: NodeJS.ProcessEnv;\n\t/**\n\t * The CLI's home, whose `credentials.json` holds stored logins. Defaults\n\t * to `GKM_HOME`, else `~/.gkm`.\n\t */\n\thome?: string;\n}\n\n/**\n * Credentials from the environment, then from what `gkm login` stored. What\n * `deploy()` uses when it is handed no provider.\n *\n * - Dokploy: `DOKPLOY_API_TOKEN` / `DOKPLOY_ENDPOINT`, each falling back to\n * the stored login, and the endpoint finally to `deploy.dokploy.endpoint`.\n * Each half is read on its own: a token is a secret and belongs in the\n * environment, an endpoint is configuration and belongs in the config.\n * - Registry: `DOCKER_REGISTRY_USERNAME` / `DOCKER_REGISTRY_PASSWORD`.\n * - AWS: `AWS_PROFILE` when it is set, and then nothing else; otherwise\n * `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`. The\n * profile winning is `secretsStoreFor`'s rule: a profile is a choice of\n * account someone made, exported keys may be left over from another.\n * Read here, by name, and handed only to the command that deploys — the\n * sandbox every other step runs in passes no `AWS_*` on.\n */\nexport function storedCredentials(\n\toptions: StoredCredentialsOptions = {},\n): CredentialProvider {\n\tconst env = options.env ?? process.env;\n\n\treturn {\n\t\tasync get(asked) {\n\t\t\t// The union, so a switch on `kind` narrows it: `K` itself never is.\n\t\t\tconst request = asked as CredentialRequest;\n\t\t\tswitch (request.kind) {\n\t\t\t\tcase 'dokploy': {\n\t\t\t\t\tconst stored = (\n\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t)\n\t\t\t\t\t).dokploy;\n\t\t\t\t\tconst token = env.DOKPLOY_API_TOKEN ?? stored?.token;\n\t\t\t\t\tconst endpoint =\n\t\t\t\t\t\tenv.DOKPLOY_ENDPOINT ?? stored?.endpoint ?? request.endpoint;\n\t\t\t\t\tif (!token || !endpoint) return undefined;\n\t\t\t\t\treturn { endpoint: endpoint.replace(/\\/$/, ''), token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'registry': {\n\t\t\t\t\tconst username = env.DOCKER_REGISTRY_USERNAME;\n\t\t\t\t\tconst password = env.DOCKER_REGISTRY_PASSWORD;\n\t\t\t\t\tif (!username || !password) return undefined;\n\t\t\t\t\treturn { username, password } as never;\n\t\t\t\t}\n\t\t\t\tcase 'godaddy': {\n\t\t\t\t\t// The environment first, then the stored login.\n\t\t\t\t\tconst token =\n\t\t\t\t\t\tenv.GODADDY_API_TOKEN ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).godaddy?.token;\n\t\t\t\t\tif (!token) return undefined;\n\t\t\t\t\treturn { token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'hostinger': {\n\t\t\t\t\tconst token =\n\t\t\t\t\t\tenv.HOSTINGER_API_TOKEN ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tawait readCredentials(\n\t\t\t\t\t\t\t\toptions.home ? { home: options.home } : undefined,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).hostinger?.token;\n\t\t\t\t\tif (!token) return undefined;\n\t\t\t\t\treturn { token } as never;\n\t\t\t\t}\n\t\t\t\tcase 'aws': {\n\t\t\t\t\tconst region = env.AWS_REGION ?? env.AWS_DEFAULT_REGION;\n\t\t\t\t\tconst where = region ? { region } : {};\n\t\t\t\t\tif (env.AWS_PROFILE) {\n\t\t\t\t\t\treturn { profile: env.AWS_PROFILE, ...where } as never;\n\t\t\t\t\t}\n\t\t\t\t\tconst accessKeyId = env.AWS_ACCESS_KEY_ID;\n\t\t\t\t\tconst secretAccessKey = env.AWS_SECRET_ACCESS_KEY;\n\t\t\t\t\tif (!accessKeyId || !secretAccessKey) return undefined;\n\t\t\t\t\treturn {\n\t\t\t\t\t\taccessKeyId,\n\t\t\t\t\t\tsecretAccessKey,\n\t\t\t\t\t\t...(env.AWS_SESSION_TOKEN\n\t\t\t\t\t\t\t? { sessionToken: env.AWS_SESSION_TOKEN }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t...where,\n\t\t\t\t\t} as never;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A kind a target declared: nothing stored here can answer it.\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|