@geekmidas/cli 10.0.0-alpha.113 → 10.0.0-alpha.115
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-DWrDIXzQ.cjs → GoDaddyProvider-BDvIMTO-.cjs} +2 -2
- package/dist/{GoDaddyProvider-DWrDIXzQ.cjs.map → GoDaddyProvider-BDvIMTO-.cjs.map} +1 -1
- package/dist/{GoDaddyProvider-CPabc3XW.mjs → GoDaddyProvider-eW1mre1g.mjs} +2 -2
- package/dist/{GoDaddyProvider-CPabc3XW.mjs.map → GoDaddyProvider-eW1mre1g.mjs.map} +1 -1
- package/dist/{LegacyStateStore-BdXoAlYY.mjs → LegacyStateStore-Ba1_x0cr.mjs} +3 -3
- package/dist/{LegacyStateStore-BdXoAlYY.mjs.map → LegacyStateStore-Ba1_x0cr.mjs.map} +1 -1
- package/dist/{LegacyStateStore-fsyPGBWu.cjs → LegacyStateStore-DFeykTd8.cjs} +3 -3
- package/dist/{LegacyStateStore-fsyPGBWu.cjs.map → LegacyStateStore-DFeykTd8.cjs.map} +1 -1
- package/dist/{LocalStateStore-BrAX5yy7.mjs → LocalStateStore-C1rUUvBr.mjs} +2 -2
- package/dist/{LocalStateStore-BrAX5yy7.mjs.map → LocalStateStore-C1rUUvBr.mjs.map} +1 -1
- package/dist/{LocalStateStore-AtviUBky.cjs → LocalStateStore-CV-04jpI.cjs} +2 -2
- package/dist/{LocalStateStore-AtviUBky.cjs.map → LocalStateStore-CV-04jpI.cjs.map} +1 -1
- package/dist/{S3StateStore-tn5g80Sx.cjs → S3StateStore-CqYi-1sb.cjs} +2 -2
- package/dist/{S3StateStore-tn5g80Sx.cjs.map → S3StateStore-CqYi-1sb.cjs.map} +1 -1
- package/dist/{S3StateStore-Cx7njkBz.mjs → S3StateStore-Dszt4fN5.mjs} +2 -2
- package/dist/{S3StateStore-Cx7njkBz.mjs.map → S3StateStore-Dszt4fN5.mjs.map} +1 -1
- package/dist/{SSMStateStore-sqZ3oDmn.mjs → SSMStateStore-BYRUyMkE.mjs} +2 -2
- package/dist/{SSMStateStore-sqZ3oDmn.mjs.map → SSMStateStore-BYRUyMkE.mjs.map} +1 -1
- package/dist/{SSMStateStore-CAFde-Fq.cjs → SSMStateStore-zpHjDCAW.cjs} +2 -2
- package/dist/{SSMStateStore-CAFde-Fq.cjs.map → SSMStateStore-zpHjDCAW.cjs.map} +1 -1
- package/dist/{add-Cs8yT5iH.cjs → add-0XI8_HOf.cjs} +3 -3
- package/dist/{add-Cs8yT5iH.cjs.map → add-0XI8_HOf.cjs.map} +1 -1
- package/dist/{add-DJE7zqJ4.mjs → add-DXdJjp0b.mjs} +3 -3
- package/dist/{add-DJE7zqJ4.mjs.map → add-DXdJjp0b.mjs.map} +1 -1
- package/dist/{bundler-DrySVbXF.mjs → bundler-B2ysiCTa.mjs} +5 -5
- package/dist/{bundler-DrySVbXF.mjs.map → bundler-B2ysiCTa.mjs.map} +1 -1
- package/dist/{bundler-NrtItVBp.cjs → bundler-hvCgi0EG.cjs} +5 -5
- package/dist/{bundler-NrtItVBp.cjs.map → bundler-hvCgi0EG.cjs.map} +1 -1
- package/dist/{cli-CHzpFBh-.cjs → cli-5k6kV_i4.cjs} +2 -2
- package/dist/{cli-CHzpFBh-.cjs.map → cli-5k6kV_i4.cjs.map} +1 -1
- package/dist/{cli-DDY3jfTt.mjs → cli-H0uB_znq.mjs} +2 -2
- package/dist/{cli-DDY3jfTt.mjs.map → cli-H0uB_znq.mjs.map} +1 -1
- package/dist/{compose-CDC2bCme.mjs → compose-BEiJWrB7.mjs} +3 -3
- package/dist/{compose-CDC2bCme.mjs.map → compose-BEiJWrB7.mjs.map} +1 -1
- package/dist/{compose-ByIbIrzs.cjs → compose-CYeMW2_o.cjs} +3 -3
- package/dist/{compose-ByIbIrzs.cjs.map → compose-CYeMW2_o.cjs.map} +1 -1
- package/dist/deploy/public.cjs +6 -6
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-DLq9-m6H.mjs → deploy-Cyx5fSb7.mjs} +5 -5
- package/dist/{deploy-DLq9-m6H.mjs.map → deploy-Cyx5fSb7.mjs.map} +1 -1
- package/dist/{deploy-Dl_NavYE.cjs → deploy-Q5qo1OP-.cjs} +5 -5
- package/dist/{deploy-Dl_NavYE.cjs.map → deploy-Q5qo1OP-.cjs.map} +1 -1
- package/dist/{dns-pzftumxg.mjs → dns-CsApfzLc.mjs} +2 -2
- package/dist/{dns-pzftumxg.mjs.map → dns-CsApfzLc.mjs.map} +1 -1
- package/dist/{dns-C2TGXUF4.cjs → dns-v9viladZ.cjs} +2 -2
- package/dist/{dns-C2TGXUF4.cjs.map → dns-v9viladZ.cjs.map} +1 -1
- package/dist/{dokploy-B7-OwY2s.mjs → dokploy-DfUo_QRw.mjs} +2 -2
- package/dist/{dokploy-B7-OwY2s.mjs.map → dokploy-DfUo_QRw.mjs.map} +1 -1
- package/dist/{dokploy-OqBh8G4g.cjs → dokploy-Di7rC2z0.cjs} +2 -2
- package/dist/{dokploy-OqBh8G4g.cjs.map → dokploy-Di7rC2z0.cjs.map} +1 -1
- package/dist/{eas-Cne743nQ.cjs → eas-CIvNT6qa.cjs} +2 -2
- package/dist/{eas-Cne743nQ.cjs.map → eas-CIvNT6qa.cjs.map} +1 -1
- package/dist/{eas-DEpwISrQ.mjs → eas-CTfRmndW.mjs} +2 -2
- package/dist/{eas-DEpwISrQ.mjs.map → eas-CTfRmndW.mjs.map} +1 -1
- package/dist/{encryption-DoVnVU82.cjs → encryption--U4NsK7N.cjs} +2 -2
- package/dist/{encryption-DoVnVU82.cjs.map → encryption--U4NsK7N.cjs.map} +1 -1
- package/dist/{encryption-DJv_jEXi.mjs → encryption-BpTPmd7h.mjs} +2 -2
- package/dist/{encryption-DJv_jEXi.mjs.map → encryption-BpTPmd7h.mjs.map} +1 -1
- package/dist/{engine-Db71-OZL.mjs → engine-BFmHfek1.mjs} +3 -3
- package/dist/{engine-Db71-OZL.mjs.map → engine-BFmHfek1.mjs.map} +1 -1
- package/dist/{engine-CJhQb50j.cjs → engine-Ovl1PB6i.cjs} +3 -3
- package/dist/{engine-CJhQb50j.cjs.map → engine-Ovl1PB6i.cjs.map} +1 -1
- package/dist/{github-C3gblUvr.cjs → github-CTlPQ5Ra.cjs} +4 -4
- package/dist/{github-C3gblUvr.cjs.map → github-CTlPQ5Ra.cjs.map} +1 -1
- package/dist/{github-BMakI-k3.mjs → github-tWAGuR9i.mjs} +4 -4
- package/dist/{github-BMakI-k3.mjs.map → github-tWAGuR9i.mjs.map} +1 -1
- package/dist/{googlePlay-B6uiHi65.cjs → googlePlay-BNH729It.cjs} +3 -3
- package/dist/{googlePlay-B6uiHi65.cjs.map → googlePlay-BNH729It.cjs.map} +1 -1
- package/dist/{googlePlay-BYZ-J5sC.mjs → googlePlay-m1De-qIJ.mjs} +3 -3
- package/dist/{googlePlay-BYZ-J5sC.mjs.map → googlePlay-m1De-qIJ.mjs.map} +1 -1
- package/dist/index.cjs +104 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +104 -68
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-CQUGbptv.mjs → migrate-4B4RgAjU.mjs} +2 -2
- package/dist/{migrate-CQUGbptv.mjs.map → migrate-4B4RgAjU.mjs.map} +1 -1
- package/dist/{migrate-bDQzFvBN.cjs → migrate-BYEmpoIg.cjs} +2 -2
- package/dist/{migrate-bDQzFvBN.cjs.map → migrate-BYEmpoIg.cjs.map} +1 -1
- package/dist/{migrate-GLBZlrlJ.cjs → migrate-DZ2--SaO.cjs} +2 -2
- package/dist/{migrate-GLBZlrlJ.cjs.map → migrate-DZ2--SaO.cjs.map} +1 -1
- package/dist/{migrate-xHYaeBkd.mjs → migrate-X0Y7fz3N.mjs} +2 -2
- package/dist/{migrate-xHYaeBkd.mjs.map → migrate-X0Y7fz3N.mjs.map} +1 -1
- package/dist/{publish-SDG1WfYn.cjs → publish-BUvYjiZH.cjs} +2 -2
- package/dist/{publish-SDG1WfYn.cjs.map → publish-BUvYjiZH.cjs.map} +1 -1
- package/dist/{publish-CSctCNf4.mjs → publish-hhgraEhO.mjs} +2 -2
- package/dist/{publish-CSctCNf4.mjs.map → publish-hhgraEhO.mjs.map} +1 -1
- package/dist/{resolve-wG49Woex.cjs → resolve-DdFKTx8l.cjs} +3 -3
- package/dist/{resolve-wG49Woex.cjs.map → resolve-DdFKTx8l.cjs.map} +1 -1
- package/dist/{resolve-CxDqDmCD.mjs → resolve-DotGHvtX.mjs} +3 -3
- package/dist/{resolve-CxDqDmCD.mjs.map → resolve-DotGHvtX.mjs.map} +1 -1
- package/dist/{rollback-BQgEdr_p.mjs → rollback-9t9G3c_u.mjs} +4 -4
- package/dist/{rollback-BQgEdr_p.mjs.map → rollback-9t9G3c_u.mjs.map} +1 -1
- package/dist/{rollback-Cw-Z0mWn.cjs → rollback-D4xeUQvG.cjs} +4 -4
- package/dist/{rollback-Cw-Z0mWn.cjs.map → rollback-D4xeUQvG.cjs.map} +1 -1
- package/dist/{seeds-CIk0l4SC.mjs → seeds-CRkKeyW0.mjs} +19 -6
- package/dist/seeds-CRkKeyW0.mjs.map +1 -0
- package/dist/{seeds-Dk8YkLkM.cjs → seeds-DbKNcs3o.cjs} +19 -6
- package/dist/seeds-DbKNcs3o.cjs.map +1 -0
- package/dist/{serverSetup-BCbD8ksJ.cjs → serverSetup-CcWgNtiC.cjs} +93 -21
- package/dist/serverSetup-CcWgNtiC.cjs.map +1 -0
- package/dist/{serverSetup--O61SRvg.mjs → serverSetup-DlRKRfTi.mjs} +93 -21
- package/dist/serverSetup-DlRKRfTi.mjs.map +1 -0
- package/dist/{sniffer-2aK7cB2u.cjs → sniffer-B6T6za4n.cjs} +6 -6
- package/dist/{sniffer-2aK7cB2u.cjs.map → sniffer-B6T6za4n.cjs.map} +1 -1
- package/dist/{sniffer-CABMO-Bh.mjs → sniffer-CakkKKqQ.mjs} +6 -6
- package/dist/{sniffer-CABMO-Bh.mjs.map → sniffer-CakkKKqQ.mjs.map} +1 -1
- package/dist/{stage-ClKTHQoM.mjs → stage-Mp6qQIoD.mjs} +4 -4
- package/dist/{stage-ClKTHQoM.mjs.map → stage-Mp6qQIoD.mjs.map} +1 -1
- package/dist/{stage-DrCS0vKD.cjs → stage-W3PUt7ar.cjs} +4 -4
- package/dist/{stage-DrCS0vKD.cjs.map → stage-W3PUt7ar.cjs.map} +1 -1
- package/dist/{stages-DJrOYLZ-.mjs → stages-Cb9rqRbN.mjs} +16 -2
- package/dist/stages-Cb9rqRbN.mjs.map +1 -0
- package/dist/{stages-_3RVNG83.cjs → stages-D4SnG5yl.cjs} +16 -2
- package/dist/stages-D4SnG5yl.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.mjs +1 -1
- package/package.json +15 -15
- package/dist/seeds-CIk0l4SC.mjs.map +0 -1
- package/dist/seeds-Dk8YkLkM.cjs.map +0 -1
- package/dist/serverSetup--O61SRvg.mjs.map +0 -1
- package/dist/serverSetup-BCbD8ksJ.cjs.map +0 -1
- package/dist/stages-DJrOYLZ-.mjs.map +0 -1
- package/dist/stages-_3RVNG83.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-ByIbIrzs.cjs","names":["GkmError","spawn","run","runOutput","mkdir","dirname","GkmError","SERVER_IPV4_KEY","createServer","createConnection","spawn","CLIENT_IP_HEADER","GkmError","createHash","CLIENT_IP_HEADER","yaml","stringify","createHash","GkmError","localRolePassword","postgresSuperuser","LOCAL_RABBITMQ_USER","EMULATOR_ACCESS_KEY_ID","planFor","provisionOrder","DEFAULT_EVENTS","STACK_CACHE","proxyFor","certificateFor","workerUnits","provideKey","resolveStageTelemetry","usesTelemetry","stackLogs","externalServices","stageServiceDeclarations","stageProviderNotes","stackRedis","LOGS_SERVICE","bucketPolicies","hostFor","NoDomainForStage","appKey","networkEnv","isReservedStageKey","suppliedOnly","telemetryEnv","otlpTelemetryEnv","isTelemetryKey","publicBuildValues","appEnvKeys","scopeTelemetryEnv","telemetryOf","workerEnvKeys","stageBackups","stackBackups","join","LOGS_PORT","appDockerfile","workerDockerfile","devServicesUsed","validateImageRef","imageRef","WORKER_PORT","resolveHost","isMainFrontendApp","composeFor","portKeys","REDIS_SERVICE","redisService","logsService","BACKUPS_SERVICE","backupsService","composeBuildPaths","DEFAULT_IMAGES","TURBO_VERSION","dirname","GkmError","mkdir","readFile","writeFile","withGeneratedSecrets","initStageSecrets","resolveStageTelemetry","usesTelemetry","withLogsPassword","runsRedis","withRedisPassword","GkmError","request","GkmError","join","runOutput","pgClient","bucketClient","ensurePostgresLogin","migrateDatabases","seedDatabases","systemLookup","imageRef","discover","constructGlobs","imageLayout","loadLocalCredentials","existsSync","ComposeTlsFileMissing","stackHosts","isLocalHost","appEnvKeys","workerEnvKeys","installedFrom","requiredServerAddress","SERVER_IPV4_KEY","serverAddressHint","stageDns","DeployJournal","createComposeState","recordDnsChanges","HostNotPointingAtServer","isReservedStageKey","plannedSeeds","applyBuckets","applyPolicies","LEGACY_LOCAL_LOGIN","postgresStatements","backupsRoleStatements","applyPostgres","envFor","primaryPortKey","SeedFailed","DeploySeedsFailed","currentActor","readFile","LOGS_SERVICE","logsAccess","hostname","userInfo","mkdir","chmod","dirname","writeFile","rm","REDIS_SERVICE","BACKUPS_SERVICE","readdir","ensureDockerignore","findBuildRoot","stringify","defineTarget"],"sources":["../src/compose/docker.ts","../src/compose/server.ts","../src/compose/caddyfile.ts","../src/compose/images.ts","../src/compose/traefik.ts","../src/compose/stack.ts","../src/compose/edge.ts","../src/compose/secrets.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 * The Docker engine the stack runs on, as `DOCKER_HOST` names it: a\n\t * deployed stage's server, `ssh://user@host`. Absent for this machine's\n\t * engine — the local stage — whose environment is left as it is.\n\t *\n\t * Compose is a client: it reads the compose file and every `env_file` here\n\t * and sends their values in the API calls that create each container. A\n\t * stage's secrets therefore never land on the server as a file — they are\n\t * in the container's configuration, which only the server's Docker group\n\t * can read.\n\t */\n\thost?: 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/**\n * The environment a docker command for `engine` runs with: this process's,\n * with `DOCKER_HOST` pointing at the stack's engine when it is a server's.\n */\nexport function engineEnv(\n\tengine: Pick<StackRef, 'host'>,\n\textra: NodeJS.ProcessEnv = {},\n): NodeJS.ProcessEnv | undefined {\n\tif (!engine.host && Object.keys(extra).length === 0) return undefined;\n\treturn {\n\t\t...process.env,\n\t\t...extra,\n\t\t...(engine.host ? { DOCKER_HOST: engine.host } : {}),\n\t};\n}\n\n/** How a stack's docker commands run: where it is, where output goes. */\nfunction runOptions(stack: StackRef, extra?: NodeJS.ProcessEnv): RunOptions {\n\tconst env = engineEnv(stack, extra);\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 a command run in a container said, whatever it exited with. */\nexport interface ExecResult {\n\t/** Its exit code — null when the service has no running container. */\n\tcode: number | null;\n\tstdout: string;\n\tstderr: string;\n}\n\n/** The engine a call that is about no stack in particular is made against. */\nexport type DockerEngine = Pick<StackRef, 'host'>;\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 on the stack's engine: the registry digest a\n\t * pulled image has, or the content id of one built and never pushed.\n\t */\n\tdigest(engine: DockerEngine, ref: string): Promise<string | undefined>;\n\t/** Create a network on the engine, unless one by that name is there. */\n\tensureNetwork(engine: DockerEngine, name: string): Promise<void>;\n\t/** Every running container publishing `port` on the engine's host. */\n\tpublishers(engine: DockerEngine, port: number): Promise<PortHolder[]>;\n\t/**\n\t * Run a command in a service's running container, `input` on its stdin —\n\t * how files reach a container on a server, through the engine alone.\n\t */\n\texec(\n\t\tstack: StackRef,\n\t\tservice: string,\n\t\tcommand: readonly string[],\n\t\tinput?: string,\n\t): Promise<ExecResult>;\n\t/**\n\t * A compose project's running container for `service` on the engine, by\n\t * its labels — found without the stack's compose file.\n\t */\n\tcontainer(\n\t\tengine: DockerEngine,\n\t\tproject: string,\n\t\tservice: string,\n\t): Promise<{ id: string; image: string } | undefined>;\n\t/**\n\t * The host port a compose project's running `service` publishes for\n\t * `inside` on the engine, by its labels — found without the stack's\n\t * compose file. Undefined when it is not running or publishes none.\n\t */\n\tpublished(\n\t\tengine: DockerEngine,\n\t\tproject: string,\n\t\tservice: string,\n\t\tinside: number,\n\t): Promise<number | undefined>;\n\t/**\n\t * Run `command` once on the engine, in a new container of `image` on\n\t * `network`, removed when it ends, with `stdin` streamed in. Each of `env`\n\t * is passed by name, never on the command line. Resolves with its exit\n\t * code.\n\t */\n\trunOnce(\n\t\tengine: DockerEngine,\n\t\toptions: {\n\t\t\timage: string;\n\t\t\tnetwork: string;\n\t\t\tcommand: readonly string[];\n\t\t\tenv?: Readonly<Record<string, string>>;\n\t\t\tstdin?: NodeJS.ReadableStream;\n\t\t\toutput?: StackRef['output'];\n\t\t},\n\t): Promise<number>;\n}\n\n/** The network compose puts a project's services on. */\nexport function projectNetwork(project: string): string {\n\treturn `${project}_default`;\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/**\n * The host port a `docker ps` Ports column publishes for `inside`:\n * `127.0.0.1:54321->5432/tcp` is 54321.\n */\nexport function publishedPort(\n\tcolumn: string,\n\tinside: number,\n): number | undefined {\n\tconst match = new RegExp(\n\t\t`(?:[\\\\d.]+|\\\\[[^\\\\]]*\\\\]):(\\\\d+)->${inside}/tcp`,\n\t).exec(column);\n\treturn match ? Number(match[1]) : undefined;\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` itself failed, before it could say anything about a service. */\nexport class DockerUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly engine: string,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask Docker on ${engine} which ports its services publish ` +\n\t\t\t\t`(docker said: ${stderr.trim() || 'nothing'}). Check that ` +\n\t\t\t\t`\\`DOCKER_HOST=${engine} docker ps\\` works from here.`,\n\t\t);\n\t\tthis.name = 'DockerUnreachable';\n\t}\n}\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\toptions: { env?: NodeJS.ProcessEnv; input?: string; timeoutMs?: number } = {},\n): Promise<{ code: number | null; stdout: string; stderr: string }> {\n\tconst { timeoutMs = 60_000 } = options;\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: [options.input === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t\t...(options.env ? { env: options.env } : {}),\n\t\t});\n\t\tif (options.input !== undefined) child.stdin?.end(options.input);\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 env = engineEnv(stack);\n\t\tconst output = await runOutput(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['port', service, String(inside)]),\n\t\t\t{\n\t\t\t\tcwd: stack.cwd,\n\t\t\t\t...(env ? { env } : {}),\n\t\t\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t\t\t},\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 env = engineEnv(stack);\n\t\tconst { code, stdout } = await capture(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['ps', '--format', '{{.Health}}', service]),\n\t\t\tenv ? { env } : {},\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(engine, ref) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { code, stdout } = await capture(\n\t\t\t'docker',\n\t\t\t['image', 'inspect', '--format={{json .RepoDigests}} {{.Id}}', ref],\n\t\t\tenv ? { env } : {},\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(engine, name) {\n\t\tconst env = engineEnv(engine);\n\t\tconst options = env ? { env } : {};\n\t\tconst { code } = await capture(\n\t\t\t'docker',\n\t\t\t['network', 'inspect', name],\n\t\t\toptions,\n\t\t);\n\t\tif (code === 0) return;\n\t\tconst created = await capture(\n\t\t\t'docker',\n\t\t\t['network', 'create', name],\n\t\t\toptions,\n\t\t);\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(engine, port) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { stdout } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--format',\n\t\t\t\t'{{.Names}}\\t{{.Label \"com.docker.compose.project\"}}\\t{{.Label \"com.docker.compose.service\"}}\\t{{.Ports}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\treturn portHolders(stdout, port);\n\t},\n\n\tasync exec(stack, service, command, input) {\n\t\tconst env = engineEnv(stack);\n\t\tconst options = env ? { env } : {};\n\t\t// By its compose labels, so it needs no compose file: `--down` reaches\n\t\t// the shared edge with nothing but its project's name.\n\t\tconst { stdout: ids } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'-q',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${stack.project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t],\n\t\t\toptions,\n\t\t);\n\t\tconst container = ids.trim().split('\\n')[0];\n\t\tif (!container) {\n\t\t\treturn { code: null, stdout: '', stderr: `${service} is not running` };\n\t\t}\n\t\treturn capture(\n\t\t\t'docker',\n\t\t\t['exec', ...(input === undefined ? [] : ['-i']), container, ...command],\n\t\t\t{ ...options, ...(input === undefined ? {} : { input }) },\n\t\t);\n\t},\n\n\tasync container(engine, project, service) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { stdout } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t\t'--format',\n\t\t\t\t'{{.ID}}\\t{{.Image}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\tconst [id, image] = stdout.trim().split('\\n')[0]?.split('\\t') ?? [];\n\t\treturn id && image ? { id, image } : undefined;\n\t},\n\n\tasync published(engine, project, service, inside) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { code, stdout, stderr } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t\t'--format',\n\t\t\t\t'{{.Ports}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\t// Docker not answering is not a service that publishes nothing.\n\t\tif (code !== 0) {\n\t\t\tthrow new DockerUnreachable(engine.host ?? 'this machine', stderr);\n\t\t}\n\t\treturn publishedPort(stdout, inside);\n\t},\n\n\trunOnce(engine, options) {\n\t\treturn dockerExit(\n\t\t\t[\n\t\t\t\t'run',\n\t\t\t\t'--rm',\n\t\t\t\t...(options.stdin ? ['-i'] : []),\n\t\t\t\t'--network',\n\t\t\t\toptions.network,\n\t\t\t\t...Object.keys(options.env ?? {}).flatMap((name) => ['-e', name]),\n\t\t\t\t'--entrypoint',\n\t\t\t\t'',\n\t\t\t\toptions.image,\n\t\t\t\t...options.command,\n\t\t\t],\n\t\t\t{\n\t\t\t\tenv: engineEnv(engine, { ...options.env }) ?? process.env,\n\t\t\t\t...(options.stdin ? { stdin: options.stdin } : {}),\n\t\t\t\t...(options.output ? { output: options.output } : {}),\n\t\t\t},\n\t\t);\n\t},\n};\n\n/** Spawn `docker`, its output where `output` says; resolve with the exit code. */\nfunction dockerExit(\n\targs: readonly string[],\n\toptions: {\n\t\tenv?: NodeJS.ProcessEnv;\n\t\tstdin?: NodeJS.ReadableStream;\n\t\toutput?: StackRef['output'];\n\t} = {},\n): Promise<number> {\n\tconst output = STDIO[options.output ?? 'inherit'];\n\tconst out = Array.isArray(output) ? output : [output, output, output];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn('docker', [...args], {\n\t\t\tstdio: [options.stdin ? 'pipe' : 'ignore', out[1], out[2]] as never,\n\t\t\tenv: options.env ?? process.env,\n\t\t\tshell: false,\n\t\t});\n\t\tif (options.stdin && child.stdin) {\n\t\t\toptions.stdin.on('error', (error) => child.stdin?.destroy(error));\n\t\t\tchild.stdin.on('error', () => {});\n\t\t\toptions.stdin.pipe(child.stdin);\n\t\t}\n\t\tchild.on('error', reject);\n\t\tchild.on('close', (code) => resolve(code ?? 1));\n\t});\n}\n\n/** `docker network create` failed. */\nexport class NetworkCreateFailed extends GkmError {\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 * Where a deployed compose stage runs: its server, reached over SSH.\n *\n * gkm never runs on the server. It runs where the deploy is started — a CI\n * runner, a developer's machine — and drives the server's Docker engine over\n * SSH (`DOCKER_HOST=ssh://user@host`), so the server holds Docker, an SSH\n * login and nothing else: no gkm, no checkout, no cloud credentials.\n *\n * ```ts\n * deploy: { compose: { server: { production: { user: 'deploy' } } } }\n * ```\n *\n * The host is the stage's `GKM_SERVER_IPV4` secret — the address its DNS\n * records already point at — unless `host` names another. The local stage is\n * never given one: it runs on this machine's Docker.\n *\n * What the deploy needs from inside the server — Postgres and MinIO, published\n * on the server's loopback alone — it reaches through an SSH tunnel on the same\n * login, so neither is ever published publicly.\n */\n\nimport { spawn } from 'node:child_process';\nimport { createConnection, createServer } from 'node:net';\nimport { GkmError } from '../errors';\nimport type { ComposeServerConfig } from '../workspace/types.js';\nimport { SERVER_IPV4_KEY } from './dnsConfig';\n\n/** A stage's server, as SSH reaches it. */\nexport interface ComposeServer {\n\tuser: string;\n\thost: string;\n\tport: number;\n}\n\n/** A deployed compose stage with nowhere to run. */\nexport class ComposeServerMissing extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly missing: 'config' | 'host',\n\t) {\n\t\tsuper(\n\t\t\tmissing === 'config'\n\t\t\t\t? `'${stage}' is a deployed stage, and gkm deploys it to its server's ` +\n\t\t\t\t\t\t\"Docker over SSH — it never starts a deployed stage on this machine's \" +\n\t\t\t\t\t\t`Docker. Name the login in gkm.config.ts: deploy: { compose: { server: ` +\n\t\t\t\t\t\t`{ ${stage}: { user: 'deploy' } } } } — the host is the stage's ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} secret (gkm secrets:set ${SERVER_IPV4_KEY} '<ip>' ` +\n\t\t\t\t\t\t`--stage ${stage}), or set host there too.`\n\t\t\t\t: `deploy.compose.server.${stage} names no host, and '${stage}' has no ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} secret to default to. Set it: gkm secrets:set ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} '<ip>' --stage ${stage} — or set ` +\n\t\t\t\t\t\t`deploy.compose.server.${stage}.host.`,\n\t\t);\n\t\tthis.name = 'ComposeServerMissing';\n\t}\n}\n\n/** SSH to the stage's server failed before anything was changed there. */\nexport class ComposeServerUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not reach Docker on ${target} over SSH (ssh said: ${stderr.trim() || 'nothing'}). ` +\n\t\t\t\t`Check that \\`ssh ${target} docker version\\` works from here: the host key in ` +\n\t\t\t\t'~/.ssh/known_hosts, the key in your agent or ~/.ssh/config, and the user in ' +\n\t\t\t\t\"the server's docker group.\",\n\t\t);\n\t\tthis.name = 'ComposeServerUnreachable';\n\t}\n}\n\n/** An SSH tunnel to a port on the server's loopback did not open. */\nexport class ComposeTunnelFailed extends GkmError {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly remotePort: number,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not open an SSH tunnel to 127.0.0.1:${remotePort} on ${target} ` +\n\t\t\t\t`(ssh said: ${stderr.trim() || 'nothing'}). The server's sshd must allow ` +\n\t\t\t\t'TCP forwarding for the deploy user (AllowTcpForwarding yes, the default, ' +\n\t\t\t\t'or local), and its key in ~/.ssh/authorized_keys must too: a key ' +\n\t\t\t\t'installed with `restrict` refuses forwarding unless it also says ' +\n\t\t\t\t'`port-forwarding` (`restrict,port-forwarding ssh-ed25519 …`).',\n\t\t);\n\t\tthis.name = 'ComposeTunnelFailed';\n\t}\n}\n\n/**\n * The stage's server: its login from `deploy.compose.server.<stage>`, its\n * host from there or the stage's `GKM_SERVER_IPV4`. Undefined for the local\n * stage, which runs on this machine.\n *\n * @throws {ComposeServerMissing} for a deployed stage with no login or host\n */\nexport function composeServer(options: {\n\tstage: string;\n\tlocal: boolean;\n\tconfig: Readonly<Record<string, ComposeServerConfig>> | undefined;\n\tcustom: Readonly<Record<string, string>> | undefined;\n}): ComposeServer | undefined {\n\tconst { stage } = options;\n\tif (options.local) return undefined;\n\tconst config = options.config?.[stage];\n\tif (!config) throw new ComposeServerMissing(stage, 'config');\n\tconst host = config.host ?? options.custom?.[SERVER_IPV4_KEY]?.trim();\n\tif (!host) throw new ComposeServerMissing(stage, 'host');\n\treturn { user: config.user, host, port: config.port ?? 22 };\n}\n\n/** `user@host`, as a person types it after `ssh`. */\nexport function sshTarget(server: ComposeServer): string {\n\treturn `${server.user}@${server.host}`;\n}\n\n/** The server's Docker engine, as `DOCKER_HOST` names it. */\nexport function dockerHost(server: ComposeServer): string {\n\tconst host = server.host.includes(':') ? `[${server.host}]` : server.host;\n\treturn `ssh://${server.user}@${host}${server.port === 22 ? '' : `:${server.port}`}`;\n}\n\n/** The arguments every `ssh` gkm runs starts with: no prompt, ever. */\nfunction sshArgs(server: ComposeServer): string[] {\n\treturn [\n\t\t'-o',\n\t\t'BatchMode=yes',\n\t\t'-o',\n\t\t'ConnectTimeout=20',\n\t\t'-p',\n\t\tString(server.port),\n\t\tsshTarget(server),\n\t];\n}\n\n/** A local port forwarded to one on the server's loopback. */\nexport interface Tunnel {\n\t/** The port on this machine's loopback. */\n\tport: number;\n\tclose(): Promise<void>;\n}\n\n/** What the deploy does on a stage's server beyond Docker. */\nexport interface ServerAccess {\n\t/**\n\t * Whether SSH logs in and Docker answers there — read-only: `docker\n\t * version`, nothing else.\n\t */\n\tcheck(server: ComposeServer): Promise<void>;\n\t/** Forward a free local port to `remotePort` on the server's loopback. */\n\ttunnel(server: ComposeServer, remotePort: number): Promise<Tunnel>;\n}\n\nasync function freeLocalPort(): Promise<number> {\n\tconst server = createServer();\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once('error', reject);\n\t\tserver.listen(0, '127.0.0.1', resolve);\n\t});\n\tconst address = server.address();\n\tawait new Promise((resolve) => server.close(resolve));\n\tif (!address || typeof address === 'string') return 0;\n\treturn address.port;\n}\n\nfunction connects(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = createConnection({ host: '127.0.0.1', port });\n\t\tsocket.once('connect', () => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(true);\n\t\t});\n\t\tsocket.once('error', () => resolve(false));\n\t});\n}\n\n/** The real one: the system's `ssh`, with the user's keys and known hosts. */\nexport const sshAccess: ServerAccess = {\n\tcheck(server) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst child = spawn(\n\t\t\t\t'ssh',\n\t\t\t\t[\n\t\t\t\t\t...sshArgs(server),\n\t\t\t\t\t'docker',\n\t\t\t\t\t'version',\n\t\t\t\t\t'--format',\n\t\t\t\t\t'{{.Server.Version}}',\n\t\t\t\t],\n\t\t\t\t{ stdio: ['ignore', 'ignore', 'pipe'] },\n\t\t\t);\n\t\t\tlet stderr = '';\n\t\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\t\tstderr += chunk.toString();\n\t\t\t});\n\t\t\tchild.on('error', (error) =>\n\t\t\t\treject(new ComposeServerUnreachable(sshTarget(server), error.message)),\n\t\t\t);\n\t\t\tchild.on('close', (code) =>\n\t\t\t\tcode === 0\n\t\t\t\t\t? resolve()\n\t\t\t\t\t: reject(new ComposeServerUnreachable(sshTarget(server), stderr)),\n\t\t\t);\n\t\t});\n\t},\n\n\tasync tunnel(server, remotePort) {\n\t\tconst port = await freeLocalPort();\n\t\tconst child = spawn(\n\t\t\t'ssh',\n\t\t\t[\n\t\t\t\t'-N',\n\t\t\t\t'-o',\n\t\t\t\t'ExitOnForwardFailure=yes',\n\t\t\t\t// A connection of its own: through a shared master (ControlMaster\n\t\t\t\t// in ~/.ssh/config) the forward would be the master's, and this\n\t\t\t\t// process — the tunnel's lifetime — would exit at once.\n\t\t\t\t'-o',\n\t\t\t\t'ControlPath=none',\n\t\t\t\t'-L',\n\t\t\t\t`127.0.0.1:${port}:127.0.0.1:${remotePort}`,\n\t\t\t\t...sshArgs(server),\n\t\t\t],\n\t\t\t{ stdio: ['ignore', 'ignore', 'pipe'] },\n\t\t);\n\t\tlet stderr = '';\n\t\tlet exited = false;\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString();\n\t\t});\n\t\tchild.on('exit', () => {\n\t\t\texited = true;\n\t\t});\n\t\tchild.on('error', (error) => {\n\t\t\texited = true;\n\t\t\tstderr += error.message;\n\t\t});\n\t\tconst close = async () => {\n\t\t\tif (exited) return;\n\t\t\tconst gone = new Promise((resolve) => child.once('exit', resolve));\n\t\t\tchild.kill('SIGTERM');\n\t\t\tawait gone;\n\t\t};\n\n\t\t// Open once a connection to it is accepted — ssh only listens once\n\t\t// it has logged in and set the forward up.\n\t\tfor (let attempt = 0; attempt < 150; attempt++) {\n\t\t\tif (exited) break;\n\t\t\tif (await connects(port)) return { port, close };\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200));\n\t\t}\n\t\tawait close();\n\t\tthrow new ComposeTunnelFailed(sshTarget(server), remotePort, stderr);\n\t},\n};\n","/**\n * The stack's own edge, rendered for Caddy: one site block per route.\n *\n * Deployed, each host is the stage's real domain and Caddy gets it a\n * certificate from Let's Encrypt on first request — the same automatic HTTPS\n * it does anywhere, with nothing to configure but the name — or serves the\n * stage's own certificate (`deploy.compose.tls`). Locally the hosts are\n * `*.localhost` and the certificates come from Caddy's own CA, as the `gkm\n * dev` edge does, so a local stack is `https://` like a deployed one.\n *\n * Pure: the routes are data (`routes.ts`), and rendering them is one string.\n */\n\nimport { CLIENT_IP_HEADER } from '@geekmidas/manifest';\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/** Where Caddy reads a stage's own certificate, inside its container. */\nexport const CADDY_TLS_DIR = '/etc/caddy/tls';\n\nexport interface CaddyfileOptions {\n\ttls: EdgeTls;\n\t/** Where ACME sends expiry notices, when someone wants them. */\n\temail?: string;\n}\n\n/** An upstream on the stack's own network: its service name. */\nfunction address({ service, port }: Upstream): string {\n\treturn `${service}:${port}`;\n}\n\n/** The Caddyfile for a stack's edge. */\nexport function edgeCaddyfile(\n\troutes: readonly EdgeRoute[],\n\toptions: CaddyfileOptions,\n): string {\n\tconst { tls } = options;\n\tconst global =\n\t\ttls.kind === 'internal'\n\t\t\t? `{\n\t# No ACME and no public DNS: the CA is Caddy's own and the names resolve\n\t# to this machine.\n\tlocal_certs\n\tauto_https disable_redirects\n}`\n\t\t\t: options.email\n\t\t\t\t? `{\n\temail ${options.email}\n}`\n\t\t\t\t: '';\n\n\tconst certificate =\n\t\ttls.kind === 'internal'\n\t\t\t? `\n\ttls internal\n`\n\t\t\t: tls.kind === 'files'\n\t\t\t\t? `\n\ttls ${tls.certFile} ${tls.keyFile}\n`\n\t\t\t\t: '';\n\n\tconst blocks = routes.map(\n\t\t({\n\t\t\thost,\n\t\t\tupstreams,\n\t\t\tprefix,\n\t\t\tallow,\n\t\t\tstreaming,\n\t\t}) => `https://${host} {${certificate}\n\t# gkm's own header, which only a service of this stack may send: the auth\n\t# server rate-limits by the client address it carries.\n\trequest_header -${CLIENT_IP_HEADER}\n${\n\tallow\n\t\t? `\n\t# Only these addresses — the peer Caddy sees, never a header a client\n\t# could set. Everything else is refused before it reaches the upstream.\n\t@denied not remote_ip ${allow.join(' ')}\n\trespond @denied 403\n`\n\t\t: ''\n}${\n\tprefix\n\t\t? `\n\t# A bucket, served at a host of its own: the bucket is a prefix on MinIO,\n\t# which routes and signs on the Host header — so it is sent the upstream's.\n\treverse_proxy ${upstreams.map(address).join(' ')} {\n\t\trewrite ${prefix}{uri}\n\t\theader_up Host {upstream_hostport}\n\t}`\n\t\t: `\n\t# Host and X-Forwarded-* are passed through as Caddy does by default, so\n\t# an app builds redirects, cookies and links on the address a caller used.\n\treverse_proxy ${upstreams.map(address).join(' ')}${\n\t\tstreaming\n\t\t\t? ` {\n\t\t# Never buffer: a streamed response — server-sent events, a Next.js\n\t\t# RSC payload — reaches the client as each chunk is written.\n\t\tflush_interval -1\n\t}`\n\t\t\t: ''\n\t}`\n}\n}`,\n\t);\n\n\t// No blank line under the header: `caddy fmt` wants the first block there.\n\treturn `${HEADER}${global ? `${global}\\n\\n` : ''}${blocks.join('\\n\\n')}\\n`;\n}\n\nconst HEADER = `# Generated by gkm compose from the construct manifest — do not edit.\n#\n# One host per API and site, each in front of its own container, one per\n# file server in front of the stack's MinIO, and — when its logs are served\n# publicly — one for OpenObserve, to the addresses it allows.\n`;\n","/**\n * Which image each app runs — and, for a tag, whether every one exists.\n *\n * A tag is a release's identity: `--tag=v1.4.0` means the images CI pushed as\n * v1.4.0, and nothing else. So a stack is never half rolled out: every app's\n * image is asked of the registry before anything is pulled or the running\n * stack is touched, and one missing image stops the whole run naming every\n * one that is missing. Nor is a missing image quietly built instead — a build\n * of whatever is checked out here is not the release the tag names.\n */\n\nimport { GkmError } from '../errors';\nimport type { ComposeDocker } from './docker';\n\n/** One app's image, as the stack runs it. */\nexport interface AppImage {\n\tapp: string;\n\tref: string;\n\ttag: string;\n}\n\n/**\n * The tag a site's image carries for a release.\n *\n * A site's public URLs are inlined when it is built, so one bundle serves one\n * stage: `v1.4.0-production` and `v1.4.0-staging` are two images of the same\n * commit. A backend reads its URLs at runtime, so one image serves every stage\n * and its tag is the release's alone.\n */\nexport function siteTag(tag: string, stage: string): string {\n\treturn `${tag}-${stage}`;\n}\n\n/** Images a tag names that the registry does not have. */\nexport class ImageTagNotFound extends GkmError {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly refs: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The registry has no image for ${refs.length === 1 ? 'this app' : `${refs.length} apps`} at '${tag}':\\n` +\n\t\t\t\trefs.map((ref) => ` - ${ref}`).join('\\n') +\n\t\t\t\t`\\nNothing was pulled or started. Push '${tag}' for every app from CI, ` +\n\t\t\t\t`pick a tag that exists, or run without --tag to build from this checkout.`,\n\t\t);\n\t\tthis.name = 'ImageTagNotFound';\n\t}\n}\n\n/** The registry did not answer, or did not let this machine in. */\nexport class RegistryUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask the registry about ${ref}: ${detail || 'no answer'}\\n` +\n\t\t\t\t`Nothing was pulled or started. Check the registry is reachable and ` +\n\t\t\t\t`that this machine is logged in to it (\\`docker login <registry>\\`).`,\n\t\t);\n\t\tthis.name = 'RegistryUnreachable';\n\t}\n}\n\n/**\n * Assert every image exists, before anything else happens.\n *\n * Asked all at once and reported all at once: a release missing two images is\n * one problem with two names, and finding the second only after fixing the\n * first is a slower way to learn the same thing.\n *\n * @throws {RegistryUnreachable} when the registry cannot say\n * @throws {ImageTagNotFound} listing every missing image\n */\nexport async function assertImagesExist(\n\tdocker: Pick<ComposeDocker, 'lookup'>,\n\ttag: string,\n\timages: readonly AppImage[],\n): Promise<void> {\n\tconst lookups = await Promise.all(\n\t\timages.map((image) => docker.lookup(image.ref)),\n\t);\n\n\tconst unreachable = lookups.find((lookup) => lookup.status === 'unreachable');\n\tif (unreachable?.status === 'unreachable') {\n\t\tthrow new RegistryUnreachable(unreachable.ref, unreachable.detail);\n\t}\n\n\tconst missing = lookups\n\t\t.filter((lookup) => lookup.status === 'missing')\n\t\t.map((lookup) => lookup.ref);\n\tif (missing.length > 0) throw new ImageTagNotFound(tag, missing);\n}\n\n/**\n * A push or a pull with no `deploy.registry` to push to or pull from.\n *\n * Without one an image is named `<namespace>/<project>-<app>:<tag>`, which\n * Docker resolves to Docker Hub — so a release would be pushed to, or pulled\n * from, somebody else's account. It is never a fallback.\n */\nexport class RegistryRequired extends GkmError {\n\tconstructor(\n\t\t/** What needed the registry: `--push`, or a pull (`--tag`/`--pull`). */\n\t\treadonly operation: 'push' | 'pull',\n\t\t/** The ref an image would have had: a Docker Hub name. */\n\t\treadonly ref: string,\n\t) {\n\t\tsuper(\n\t\t\t`${operation === 'push' ? 'Pushing' : 'Pulling'} images needs a registry, and gkm.config.ts sets no deploy.registry: ` +\n\t\t\t\t`'${ref}' would be ${operation === 'push' ? 'pushed to' : 'pulled from'} Docker Hub. ` +\n\t\t\t\t`Set deploy.registry (e.g. registry: 'ghcr.io/acme') in gkm.config.ts.` +\n\t\t\t\t(operation === 'pull'\n\t\t\t\t\t? ' To run images built here instead, pass --build.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'RegistryRequired';\n\t}\n}\n\n/**\n * What a push reports, and what a pull can pin to: each app's image as\n * `<ref>@sha256:…` — the tag it was pushed as, and the exact image, whatever\n * that tag is later moved to.\n */\nexport type ImageDigests = Record<string, string>;\n\n/** An image pinned to its digest: `<ref>@sha256:…`. */\nexport function pinnedRef(ref: string, digest: string): string {\n\treturn `${ref.split('@')[0]}@${digest}`;\n}\n\n/** A digests file with no entry for an app the stack runs. */\nexport class ImageDigestMissing extends GkmError {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly apps: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${file} pins no digest for ${apps.join(', ')}. Use the file the ` +\n\t\t\t\t`same release's \\`gkm compose --build --push --digests-file\\` wrote, ` +\n\t\t\t\t`or run without --digests-file to pull by tag.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMissing';\n\t}\n}\n\n/** A digests file entry that is not this app's image. */\nexport class ImageDigestMismatch extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly expected: string,\n\t\treadonly found: string,\n\t) {\n\t\tsuper(\n\t\t\t`The digests file pins '${app}' to ${found}, but this release runs ` +\n\t\t\t\t`${expected}. It was written for another registry, project, stage ` +\n\t\t\t\t`or tag; use the file this stage's push of this tag wrote.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMismatch';\n\t}\n}\n\n/** A digests file that is not a JSON object of app to pinned ref. */\nexport class ImageDigestsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`${file} is not a digests file (${detail}). It should be the JSON ` +\n\t\t\t\t`object \\`gkm compose --build --push --digests-file\\` writes: ` +\n\t\t\t\t`{ \"api\": \"<registry>/<image>:<tag>@sha256:…\" }.`,\n\t\t);\n\t\tthis.name = 'ImageDigestsInvalid';\n\t}\n}\n\n/** Parse a digests file's content, checking its shape. */\nexport function parseDigests(file: string, content: string): ImageDigests {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new ImageDigestsInvalid(\n\t\t\tfile,\n\t\t\terror instanceof Error ? error.message : String(error),\n\t\t);\n\t}\n\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\tthrow new ImageDigestsInvalid(file, 'not a JSON object');\n\t}\n\tfor (const [app, value] of Object.entries(parsed)) {\n\t\tif (typeof value !== 'string' || !/@sha256:[0-9a-f]{64}$/.test(value)) {\n\t\t\tthrow new ImageDigestsInvalid(\n\t\t\t\tfile,\n\t\t\t\t`'${app}' is not an <image>:<tag>@sha256:… ref`,\n\t\t\t);\n\t\t}\n\t}\n\treturn parsed as ImageDigests;\n}\n\n/**\n * Each image pinned to the digest the file names for it.\n *\n * @throws {ImageDigestMissing} naming every app the file has no entry for\n * @throws {ImageDigestMismatch} when an entry is another image or tag\n */\nexport function pinImages<T extends AppImage>(\n\tfile: string,\n\tdigests: ImageDigests,\n\timages: readonly T[],\n): T[] {\n\tconst missing = images\n\t\t.filter((image) => !digests[image.app])\n\t\t.map((image) => image.app);\n\tif (missing.length > 0) throw new ImageDigestMissing(file, missing);\n\n\treturn images.map((image) => {\n\t\tconst pinned = digests[image.app]!;\n\t\tif (pinned.split('@')[0] !== image.ref) {\n\t\t\tthrow new ImageDigestMismatch(image.app, image.ref, pinned);\n\t\t}\n\t\treturn { ...image, ref: pinned };\n\t});\n}\n","/**\n * The server's shared edge, rendered for Traefik: what the edge itself runs\n * with, and what one stack registers with it.\n *\n * One Traefik per server owns 80 and 443, the ACME state and the redirect to\n * HTTPS. It is configured through its file provider alone: each stack writes\n * one file — its routers, services and middlewares, every name prefixed with\n * its compose project — into a directory the edge watches, and removes it\n * when it stops. There is no Docker socket: the edge never learns what runs\n * on the server except from those files.\n *\n * The edge and the stacks meet on one external Docker network. Only a\n * stack's public services join it, each under an alias prefixed with its\n * project (`<project>-api`), because the network is shared: a bare service\n * name there would be answered by every stack's `api`.\n *\n * Pure: the documents are data, and the edge's side effects are `edge.ts`'s.\n */\n\nimport { createHash } from 'node:crypto';\nimport { CLIENT_IP_HEADER } from '@geekmidas/manifest';\nimport { stringify } from 'yaml';\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/**\n * The image, pinned: the edge is every stack's way in, so a new version is a\n * change to this line, not whatever `latest` is on the day a server starts.\n */\nexport const TRAEFIK_IMAGE = 'traefik:v3.7.13';\n\n/** The edge's compose project, one per server. */\nexport const EDGE_PROJECT = 'gkm-edge';\n\n/** The external network the edge and every stack's public services share. */\nexport const EDGE_NETWORK = 'gkm-edge';\n\n/** The edge's compose service. */\nexport const EDGE_SERVICE = 'traefik';\n\n/** Inside the edge's container: what it watches, and where certificates are. */\nexport const EDGE_DYNAMIC_DIR = '/etc/gkm-edge/dynamic';\nexport const EDGE_CERTS_DIR = '/etc/gkm-edge/certs';\n\n/** The certificate resolver every deployed route without its own certificate uses. */\nexport const ACME_RESOLVER = 'letsencrypt';\n\n/** The internal entrypoint the edge's health check asks; never published. */\nconst PING_PORT = 8082;\n\n/** A stack's service, as the edge — and the stack itself — reach it. */\nexport function edgeAlias(project: string, service: string): string {\n\treturn `${project}-${service}`;\n}\n\n/** A stack's certificate, as the edge's container reads it. */\nexport function edgeCertificatePaths(project: string): {\n\tcertFile: string;\n\tkeyFile: string;\n} {\n\treturn {\n\t\tcertFile: `${EDGE_CERTS_DIR}/${project}.crt`,\n\t\tkeyFile: `${EDGE_CERTS_DIR}/${project}.key`,\n\t};\n}\n\n/** The edge's ports on the host. */\nexport interface EdgePorts {\n\thttps: number;\n\thttp: number;\n}\n\n/**\n * The edge's static configuration: the entrypoints, the redirect, ACME, and\n * the directory it watches. No API and no dashboard — nothing about the edge\n * is reachable but the routes stacks register.\n */\nexport function traefikStatic(ports: EdgePorts): Record<string, unknown> {\n\treturn {\n\t\tglobal: { checkNewVersion: false, sendAnonymousUsage: false },\n\t\tentryPoints: {\n\t\t\tweb: {\n\t\t\t\taddress: ':80',\n\t\t\t\thttp: {\n\t\t\t\t\t// Every plain-HTTP request is sent to HTTPS — but an ACME\n\t\t\t\t\t// HTTP-01 challenge, which Traefik answers before the redirect.\n\t\t\t\t\tredirections: {\n\t\t\t\t\t\tentryPoint: {\n\t\t\t\t\t\t\t// The published port when it is not 443, so the redirect\n\t\t\t\t\t\t\t// lands where the edge actually listens.\n\t\t\t\t\t\t\tto: ports.https === 443 ? 'websecure' : `:${ports.https}`,\n\t\t\t\t\t\t\tscheme: 'https',\n\t\t\t\t\t\t\tpermanent: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twebsecure: { address: ':443' },\n\t\t\tping: { address: `:${PING_PORT}` },\n\t\t},\n\t\tping: { entryPoint: 'ping' },\n\t\tproviders: {\n\t\t\tfile: { directory: EDGE_DYNAMIC_DIR, watch: true },\n\t\t},\n\t\tcertificatesResolvers: {\n\t\t\t[ACME_RESOLVER]: {\n\t\t\t\tacme: {\n\t\t\t\t\tstorage: '/acme/acme.json',\n\t\t\t\t\thttpChallenge: { entryPoint: 'web' },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tlog: { level: 'INFO' },\n\t};\n}\n\n/** The edge's compose document. */\nexport function edgeCompose(options: {\n\tports: EdgePorts;\n\t/**\n\t * The static configuration, as written: handed to the container inline\n\t * (`configs.content`), so nothing is read from a path on whichever machine\n\t * runs the deploy — and its hash recreates the edge when it changes.\n\t */\n\tstaticConfig: string;\n\tlogging: { driver: string; options: Record<string, string> };\n}): Record<string, unknown> {\n\tconst { ports } = options;\n\treturn {\n\t\tname: EDGE_PROJECT,\n\t\tservices: {\n\t\t\t[EDGE_SERVICE]: {\n\t\t\t\timage: TRAEFIK_IMAGE,\n\t\t\t\trestart: 'unless-stopped',\n\t\t\t\tports: [`${ports.https}:443`, `${ports.http}:80`],\n\t\t\t\tconfigs: [{ source: 'traefik', target: '/etc/traefik/traefik.yml' }],\n\t\t\t\tvolumes: [\n\t\t\t\t\t// Volumes on the server, written through the engine (`docker\n\t\t\t\t\t// exec`): each stack's routes and certificate, replaced by a\n\t\t\t\t\t// rename the file provider sees whole.\n\t\t\t\t\t`dynamic:${EDGE_DYNAMIC_DIR}`,\n\t\t\t\t\t`certs:${EDGE_CERTS_DIR}`,\n\t\t\t\t\t'acme:/acme',\n\t\t\t\t],\n\t\t\t\t// Static configuration is read at start: a change to it is a\n\t\t\t\t// change to the service, so `up` recreates the edge.\n\t\t\t\tlabels: {\n\t\t\t\t\t'dev.geekmidas.edge.config': createHash('sha256')\n\t\t\t\t\t\t.update(options.staticConfig)\n\t\t\t\t\t\t.digest('hex')\n\t\t\t\t\t\t.slice(0, 16),\n\t\t\t\t},\n\t\t\t\tnetworks: ['edge'],\n\t\t\t\thealthcheck: {\n\t\t\t\t\ttest: ['CMD', 'traefik', 'healthcheck', '--ping'],\n\t\t\t\t\tinterval: '10s',\n\t\t\t\t\ttimeout: '5s',\n\t\t\t\t\tretries: 5,\n\t\t\t\t},\n\t\t\t\tlogging: options.logging,\n\t\t\t},\n\t\t},\n\t\tconfigs: { traefik: { content: options.staticConfig } },\n\t\tvolumes: { acme: {}, dynamic: {}, certs: {} },\n\t\tnetworks: { edge: { name: EDGE_NETWORK, external: true } },\n\t};\n}\n\n/** What a stack registers with the edge — its routes, and its certificate. */\nexport interface TraefikStackOptions {\n\tproject: string;\n\t/** ACME, or the stage's own certificate. Never the local CA: that is Caddy's. */\n\ttls: Exclude<EdgeTls, { kind: 'internal' }>;\n}\n\n/** A stack's dynamic configuration, as an object. */\nexport function traefikDynamic(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): Record<string, unknown> {\n\tconst { project, tls } = options;\n\tconst name = (route: EdgeRoute, suffix?: string) =>\n\t\t`${project}-${route.name}${suffix ? `-${suffix}` : ''}`;\n\tconst url = ({ service, port }: Upstream) =>\n\t\t`http://${edgeAlias(project, service)}:${port}`;\n\n\tconst routers: Record<string, unknown> = {};\n\tconst services: Record<string, unknown> = {};\n\tconst middlewares: Record<string, unknown> = {};\n\n\t// gkm's own header, which only a service of this stack may send — the\n\t// auth server rate-limits by the client address it carries — removed from\n\t// every request that arrives from outside. An empty value is Traefik's\n\t// way of removing a request header.\n\tconst strip = `${project}-strip-gkm-headers`;\n\tif (routes.length > 0) {\n\t\tmiddlewares[strip] = {\n\t\t\theaders: { customRequestHeaders: { [CLIENT_IP_HEADER]: '' } },\n\t\t};\n\t}\n\n\tfor (const route of routes) {\n\t\tconst chain: string[] = [strip];\n\t\tif (route.allow) {\n\t\t\t// The peer Traefik sees — never X-Forwarded-For, which a client\n\t\t\t// could set. Everything else gets 403.\n\t\t\tmiddlewares[name(route, 'allow')] = {\n\t\t\t\tipAllowList: { sourceRange: [...route.allow] },\n\t\t\t};\n\t\t\tchain.push(name(route, 'allow'));\n\t\t}\n\t\tif (route.prefix) {\n\t\t\tmiddlewares[name(route, 'prefix')] = {\n\t\t\t\taddPrefix: { prefix: route.prefix },\n\t\t\t};\n\t\t\tchain.push(name(route, 'prefix'));\n\t\t}\n\n\t\trouters[name(route)] = {\n\t\t\trule: `Host(\\`${route.host}\\`)`,\n\t\t\tentryPoints: ['websecure'],\n\t\t\tservice: name(route),\n\t\t\tmiddlewares: chain,\n\t\t\ttls: tls.kind === 'acme' ? { certResolver: ACME_RESOLVER } : {},\n\t\t};\n\n\t\tservices[name(route)] = {\n\t\t\tloadBalancer: {\n\t\t\t\tservers: route.upstreams.map((upstream) => ({ url: url(upstream) })),\n\t\t\t\t// A bucket is routed and signed on the Host header, so MinIO is\n\t\t\t\t// sent its own; an app is sent the one the caller used, which is\n\t\t\t\t// what it builds redirects, cookies and links on.\n\t\t\t\t...(route.prefix ? { passHostHeader: false } : {}),\n\t\t\t\t...(route.streaming\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t// Never buffer: each chunk of a streamed response is\n\t\t\t\t\t\t\t// flushed to the client as it is written.\n\t\t\t\t\t\t\tresponseForwarding: { flushInterval: '-1ms' },\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\t...(route.health\n\t\t\t\t\t? {\n\t\t\t\t\t\t\thealthCheck: {\n\t\t\t\t\t\t\t\tpath: route.health,\n\t\t\t\t\t\t\t\tinterval: '5s',\n\t\t\t\t\t\t\t\ttimeout: '3s',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\thttp: {\n\t\t\trouters,\n\t\t\tservices,\n\t\t\t...(Object.keys(middlewares).length > 0 ? { middlewares } : {}),\n\t\t},\n\t\t...(tls.kind === 'files'\n\t\t\t? {\n\t\t\t\t\ttls: {\n\t\t\t\t\t\tcertificates: [{ certFile: tls.certFile, keyFile: tls.keyFile }],\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/** A stack's dynamic configuration file, as written to the edge's directory. */\nexport function traefikDynamicFile(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): string {\n\treturn `# Generated by gkm compose for ${options.project} — do not edit.\n# The shared edge (${EDGE_PROJECT}) reads every file in this directory; this\n# one is removed by gkm compose --down.\n${yaml(traefikDynamic(routes, options))}`;\n}\n\n/** The edge's static configuration file. */\nexport function traefikStaticFile(ports: EdgePorts): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n${yaml(traefikStatic(ports))}`;\n}\n\n/** The edge's compose file. */\nexport function edgeComposeFile(\n\toptions: Parameters<typeof edgeCompose>[0],\n): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n#\n# Started by the first stack that runs with proxy: 'traefik', and left\n# running by gkm compose --down. Stop it, once nothing uses it, with:\n#\n# docker compose -p ${EDGE_PROJECT} down\n${yaml(edgeCompose(options))}`;\n}\n\nfunction yaml(value: unknown): string {\n\treturn stringify(value, { lineWidth: 0, aliasDuplicateObjects: false });\n}\n","/**\n * The stack a workspace runs as for one stage — pure.\n *\n * Everything `gkm compose` writes is decided here, as data: the compose file,\n * the Caddyfile, one env file per backend, and the image each app runs. The\n * command around it reads the workspace, asks the registry, writes the files\n * and starts Docker; none of those decide anything, so all of it can be\n * asserted without a daemon.\n *\n * The values come from the same derivations every other target uses. The\n * plan is reconcile's `planFor`, the keys an app reads are `appEnvKeys`, and\n * every URL is `envFor`'s — asked twice, once with each app at its public\n * address and once on the compose network, because a browser and a sibling\n * service reach the same API by different names.\n */\n\nimport { createHash } from 'node:crypto';\nimport { join } from 'node:path';\nimport {\n\ttype ConstructManifest,\n\tprovideKey,\n\tprovisionOrder,\n} from '@geekmidas/manifest';\nimport { stageBackups } from '../backups/config.js';\nimport {\n\tBACKUPS_SERVICE,\n\tbackupsService,\n\ttype StackBackups,\n\tstackBackups,\n} from '../backups/service.js';\nimport { type WorkerUnit, workerUnits } from '../build/workers.js';\nimport {\n\ttype DevServiceUse,\n\tdevServicesUsed,\n\ttype ExternalServices,\n\texternalServices,\n\ttype ServiceDeclaration,\n\tstageServiceDeclarations,\n\tsuppliedOnly,\n} from '../deploy/devServices.js';\nimport { isMainFrontendApp, resolveHost } from '../deploy/domain.js';\nimport { type DeployIdentity, imageRef } from '../deploy/identity.js';\nimport { validateImageRef } from '../docker/imageRef.js';\nimport { appDockerfile, workerDockerfile } from '../docker/index.js';\nimport { composeBuildPaths, type ImageLayout } from '../docker/layout.js';\nimport { TURBO_VERSION, WORKER_PORT } from '../docker/templates.js';\nimport { GkmError } from '../errors';\nimport { stageProviderNotes } from '../providers/notes.js';\nimport { appEnvKeys, networkEnv, workerEnvKeys } from '../reconcile/apps.js';\nimport { hostFor } from '../reconcile/caddyfile.js';\nimport { type ComposeService, composeFor } from '../reconcile/compose.js';\nimport { DEFAULT_IMAGES, portKeys } from '../reconcile/containers.js';\nimport { EMULATOR_ACCESS_KEY_ID } from '../reconcile/emulator.js';\nimport { localRolePassword } from '../reconcile/env.js';\nimport {\n\ttype ContainerCredentials,\n\tLOCAL_RABBITMQ_USER,\n\ttype LocalCredentials,\n\tpostgresSuperuser,\n} from '../reconcile/localCredentials.js';\nimport { type Plan, type PlannedResource, planFor } from '../reconcile/plan.js';\nimport { bucketPolicies } from '../reconcile/provision.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport {\n\totlpTelemetryEnv,\n\ttype ResolvedTelemetry,\n\tresolveStageTelemetry,\n\ttelemetryEnv,\n} from '../telemetry/config.js';\nimport {\n\tisTelemetryKey,\n\tscopeTelemetryEnv,\n\ttelemetryOf,\n\tusesTelemetry,\n} from '../telemetry/edges.js';\nimport { DEFAULT_EVENTS } from '../types.js';\nimport { appKey } from '../workspace/derive.js';\nimport type {\n\tComposeTlsConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../workspace/types.js';\nimport { CADDY_TLS_DIR, edgeCaddyfile } from './caddyfile.js';\nimport { isReservedStageKey } from './dnsConfig.js';\nimport { type AppImage, siteTag } from './images.js';\nimport {\n\tLOGS_SERVICE,\n\tlogsService,\n\ttype StackLogs,\n\tstackLogs,\n} from './logs.js';\nimport { LOGS_PORT } from './logsConfig.js';\nimport { certificateFor, proxyFor } from './proxy.js';\nimport {\n\tREDIS_SERVICE,\n\tredisService,\n\tSTACK_CACHE,\n\ttype StackRedis,\n\tstackRedis,\n} from './redis.js';\nimport type { ComposeProxy, EdgeRoute, EdgeTls } from './routes.js';\nimport { publicBuildValues } from './siteBuild.js';\nimport {\n\tEDGE_NETWORK,\n\tedgeAlias,\n\tedgeCertificatePaths,\n\ttraefikDynamicFile,\n} from './traefik.js';\n\n/** Where a stack's files are written, relative to the workspace root. */\nexport function stackDir(stage: string): string {\n\treturn `.gkm/compose/${stage}`;\n}\n\n/**\n * The compose project a stage's stack runs as.\n *\n * The deploy identity's scope, so two workspaces with one name in different\n * namespaces never share containers or volumes — and the stage, so a\n * machine can run two stages side by side.\n */\nexport function composeProject(identity: DeployIdentity): string {\n\treturn `${identity.scope}-${identity.stage}`;\n}\n\n/** The ports the edge is published on, and the variables that move them. */\nexport const EDGE_PORT_ENV = {\n\thttps: 'GKM_COMPOSE_HTTPS_PORT',\n\thttp: 'GKM_COMPOSE_HTTP_PORT',\n} as const;\n\n/**\n * The variable that moves the local stage's OpenObserve off its loopback\n * port, 5080 — which the local stage takes from nowhere else, since it\n * ignores `deploy.telemetry`. Another stack, or another tool, may hold 5080.\n */\nexport const LOGS_PORT_ENV = 'GKM_COMPOSE_LOGS_PORT';\n\n/**\n * Containers this target does not run.\n *\n * The AWS emulator never applies: a stack is a server target, whose events\n * are pg-boss. Reconcile's Caddy fronts `gkm dev`'s host processes; the stack\n * brings its own edge.\n *\n * MinIO and Mailpit run on the local stage always, and on a deployed stage\n * only where `--allow-dev-services` allowed them and its secrets configure no\n * real bucket or mail server — see `devServices.ts`.\n */\nconst NOT_RUN: Readonly<Record<string, true>> = {\n\tlocalstack: true,\n\tcaddy: true,\n};\n\n/** The kinds a deployed stage takes from its secrets, or a dev service. */\nconst SERVICE_KINDS: Readonly<Record<string, ServiceDeclaration['kind']>> = {\n\temail: 'email',\n\tobjects: 'objects',\n\t'file-server': 'file-server',\n};\n\n/** The region MinIO is addressed with. It has no regions; the SDK wants one. */\nconst MINIO_REGION = 'us-east-1';\n\n/** The S3 client's credentials, read beside a bucket's URL when it has them. */\nconst STORAGE_KEYS = [\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_REGION',\n] as const;\n\n/**\n * Every service's Docker logs, rotated. The json-file driver keeps a\n * container's output in one file that grows until the disk is full — on a\n * small server, in weeks. Three files of 10 MB each per container is enough\n * to see what happened and never fills anything. A project's own override\n * file that sets `logging` wins over it.\n */\nexport const LOG_ROTATION = {\n\tdriver: 'json-file',\n\toptions: { 'max-size': '10m', 'max-file': '3' },\n} as const;\n\n/** Each image's build, where the stack builds rather than pulls. */\nexport interface AppBuild {\n\t/** Where the Dockerfile is written, relative to the workspace root. */\n\tdockerfile: string;\n\t/** A site's public URLs, inlined by its bundler. */\n\targs?: Record<string, string>;\n}\n\n/** One app in the stack. */\nexport interface StackApp extends AppImage {\n\t/** Its compose service name — the app key, `api`. */\n\tname: string;\n\t/** The construct it serves. */\n\tid: string;\n\tkind: 'rest-api' | 'site';\n\t/** Its directory, relative to the workspace root. */\n\tpath: string;\n\tport: number;\n\t/** The host the edge answers it on. */\n\thost: string;\n\t/** `https://<host>` — with the edge's port where it is not 443. */\n\turl: string;\n\tbuild?: AppBuild;\n\t/** A backend's environment, exactly the keys it reads. Absent for a site. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A Worker in the stack: its crons, queue consumers and subscribers in a\n * container of their own. Nothing routes to it and nothing is published —\n * its one route is the health check Docker asks.\n */\nexport interface StackWorker extends AppImage {\n\t/** Its compose service name — `jobs`. */\n\tname: string;\n\t/** The Worker construct. */\n\tid: string;\n\t/** The app whose build writes its entry, which its image is built from. */\n\thost: string;\n\t/** Where its health check answers, inside the container. */\n\tport: number;\n\tbuild?: AppBuild;\n\t/** Exactly the keys the worker's constructs read. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A mobile app, as a stage builds it: nothing in the stack runs it — EAS\n * builds it and the stores ship it — but its build reads the stage's\n * public values, resolved here the way a site's build args are.\n */\nexport interface StackMobileApp {\n\t/** Its app key — `app`. */\n\tname: string;\n\t/** The `MobileApp` construct. */\n\tid: string;\n\t/**\n\t * What its build reads, for this stage: its scheme, its edges' public\n\t * URLs under `EXPO_PUBLIC_`, and every stage secret already named so.\n\t */\n\tvalues: Record<string, string>;\n}\n\n/** A service as the stack's compose file defines it. */\nexport interface StackService {\n\timage: string;\n\tbuild?: {\n\t\tcontext: string;\n\t\tdockerfile: string;\n\t\targs?: Record<string, string>;\n\t};\n\t/** `build` for an image built on the server and never pulled. */\n\tpull_policy?: 'build';\n\trestart?: string;\n\tcommand?: string | string[];\n\tenv_file?: { path: string; format: 'raw' }[];\n\tenvironment?: Record<string, string>;\n\tports?: string[];\n\tvolumes?: string[];\n\t/** Files handed to the container inline — see {@link withCaddyConfigs}. */\n\tconfigs?: { source: string; target: string; mode?: number }[];\n\tlabels?: Record<string, string>;\n\tdepends_on?: Record<string, { condition: 'service_healthy' }>;\n\thealthcheck?: ComposeService['healthcheck'];\n\t/**\n\t * Behind the shared edge, a public service is on the stack's own network\n\t * and the edge's, by an alias unique on both.\n\t */\n\tnetworks?: Record<string, { aliases: string[] }>;\n\tlogging?: {\n\t\tdriver: string;\n\t\toptions: Record<string, string>;\n\t};\n}\n\nexport interface StackFile {\n\tname: string;\n\tservices: Record<string, StackService>;\n\tvolumes: Record<string, Record<string, never>>;\n\t/** The shared edge's network, which the stack joins but never creates. */\n\tnetworks?: Record<string, { name: string; external: true }>;\n\t/** Files the stack's containers are handed, by content. */\n\tconfigs?: Record<string, { content: string }>;\n}\n\n/**\n * The stack with Caddy's files inline: its Caddyfile and, where the stage has\n * one, its own certificate — `configs` with their `content`, which compose\n * copies into the container through the engine's API. Nothing is mounted from\n * a path, so the stack runs the same on a server's engine, over SSH, as on\n * this machine's. Their hash is a label: a changed file is a changed service,\n * which `up` recreates (compose does not, for a config's content alone).\n */\nexport function withCaddyConfigs(\n\tcompose: StackFile,\n\tfiles: { caddyfile: string; tls?: { cert: string; key: string } },\n): StackFile {\n\tconst caddy = compose.services.caddy;\n\tif (!caddy) return compose;\n\tconst configs: Record<string, { content: string }> = {\n\t\tcaddyfile: { content: files.caddyfile },\n\t\t...(files.tls\n\t\t\t? {\n\t\t\t\t\t'tls-cert': { content: files.tls.cert },\n\t\t\t\t\t'tls-key': { content: files.tls.key },\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n\tconst hash = createHash('sha256');\n\tfor (const [name, { content }] of Object.entries(configs)) {\n\t\thash.update(`${name}\\0${content}\\0`);\n\t}\n\treturn {\n\t\t...compose,\n\t\tservices: {\n\t\t\t...compose.services,\n\t\t\tcaddy: {\n\t\t\t\t...caddy,\n\t\t\t\tconfigs: [\n\t\t\t\t\t{ source: 'caddyfile', target: '/etc/caddy/Caddyfile' },\n\t\t\t\t\t...(files.tls\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{ source: 'tls-cert', target: `${CADDY_TLS_DIR}/cert.pem` },\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tsource: 'tls-key',\n\t\t\t\t\t\t\t\t\ttarget: `${CADDY_TLS_DIR}/key.pem`,\n\t\t\t\t\t\t\t\t\tmode: 0o400,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t\tlabels: {\n\t\t\t\t\t...caddy.labels,\n\t\t\t\t\t'dev.geekmidas.caddy.config': hash.digest('hex').slice(0, 16),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconfigs: { ...compose.configs, ...configs },\n\t};\n}\n\nexport interface ComposeStack {\n\tproject: string;\n\tstage: string;\n\t/** The project's local stage, served with Caddy's internal CA. */\n\tlocal: boolean;\n\tapps: StackApp[];\n\t/** Each Worker with background work, in a container of its own. */\n\tworkers: StackWorker[];\n\t/** Each mobile app, and what its build reads for this stage. */\n\tmobileApps: StackMobileApp[];\n\t/** The infrastructure containers, by compose service name. */\n\tinfra: string[];\n\tcompose: StackFile;\n\t/**\n\t * What serves the stack: its own Caddy, or the server's shared Traefik\n\t * edge (`deploy.compose.proxy`). The local stage is always Caddy.\n\t */\n\tproxy: ComposeProxy;\n\t/** Every public host and what answers it — what either proxy renders. */\n\troutes: EdgeRoute[];\n\t/** The stack's own Caddy's configuration — with `proxy: 'caddy'`. */\n\tcaddyfile?: string;\n\t/**\n\t * What the stack registers with the shared edge — with `proxy:\n\t * 'traefik'`: the dynamic configuration file written to its directory.\n\t */\n\ttraefik?: string;\n\t/**\n\t * The stage's own certificate and key, on this machine\n\t * (`deploy.compose.tls`) — copied to where the proxy reads it.\n\t */\n\ttls?: ComposeTlsConfig;\n\t/** Generated Dockerfiles, by path relative to the workspace root. */\n\tdockerfiles: Record<string, string>;\n\t/** The plan the stack was derived from — what provisioning creates. */\n\tplan: Plan;\n\t/** The containers' logins, and the seed role passwords take. */\n\tcredential: StackCredential;\n\t/**\n\t * The stack's MinIO, where it runs one: its root credential — what the\n\t * backends sign with — and the buckets and open paths provisioning\n\t * creates in it.\n\t */\n\tstorage?: StackStorage;\n\t/** The dev services a deployed stage runs (`--allow-dev-services`). */\n\tdevServices: DevServiceUse[];\n\t/**\n\t * The stack's OpenObserve, when the stage's telemetry is self-hosted —\n\t * every process with a `Telemetry` edge sends its logs and traces to it.\n\t */\n\tlogs?: StackLogs;\n\t/** Where the stage's telemetry goes, when any process uses it. */\n\ttelemetry?: ResolvedTelemetry;\n\t/**\n\t * The stack's Redis, where a declared cache lives in it — every cache\n\t * whose URL the stage's secrets do not set.\n\t */\n\tredis?: StackRedis;\n\t/**\n\t * The stage's backups, where it is deployed, runs Postgres and has not\n\t * set `deploy.backups.<stage>: false`.\n\t */\n\tbackups?: StackBackups;\n}\n\n/** What a stack's containers run with, and what its role passwords take. */\nexport interface StackCredential {\n\tcontainers: ContainerCredentials;\n\tseed: string;\n}\n\n/** The local stage's stack, without the logins `gkm dev` generates. */\nexport class LocalCredentialsMissing extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The local stage '${stage}' runs with this machine's generated logins, and none were passed. Load them with loadLocalCredentials(workspace) and pass them as localCredentials.`,\n\t\t);\n\t\tthis.name = 'LocalCredentialsMissing';\n\t}\n}\n\n/**\n * A deployed stage's container logins, derived from its seed like its role\n * passwords — so every deploy of the stage computes the same ones, and no one\n * reading the repo can.\n */\nexport function derivedCredentials(\n\tproject: string,\n\tplan: Plan,\n\tseed: string,\n): ContainerCredentials {\n\tconst derive = (purpose: string) =>\n\t\tlocalRolePassword(project, plan, purpose, seed);\n\treturn {\n\t\tpostgres: { user: postgresSuperuser(project), password: derive('master') },\n\t\tminio: { user: `${project}-minio`, password: derive('minio') },\n\t\trabbitmq: { user: LOCAL_RABBITMQ_USER, password: derive('rabbitmq') },\n\t\tredis: { password: derive('redis') },\n\t\tcacheToken: derive('cache-token'),\n\t\temulator: {\n\t\t\taccessKeyId: EMULATOR_ACCESS_KEY_ID,\n\t\t\tsecretAccessKey: derive('emulator'),\n\t\t},\n\t\t// Never read: a deployed stage's OpenObserve signs in with the root\n\t\t// login its secrets hold (`stackLogs`), and the stack hands each process\n\t\t// its telemetry keys from that, not from the derivation.\n\t\tlogs: { email: `admin@${project}`, password: derive('logs') },\n\t};\n}\n\n/** The stack's MinIO, and what is created in it. */\nexport interface StackStorage {\n\tuser: string;\n\tpassword: string;\n\t/** Each bucket's stage-scoped name. */\n\tbuckets: string[];\n\t/** The open paths of each served bucket. */\n\tpolicies: { bucket: string; open: string[] }[];\n}\n\nexport interface StackInput {\n\tworkspace: NormalizedWorkspace;\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/**\n\t * Each Worker's crons', queues' and subscribers' files, from discovery —\n\t * which workers run, and which app each is built from.\n\t */\n\tbackground?: Readonly<Record<string, readonly string[]>>;\n\tstage: string;\n\tidentity: DeployIdentity;\n\timages: {\n\t\tmode: 'build' | 'pull';\n\t\t/** A release tag, or — building — the commit. */\n\t\ttag: string;\n\t\tregistry?: string;\n\t};\n\t/** The stage's secrets — set by hand, and what a deployed stage generated. */\n\tsecrets?: StageSecrets | null;\n\t/**\n\t * This machine's generated local logins — required for the local stage,\n\t * which runs with the same ones `gkm dev` does. See `localCredentials.ts`.\n\t */\n\tlocalCredentials?: LocalCredentials;\n\t/**\n\t * `--allow-dev-services`: a deployed stage runs the dev service for every\n\t * bucket and mail it does not account for. The local stage runs both\n\t * regardless.\n\t */\n\tallowDevServices?: boolean;\n\t/** The edge's published ports. 443 and 80 by default. */\n\tports?: {\n\t\thttps?: number;\n\t\thttp?: number;\n\t\t/** The local stage's OpenObserve port — see {@link LOGS_PORT_ENV}. */\n\t\tlogs?: number;\n\t};\n\t/**\n\t * The stack only builds its images, to push them (`--build --push`): no\n\t * backend's or worker's runtime environment is resolved and no service\n\t * reads an env file, so building needs none of the stage's backend\n\t * secrets. A site's build args — its public URLs — are still resolved.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * For builds: where the images are built from and with what — the build\n\t * root, its package manager and turbo. The workspace's root, with pnpm,\n\t * when not given.\n\t */\n\tlayout?: ImageLayout;\n}\n\n/** A value only the stage's secrets can hold, and they do not. */\nexport class StageSecretMissing extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${app}' reads ${key}, and the stage '${stage}' has none. Nothing in ` +\n\t\t\t\t`the stack can derive it; set it in the stage's secrets: ` +\n\t\t\t\t`gkm secrets:set ${key} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'StageSecretMissing';\n\t}\n}\n\n/** A deployed stage's secrets with no seed to derive its passwords from. */\nexport class StageSeedMissing extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' has no seed in its secrets, and a deployed stage's ` +\n\t\t\t\t`database passwords are derived from it. Run gkm compose --stage ${stage} ` +\n\t\t\t\t`without --dry-run once, or gkm deploy, to generate it.`,\n\t\t);\n\t\tthis.name = 'StageSeedMissing';\n\t}\n}\n\n/** A workspace with no API and no site to run. */\nexport class NothingToCompose extends GkmError {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`${root} declares no RestApi, no site and no Worker with work to do, ` +\n\t\t\t\t`so a stack would run nothing. Mobile apps ship through their own ` +\n\t\t\t\t`toolchain.`,\n\t\t);\n\t\tthis.name = 'NothingToCompose';\n\t}\n}\n\n/** A value that cannot be written to an env file a line at a time. */\nexport class EnvValueMultiline extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t) {\n\t\tsuper(\n\t\t\t`${key} for '${app}' spans more than one line, and an env file holds ` +\n\t\t\t\t`one value per line. Store it on one line — base64, or JSON — and ` +\n\t\t\t\t`decode it where it is read.`,\n\t\t);\n\t\tthis.name = 'EnvValueMultiline';\n\t}\n}\n\n/** The services a stack's apps wait on and the edge waits on in turn. */\nconst HEALTHY = { condition: 'service_healthy' } as const;\n\n/**\n * An app's health check: its own server, asked on 127.0.0.1 — not\n * `localhost`, which resolves to `::1` first in an Alpine container while a\n * server may listen on IPv4 alone.\n */\nfunction probe(port: number, path: string): StackService['healthcheck'] {\n\treturn {\n\t\ttest: [\n\t\t\t'CMD',\n\t\t\t'wget',\n\t\t\t'-q',\n\t\t\t'-O',\n\t\t\t'/dev/null',\n\t\t\t`http://127.0.0.1:${port}${path}`,\n\t\t],\n\t\tinterval: '5s',\n\t\ttimeout: '3s',\n\t\tretries: 20,\n\t\tstart_period: '10s',\n\t};\n}\n\n/**\n * What a stage's stack provisions: reconcile's plan, with a server target's\n * backends whatever `deploy.default` says — the stack is one machine running\n * containers, so events are pg-boss beside the declared database, and every\n * cache, one declared from that database included, is in the stack's own\n * Redis.\n */\nexport function stackPlan(\n\tworkspace: Pick<NormalizedWorkspace, 'stages'>,\n\tmanifest: ConstructManifest,\n\tstage: string,\n): Plan {\n\treturn planFor(manifest, stage, provisionOrder(manifest), {\n\t\tlocalStage: workspace.stages.local,\n\t\tevents: DEFAULT_EVENTS.server,\n\t\tcache: STACK_CACHE,\n\t\t// The stack brings its own edge; reconcile's would front the host.\n\t\tedge: false,\n\t});\n}\n\n/** The stack for one stage. */\nexport function composeStack(input: StackInput): ComposeStack {\n\tconst { workspace, manifest, stage, identity } = input;\n\tconst local = stage === workspace.stages.local;\n\tconst project = composeProject(identity);\n\tconst custom = input.secrets?.custom ?? {};\n\tconst https = input.ports?.https ?? 443;\n\tconst http = input.ports?.http ?? 80;\n\tconst proxy = proxyFor(workspace.deploy?.compose, stage, local);\n\tconst certificate = local\n\t\t? undefined\n\t\t: certificateFor(workspace.deploy?.compose, stage, workspace.root);\n\n\t// A server target's backends, whatever `deploy.default` says: the stack is\n\t// one machine running containers, so events are pg-boss beside the\n\t// declared database — and every cache, one declared from that database\n\t// included, is in the stack's own Redis.\n\tconst plan = stackPlan(workspace, manifest, stage);\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\n\t// The local stage's logins are the ones `gkm dev` generated for this\n\t// machine, so the two run their containers with the same; a deployed\n\t// stage's are derived from its seed.\n\tif (local && !input.localCredentials) {\n\t\tthrow new LocalCredentialsMissing(stage);\n\t}\n\tconst seed = local ? input.localCredentials!.seed : input.secrets?.seed;\n\tif (!seed) throw new StageSeedMissing(stage);\n\tconst containers: ContainerCredentials = local\n\t\t? input.localCredentials!\n\t\t: derivedCredentials(workspace.name, plan, seed);\n\tconst credential: StackCredential = {\n\t\tcontainers: {\n\t\t\t...containers,\n\t\t\t// The stage's own key pair, where it set one, is what MinIO runs as.\n\t\t\tminio: {\n\t\t\t\tuser: custom.AWS_ACCESS_KEY_ID ?? containers.minio.user,\n\t\t\t\tpassword: custom.AWS_SECRET_ACCESS_KEY ?? containers.minio.password,\n\t\t\t},\n\t\t},\n\t\tseed,\n\t};\n\n\tconst apps = stackApps(workspace, manifest, plan, {\n\t\tlocal,\n\t\tstage,\n\t\thttps,\n\t\tidentity,\n\t\timages: input.images,\n\t});\n\tconst workers = stackWorkers(\n\t\tworkerUnits(workspace, manifest, input.background ?? {}),\n\t\t{ stage, identity, images: input.images },\n\t);\n\tif (apps.length === 0 && workers.length === 0) {\n\t\tthrow new NothingToCompose(workspace.root);\n\t}\n\n\t// Which construct each key belongs to, so a key is resolved by what it is\n\t// rather than by its spelling.\n\tconst owners = new Map<string, PlannedResource>();\n\tfor (const resource of plan.resources) {\n\t\towners.set(resource.envKey, resource);\n\t\tif (resource.kind === 'email') {\n\t\t\towners.set(provideKey(resource.id, 'from'), resource);\n\t\t\towners.set(provideKey(resource.id, 'inboxUrl'), resource);\n\t\t}\n\t\tif (resource.kind === 'external-api') {\n\t\t\towners.set(provideKey(resource.id, 'credentials'), resource);\n\t\t}\n\t}\n\n\tconst domain = workspace.domains?.[stage];\n\n\t// Where the stage's telemetry goes, when a process uses a `Telemetry`\n\t// node: the local stage always to OpenObserve, a deployed one where\n\t// `deploy.telemetry` says — and OpenObserve when it says nothing.\n\tconst telemetry = resolveStageTelemetry({\n\t\t...(workspace.deploy?.telemetry\n\t\t\t? { telemetry: workspace.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal,\n\t\ttarget: 'compose',\n\t\truntime: 'server',\n\t\tselfHosted: true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\n\t// The log UI, when the stage's telemetry is self-hosted: its root login,\n\t// how it is reached, and what each process with the edge is handed to send\n\t// to it.\n\tconst logsBase =\n\t\ttelemetry?.provider === 'self-hosted'\n\t\t\t? stackLogs({\n\t\t\t\t\tconfig:\n\t\t\t\t\t\tlocal && input.ports?.logs\n\t\t\t\t\t\t\t? { ...telemetry.selfHosted, port: input.ports.logs }\n\t\t\t\t\t\t\t: telemetry.selfHosted,\n\t\t\t\t\tstage,\n\t\t\t\t\tlocal,\n\t\t\t\t\tproject: workspace.name,\n\t\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\t\tcustom,\n\t\t\t\t\thttps,\n\t\t\t\t\t...(local ? { localLogin: input.localCredentials!.logs } : {}),\n\t\t\t\t})\n\t\t\t: undefined;\n\n\t// Mail and storage: the local stage runs Mailpit and MinIO for all of it.\n\t// A deployed stage takes each from its secrets — or, where allowed, from a\n\t// dev service. Only decided here: whether the stage lacks a key is the\n\t// deploy's readiness check's to say, once, and a build asks no such thing.\n\tconst services: ExternalServices = local\n\t\t? {\n\t\t\t\tmissing: [],\n\t\t\t\tminio: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'objects')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t\tmailpit: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'email')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t}\n\t\t: externalServices({\n\t\t\t\tstage,\n\t\t\t\tdeclarations: stageServiceDeclarations({\n\t\t\t\t\tmanifest,\n\t\t\t\t\t...(input.runnables ? { runnables: input.runnables } : {}),\n\t\t\t\t}),\n\t\t\t\tsupplied: custom,\n\t\t\t\tallow: input.allowDevServices === true,\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\tproviders: stageProviderNotes(workspace, stage),\n\t\t\t});\n\n\t// The caches: in the stack's Redis, unless the stage set a cache's URL —\n\t// a managed Redis — and with every one set, there is no Redis to run.\n\tconst redis = stackRedis({\n\t\tplan,\n\t\tstage,\n\t\tlocal,\n\t\tcustom,\n\t\t...(local ? { localPassword: input.localCredentials!.redis.password } : {}),\n\t});\n\n\tconst infra = [\n\t\t...plan.containers\n\t\t\t.filter((c) => !NOT_RUN[c])\n\t\t\t// Run as the stack's own, below, with the stage's login.\n\t\t\t.filter((c) => c !== LOGS_SERVICE)\n\t\t\t.filter((c) => c !== 'minio' || services.minio.length > 0)\n\t\t\t.filter((c) => c !== 'mailpit' || services.mailpit.length > 0)\n\t\t\t.filter((c) => c !== REDIS_SERVICE || redis !== undefined),\n\t\t...(logsBase ? [LOGS_SERVICE] : []),\n\t].sort();\n\n\t// The stack's MinIO signs with the stage's own key pair where it set one,\n\t// and otherwise with the stage's login: the local one `gkm dev` generated,\n\t// or — deployed — one derived from the stage's seed.\n\tconst storage: StackStorage | undefined = infra.includes('minio')\n\t\t? (() => {\n\t\t\t\tconst buckets = services.minio\n\t\t\t\t\t.map((id) => byId.get(id)?.name)\n\t\t\t\t\t.filter((name): name is string => Boolean(name))\n\t\t\t\t\t.sort();\n\t\t\t\treturn {\n\t\t\t\t\t...credential.containers.minio,\n\t\t\t\t\tbuckets,\n\t\t\t\t\tpolicies: bucketPolicies(plan).filter((p) =>\n\t\t\t\t\t\tbuckets.includes(p.bucket),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t})()\n\t\t: undefined;\n\n\t// Each file server over the stack's MinIO, at a host of its own on the\n\t// edge — the shape it has deployed: a domain serving a bucket.\n\tconst fileServers = new Map<string, { url: string; route: EdgeRoute }>();\n\tif (storage) {\n\t\tfor (const resource of plan.resources) {\n\t\t\tif (resource.kind !== 'file-server' || !resource.of) continue;\n\t\t\tif (!services.minio.includes(resource.of)) continue;\n\t\t\tif (custom[resource.envKey] !== undefined) continue;\n\t\t\tconst bucket = byId.get(resource.of);\n\t\t\tif (!bucket) continue;\n\n\t\t\tlet host: string;\n\t\t\tif (local) {\n\t\t\t\thost = hostFor(resource, workspace.name);\n\t\t\t} else {\n\t\t\t\tif (!domain) throw new NoDomainForStage(stage);\n\t\t\t\thost = `${resource.subdomain ?? appKey(resource.id)}.${domain}`;\n\t\t\t}\n\t\t\tfileServers.set(resource.id, {\n\t\t\t\turl: `https://${host}${local && https !== 443 ? `:${https}` : ''}`,\n\t\t\t\troute: {\n\t\t\t\t\tname: `files-${appKey(resource.id)}`,\n\t\t\t\t\thost,\n\t\t\t\t\tupstreams: [{ service: 'minio', port: 9000 }],\n\t\t\t\t\tstreaming: false,\n\t\t\t\t\tprefix: `/${bucket.name}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// Behind the shared edge, the services it routes to are on a network\n\t// every stack's public services share, where a bare name — `api` — would\n\t// be answered by each stack's. They are reached, from the edge and from\n\t// inside the stack alike, by an alias prefixed with the project.\n\tconst edgeServices = new Set(\n\t\tproxy === 'traefik'\n\t\t\t? [\n\t\t\t\t\t...apps.map((app) => app.name),\n\t\t\t\t\t...(fileServers.size > 0 ? ['minio'] : []),\n\t\t\t\t\t...(logsBase?.host && logsBase.public ? [LOGS_SERVICE] : []),\n\t\t\t\t]\n\t\t\t: [],\n\t);\n\tconst hostOf = (service: string) =>\n\t\tedgeServices.has(service) ? edgeAlias(project, service) : service;\n\tconst logs: StackLogs | undefined = logsBase && {\n\t\t...logsBase,\n\t\tappEnv: {\n\t\t\t...logsBase.appEnv,\n\t\t\tOTEL_EXPORTER_OTLP_ENDPOINT:\n\t\t\t\tlogsBase.appEnv.OTEL_EXPORTER_OTLP_ENDPOINT.replace(\n\t\t\t\t\t`//${LOGS_SERVICE}:`,\n\t\t\t\t\t`//${hostOf(LOGS_SERVICE)}:`,\n\t\t\t\t),\n\t\t},\n\t};\n\n\t// Every key the stage resolves, twice: with each app at its public address\n\t// — what a browser is handed, and what an app says it is — and with each on\n\t// the compose network, which is how one service reaches another.\n\tconst derivation = {\n\t\tproject: workspace.name,\n\t\tcredentials: credential.containers,\n\t\tseed: credential.seed,\n\t\t// Mailpit on a deployed stage sends as the stage's domain.\n\t\t...(!local && domain ? { mailFrom: `noreply@${domain}` } : {}),\n\t};\n\tconst outside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(apps.map((app) => [app.id, app.url])),\n\t\t},\n\t\thostOf,\n\t);\n\tconst inside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(\n\t\t\t\tapps.map((app) => [app.id, `http://${hostOf(app.name)}:${app.port}`]),\n\t\t\t),\n\t\t},\n\t\thostOf,\n\t);\n\n\tconst surfaceUrls = new Map(\n\t\tplan.resources\n\t\t\t.filter((r) => r.kind === 'rest-api' || r.kind === 'site')\n\t\t\t.map((r) => [r.envKey, r.id]),\n\t);\n\tconst appById = new Map(apps.map((app) => [app.id, app]));\n\n\t/**\n\t * What a key resolves to for one app, from the stage's secrets where only\n\t * they can hold it, and the derivations otherwise.\n\t */\n\tconst valueFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkey: string,\n\t\towner: PlannedResource | undefined,\n\t): string | undefined => {\n\t\t// The server's address is gkm's own: never in an app's environment.\n\t\tif (isReservedStageKey(key)) return undefined;\n\t\t// A deployed stage has no inbox: Mailpit runs only locally — not for a\n\t\t// backend, a site's bundle or a phone.\n\t\tif (!local && owner?.kind === 'email' && key.endsWith('_INBOX_URL')) {\n\t\t\treturn undefined;\n\t\t}\n\t\t// Mail and storage: what the stage set — a real server, a real bucket —\n\t\t// and otherwise the dev service it runs, which `services` has already\n\t\t// checked it may.\n\t\tif (owner && SERVICE_KINDS[owner.kind]) {\n\t\t\tif (custom[key] !== undefined) return custom[key];\n\t\t\tif (owner.kind === 'file-server') return fileServers.get(owner.id)?.url;\n\t\t\treturn outside[key];\n\t\t}\n\n\t\t// Supplied by somebody: a third party's credentials, and — deployed —\n\t\t// the secrets the stage generated.\n\t\tif (owner && suppliedOnly(owner.kind, owner.id, key, local)) {\n\t\t\tconst value = custom[key];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new StageSecretMissing(app.name, key, stage);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// Set by hand wins over derived: it is the stage saying what it is.\n\t\tif (custom[key] !== undefined) return custom[key];\n\n\t\t// A cache, in the stack's Redis, by its name on the network.\n\t\tif (owner?.kind === 'cache') return redis?.urls[key];\n\n\t\t// A backend reaches a sibling surface on the compose network; its own\n\t\t// address is the public one, which is what it builds links on. A site\n\t\t// runs in a browser, which has only the public addresses.\n\t\tconst surface = surfaceUrls.get(key);\n\t\tif (app.kind === 'rest-api' && surface && surface !== app.id) {\n\t\t\treturn inside[key];\n\t\t}\n\n\t\treturn outside[key];\n\t};\n\n\t// What the stage resolves for its `Telemetry` node, before a process is\n\t// named: the stack's OpenObserve, or the provider `deploy.telemetry` names.\n\tconst telemetryValues: Record<string, string> | undefined = logs\n\t\t? telemetryEnv(\n\t\t\t\t{\n\t\t\t\t\tendpoint: logs.appEnv.OTEL_EXPORTER_OTLP_ENDPOINT,\n\t\t\t\t\theaders: logs.appEnv.OTEL_EXPORTER_OTLP_HEADERS,\n\t\t\t\t},\n\t\t\t\ttelemetry?.sampleRate ?? 1,\n\t\t\t)\n\t\t: telemetry?.provider === 'otlp'\n\t\t\t? otlpTelemetryEnv(telemetry)\n\t\t\t: undefined;\n\n\t/** Each key one backend process reads, resolved for this stage. */\n\tconst valuesFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkeys: ReadonlySet<string>,\n\t): Record<string, string> => {\n\t\tconst values: Record<string, string> = {};\n\t\tfor (const key of [...keys].sort()) {\n\t\t\t// The node's keys are the stage's telemetry, added per process.\n\t\t\tif (isTelemetryKey(key)) continue;\n\t\t\tconst owner = owners.get(key) ?? storageOwner(key, plan);\n\t\t\tif ((STORAGE_KEYS as readonly string[]).includes(key)) {\n\t\t\t\t// The stage's own key pair where it set one — an external bucket\n\t\t\t\t// signs with it — and otherwise the stack's MinIO's.\n\t\t\t\tconst value = custom[key] ?? storageValue(key, storage);\n\t\t\t\tif (value !== undefined) values[key] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = valueFor(app, key, owner);\n\t\t\tif (value !== undefined) values[key] = value;\n\t\t}\n\t\treturn values;\n\t};\n\n\tfor (const app of apps) {\n\t\tif (app.kind === 'site') {\n\t\t\tconst site = manifest[app.id];\n\t\t\tif (site?.kind !== 'site') continue;\n\n\t\t\tconst args = publicBuildValues(\n\t\t\t\tsite,\n\t\t\t\tmanifest,\n\t\t\t\t(key) => valueFor(app, key, owners.get(key)),\n\t\t\t\tcustom,\n\t\t\t);\n\t\t\tif (app.build && Object.keys(args).length > 0) app.build.args = args;\n\t\t\tcontinue;\n\t\t}\n\t\t// Built to be pushed, a backend's image is every stage's: what it reads\n\t\t// at runtime is the deploy's business, not the build's.\n\t\tif (input.buildOnly) continue;\n\n\t\tconst keys = appEnvKeys(manifest, app.name, input.runnables) ?? new Set();\n\t\tconst values = valuesFor(app, keys);\n\n\t\t// The origins Better Auth trusts are the browser's and, now, each\n\t\t// service that calls this surface across the compose network: its CSRF\n\t\t// check applies to every caller, and a sibling's request carries its\n\t\t// own origin, not a browser's.\n\t\tconst trusted = provideKey(app.id, 'trustedOrigins');\n\t\tif (keys.has(trusted)) {\n\t\t\tconst internal = (byId.get(app.id)?.callers ?? [])\n\t\t\t\t.map((caller) => appById.get(caller))\n\t\t\t\t.filter((caller): caller is StackApp => caller?.kind === 'rest-api')\n\t\t\t\t.map((caller) => `http://${hostOf(caller.name)}:${caller.port}`);\n\t\t\tconst origins = [\n\t\t\t\t...(values[trusted] ?? '').split(',').filter(Boolean),\n\t\t\t\t...internal,\n\t\t\t];\n\t\t\tvalues[trusted] = [...new Set(origins)].join(',');\n\t\t}\n\n\t\t// Telemetry: the stage's, to a process with an edge to the node.\n\t\tapp.env = {\n\t\t\t...scopeTelemetryEnv(values, {\n\t\t\t\tuses: telemetryOf(manifest, app.id) !== undefined,\n\t\t\t\tserviceName: app.name,\n\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t}),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(app.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\n\t\tfor (const [key, value] of Object.entries(app.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(app.name, key);\n\t\t}\n\t}\n\n\t// A mobile app runs on a phone, which has only the public addresses — as\n\t// a browser does — so its values resolve as a site's do.\n\tconst mobileApps: StackMobileApp[] = [];\n\tfor (const declaration of Object.values(manifest)) {\n\t\tif (declaration.kind !== 'mobile-app') continue;\n\t\tconst app = {\n\t\t\tname: appKey(declaration.id),\n\t\t\tid: declaration.id,\n\t\t\tkind: 'site' as const,\n\t\t};\n\t\tmobileApps.push({\n\t\t\tname: app.name,\n\t\t\tid: app.id,\n\t\t\tvalues: publicBuildValues(\n\t\t\t\tdeclaration,\n\t\t\t\tmanifest,\n\t\t\t\t(key) => valueFor(app, key, owners.get(key)),\n\t\t\t\tcustom,\n\t\t\t),\n\t\t});\n\t}\n\n\t// A worker reaches every surface across the compose network: it is never\n\t// one, so no address is its own.\n\tfor (const worker of input.buildOnly ? [] : workers) {\n\t\tconst keys =\n\t\t\tworkerEnvKeys(manifest, worker.id, input.runnables) ?? new Set();\n\t\tworker.env = {\n\t\t\t...scopeTelemetryEnv(\n\t\t\t\tvaluesFor({ name: worker.name, id: worker.id, kind: 'rest-api' }, keys),\n\t\t\t\t{\n\t\t\t\t\tuses: telemetryOf(manifest, worker.id) !== undefined,\n\t\t\t\t\tserviceName: worker.name,\n\t\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t\t},\n\t\t\t),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(worker.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(worker.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(worker.name, key);\n\t\t}\n\t}\n\n\t// A deployed stage's certificates: its own, where it set one, as the\n\t// proxy's container reads them — otherwise Let's Encrypt's.\n\tconst deployedTls: Exclude<EdgeTls, { kind: 'internal' }> = certificate\n\t\t? {\n\t\t\t\tkind: 'files',\n\t\t\t\t...(proxy === 'caddy'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcertFile: `${CADDY_TLS_DIR}/cert.pem`,\n\t\t\t\t\t\t\tkeyFile: `${CADDY_TLS_DIR}/key.pem`,\n\t\t\t\t\t\t}\n\t\t\t\t\t: edgeCertificatePaths(project)),\n\t\t\t}\n\t\t: { kind: 'acme' };\n\tconst tls: EdgeTls = local ? { kind: 'internal' } : deployedTls;\n\n\t// The stage's backups: a deployed stage with Postgres, unless it said\n\t// `false`. A stack that only builds runs nothing, so has none.\n\tconst backupsChoice = input.buildOnly\n\t\t? undefined\n\t\t: stageBackups(workspace, manifest, stage);\n\tconst backups =\n\t\tbackupsChoice?.mode === 'on' && infra.includes('postgres')\n\t\t\t? stackBackups({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tstage,\n\t\t\t\t\tproject,\n\t\t\t\t\tplan,\n\t\t\t\t\tbackups: backupsChoice.backups,\n\t\t\t\t\tcustom,\n\t\t\t\t\tseed,\n\t\t\t\t\tsuperuser: credential.containers.postgres,\n\t\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t\t})\n\t\t\t: undefined;\n\n\tconst layout = input.layout ?? defaultLayout(workspace.root);\n\tconst compose = stackFile({\n\t\tproject,\n\t\tplan,\n\t\tinfra,\n\t\tapps,\n\t\tworkers,\n\t\tcredentials: credential.containers,\n\t\t...(storage ? { storage } : {}),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\t...(backups ? { backups } : {}),\n\t\thttps,\n\t\thttp,\n\t\tcomposeDir: join(workspace.root, stackDir(stage)),\n\t\tbuildRoot: layout.buildRoot,\n\t\tworkspaceRoot: workspace.root,\n\t\tenvFiles: !input.buildOnly,\n\t\tproxy,\n\t\tedge: new Map(\n\t\t\t[...edgeServices].map((service) => [service, hostOf(service)]),\n\t\t),\n\t});\n\n\t// One route per public host — the data both proxies render.\n\tconst routes: EdgeRoute[] = [\n\t\t...apps.map(\n\t\t\t(app): EdgeRoute => ({\n\t\t\t\tname: app.name,\n\t\t\t\thost: app.host,\n\t\t\t\tupstreams: [{ service: app.name, port: app.port }],\n\t\t\t\tstreaming: true,\n\t\t\t\thealth: app.kind === 'site' ? '/' : '/health',\n\t\t\t}),\n\t\t),\n\t\t...[...fileServers.values()].map(({ route }) => route),\n\t\t...(logs?.host && logs.public\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: LOGS_SERVICE,\n\t\t\t\t\t\thost: logs.host,\n\t\t\t\t\t\tupstreams: [{ service: LOGS_SERVICE, port: LOGS_PORT }],\n\t\t\t\t\t\tstreaming: true,\n\t\t\t\t\t\tallow: logs.public.allow,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\tconst dockerfiles: Record<string, string> = {};\n\tfor (const app of apps) {\n\t\tif (!app.build) continue;\n\t\t// The same Dockerfile `gkm docker` writes: the image is built inside\n\t\t// Docker from a pruned slice of the build root, and nothing is built\n\t\t// here first.\n\t\tdockerfiles[app.build.dockerfile] = appDockerfile(\n\t\t\tapp.name,\n\t\t\tworkspace.apps[app.name]!,\n\t\t\t{\n\t\t\t\tlayout,\n\t\t\t\tworkspaceRoot: workspace.root,\n\t\t\t\tapps: workspace.apps,\n\t\t\t\tmanifest,\n\t\t\t\tcache: STACK_CACHE,\n\t\t\t\t// A site's clients trace at this stage's sample rate.\n\t\t\t\tworkspace,\n\t\t\t\tstage,\n\t\t\t\t// Every build argument the site is handed, declared, or the\n\t\t\t\t// build drops it.\n\t\t\t\t...(app.kind === 'site' && app.build.args\n\t\t\t\t\t? { publicUrlArgs: Object.keys(app.build.args) }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\tif (!worker.build) continue;\n\t\tdockerfiles[worker.build.dockerfile] = workerDockerfile(\n\t\t\t{ id: worker.id, name: worker.name, app: worker.host },\n\t\t\tworkspace.apps[worker.host]!,\n\t\t\t{ layout, workspaceRoot: workspace.root, cache: STACK_CACHE },\n\t\t);\n\t}\n\n\treturn {\n\t\tproject,\n\t\tstage,\n\t\tlocal,\n\t\tapps,\n\t\tworkers,\n\t\tmobileApps,\n\t\tinfra,\n\t\tcompose,\n\t\tproxy,\n\t\troutes,\n\t\t...(proxy === 'caddy'\n\t\t\t? { caddyfile: edgeCaddyfile(routes, { tls }) }\n\t\t\t: {\n\t\t\t\t\ttraefik: traefikDynamicFile(routes, {\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttls: deployedTls,\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t...(certificate ? { tls: certificate } : {}),\n\t\tdockerfiles,\n\t\tplan,\n\t\tcredential,\n\t\t...(storage ? { storage } : {}),\n\t\tdevServices: local ? [] : devServicesUsed(services),\n\t\t...(logs ? { logs } : {}),\n\t\t...(telemetry ? { telemetry } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\t...(backups ? { backups } : {}),\n\t};\n}\n\n/** The stack's MinIO's value for one of the S3 client's keys. */\nfunction storageValue(\n\tkey: string,\n\tstorage: StackStorage | undefined,\n): string | undefined {\n\tif (!storage) return undefined;\n\tif (key === 'AWS_ACCESS_KEY_ID') return storage.user;\n\tif (key === 'AWS_SECRET_ACCESS_KEY') return storage.password;\n\tif (key === 'AWS_REGION') return MINIO_REGION;\n\treturn undefined;\n}\n\n/** Which bucket an S3 credential key belongs to — the first one declared. */\nfunction storageOwner(key: string, plan: Plan): PlannedResource | undefined {\n\tif (!(STORAGE_KEYS as readonly string[]).includes(key)) return undefined;\n\treturn plan.resources.find((r) => r.kind === 'objects');\n}\n\n/** The apps a stack runs: every API and every site, at its stage address. */\nfunction stackApps(\n\tworkspace: NormalizedWorkspace,\n\tmanifest: ConstructManifest,\n\tplan: Plan,\n\toptions: {\n\t\tlocal: boolean;\n\t\tstage: string;\n\t\thttps: number;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackApp[] {\n\tconst apps: StackApp[] = [];\n\tconst resources = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'site')\n\t\t\tcontinue;\n\n\t\tconst name = appKey(id);\n\t\tconst app = workspace.apps[name];\n\t\tconst resource = resources.get(id);\n\t\tif (!app || !resource || !app.port) continue;\n\n\t\tconst host = hostOf(name, app, workspace, resource, options);\n\t\tconst site = declaration.kind === 'site';\n\t\tconst tag = site\n\t\t\t? siteTag(options.images.tag, options.stage)\n\t\t\t: options.images.tag;\n\t\tconst ref = validateImageRef(\n\t\t\timageRef(options.identity, name, options.images.registry, tag),\n\t\t);\n\n\t\tapps.push({\n\t\t\tapp: name,\n\t\t\tname,\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tpath: app.path,\n\t\t\tport: app.port,\n\t\t\thost,\n\t\t\turl: `https://${host}${options.local && options.https !== 443 ? `:${options.https}` : ''}`,\n\t\t\tref,\n\t\t\ttag,\n\t\t\t...(options.images.mode === 'build'\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${name}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\treturn apps.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Each worker's image, and where it is built from. */\nfunction stackWorkers(\n\tunits: readonly WorkerUnit[],\n\toptions: {\n\t\tstage: string;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackWorker[] {\n\treturn units.map((unit) => ({\n\t\tapp: unit.name,\n\t\tname: unit.name,\n\t\tid: unit.id,\n\t\thost: unit.app,\n\t\tport: WORKER_PORT,\n\t\tref: validateImageRef(\n\t\t\timageRef(\n\t\t\t\toptions.identity,\n\t\t\t\tunit.name,\n\t\t\t\toptions.images.registry,\n\t\t\t\toptions.images.tag,\n\t\t\t),\n\t\t),\n\t\ttag: options.images.tag,\n\t\t...(options.images.mode === 'build'\n\t\t\t? {\n\t\t\t\t\tbuild: {\n\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${unit.name}`,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\n/**\n * The host an app answers on for a stage: the `gkm dev` edge's\n * `*.localhost` names for the local stage, and the stage's domain — by the\n * same rule a deploy follows — for any other.\n */\nfunction hostOf(\n\tname: string,\n\tapp: NormalizedAppConfig,\n\tworkspace: NormalizedWorkspace,\n\tresource: PlannedResource,\n\toptions: { local: boolean; stage: string },\n): string {\n\tif (options.local) return hostFor(resource, workspace.name);\n\n\treturn resolveHost(\n\t\tname,\n\t\tapp,\n\t\toptions.stage,\n\t\tworkspace.domains,\n\t\tisMainFrontendApp(name, app, workspace.apps),\n\t);\n}\n\n/** The compose document: the infrastructure, the apps, and the edge. */\nfunction stackFile(options: {\n\tproject: string;\n\tplan: Plan;\n\tinfra: readonly string[];\n\tapps: readonly StackApp[];\n\tworkers: readonly StackWorker[];\n\tcredentials: ContainerCredentials;\n\tstorage?: StackStorage;\n\tlogs?: StackLogs;\n\tredis?: StackRedis;\n\tbackups?: StackBackups;\n\thttps: number;\n\thttp: number;\n\tcomposeDir: string;\n\tbuildRoot: string;\n\tworkspaceRoot: string;\n\t/** Whether services read env files — not in a stack that only builds. */\n\tenvFiles: boolean;\n\tproxy: ComposeProxy;\n\t/** Behind the shared edge: each service it routes to, and its alias. */\n\tedge: ReadonlyMap<string, string>;\n}): StackFile {\n\tconst { project, plan, apps } = options;\n\t// What reconcile defines; OpenObserve is the stack's own.\n\tconst infra = options.infra.filter((name) => name !== LOGS_SERVICE);\n\n\t// Reconcile's definitions — images, health checks, volumes — with nothing\n\t// published to the host. Ports are allocation's business there; here the\n\t// edge is the only way in.\n\tconst derived = composeFor(\n\t\t{ ...plan, containers: [...infra] },\n\t\t{\n\t\t\tproject,\n\t\t\tports: Object.fromEntries(\n\t\t\t\tportKeys(infra, plan.fakes).map((key) => [key, 0]),\n\t\t\t),\n\t\t\tcredentials: options.credentials,\n\t\t},\n\t);\n\n\tconst services: Record<string, StackService> = {};\n\tconst volumes: Record<string, Record<string, never>> = {\n\t\t...derived.volumes,\n\t\t...(options.proxy === 'caddy'\n\t\t\t? { 'caddy-data': {}, 'caddy-config': {} }\n\t\t\t: {}),\n\t\t...(options.logs ? { 'openobserve-data': {} } : {}),\n\t};\n\n\tfor (const name of infra) {\n\t\tconst {\n\t\t\tports: _ports,\n\t\t\tdepends_on,\n\t\t\tprofiles: _profiles,\n\t\t\t...service\n\t\t} = derived.services[name]!;\n\t\tservices[name] = {\n\t\t\t...service,\n\t\t\t...(depends_on?.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tdepends_on.map((dep) => [dep, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tconst postgres = services.postgres;\n\tif (postgres) {\n\t\t// Loopback only, on a port Docker picks: gkm creates the databases and\n\t\t// roles and runs the migrations from this machine, and nothing else\n\t\t// should reach the database from outside the stack.\n\t\tpostgres.ports = ['127.0.0.1::5432'];\n\t}\n\n\tconst minio = services.minio;\n\tif (minio && options.storage) {\n\t\tminio.environment = {\n\t\t\t...minio.environment,\n\t\t\tMINIO_ROOT_USER: options.storage.user,\n\t\t\tMINIO_ROOT_PASSWORD: options.storage.password,\n\t\t};\n\t\t// Loopback only, like Postgres: gkm creates the buckets and their\n\t\t// policies from this machine. The apps reach it on the network, and a\n\t\t// browser through a file server's host on the edge.\n\t\tminio.ports = ['127.0.0.1::9000'];\n\t}\n\n\t// Its own definition rather than reconcile's: `gkm dev`'s Redis is an\n\t// open, unbounded scratch store; this one is a production cache.\n\tif (services[REDIS_SERVICE] && options.redis) {\n\t\tservices[REDIS_SERVICE] = redisService(options.redis);\n\t}\n\n\t// Started with the infrastructure, but nothing waits on it: an app whose\n\t// telemetry cannot be delivered still serves.\n\tif (options.logs) services[LOGS_SERVICE] = logsService(options.logs);\n\n\t// The stage's backups: on the stack's network, from nothing on the host.\n\tif (options.backups) {\n\t\tservices[BACKUPS_SERVICE] = backupsService(\n\t\t\toptions.backups,\n\t\t\toptions.envFiles,\n\t\t);\n\t}\n\n\tfor (const app of apps) {\n\t\tservices[app.name] = {\n\t\t\timage: app.ref,\n\t\t\t...(app.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\t...composeBuildPaths({\n\t\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\t\tdockerfile: app.build.dockerfile,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(app.build.args ? { args: app.build.args } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\t// A site is a bundle and reads nothing at runtime; a backend reads\n\t\t\t// exactly the keys in its own file.\n\t\t\t...(app.kind === 'rest-api'\n\t\t\t\t? {\n\t\t\t\t\t\tenv_file: [{ path: `./${app.name}.env`, format: 'raw' as const }],\n\t\t\t\t\t\t...(infra.length\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(app.port, app.kind === 'site' ? '/' : '/health'),\n\t\t};\n\t}\n\n\t// A worker: no route, no published port — its health check is Docker's.\n\tfor (const worker of options.workers) {\n\t\tservices[worker.name] = {\n\t\t\timage: worker.ref,\n\t\t\t...(worker.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: composeBuildPaths({\n\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\tdockerfile: worker.build.dockerfile,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\tenv_file: [{ path: `./${worker.name}.env`, format: 'raw' as const }],\n\t\t\t...(infra.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(worker.port, '/health'),\n\t\t};\n\t}\n\n\tif (options.proxy === 'caddy') {\n\t\tservices.caddy = {\n\t\t\timage: DEFAULT_IMAGES.caddy!,\n\t\t\trestart: 'unless-stopped',\n\t\t\tports: [`${options.https}:443`, `${options.http}:80`],\n\t\t\t// The Caddyfile and the stage's own certificate are inline configs,\n\t\t\t// added as the file is written (`withCaddyConfigs`).\n\t\t\tvolumes: ['caddy-data:/data', 'caddy-config:/config'],\n\t\t\tdepends_on: Object.fromEntries(apps.map((app) => [app.name, HEALTHY])),\n\t\t\thealthcheck: {\n\t\t\t\ttest: ['CMD', 'caddy', 'version'],\n\t\t\t\tinterval: '10s',\n\t\t\t\ttimeout: '5s',\n\t\t\t\tretries: 5,\n\t\t\t},\n\t\t};\n\t}\n\n\t// Behind the shared edge: each service it routes to joins its network,\n\t// under the alias the edge reaches it by — and keeps the stack's own,\n\t// with the same alias, which is how the stack's services reach it too.\n\t// Everything else — the databases, Redis, the workers — stays off it.\n\tfor (const [service, alias] of options.edge) {\n\t\tconst definition = services[service];\n\t\tif (!definition) continue;\n\t\tdefinition.networks = {\n\t\t\tdefault: { aliases: [alias] },\n\t\t\tedge: { aliases: [alias] },\n\t\t};\n\t}\n\n\tfor (const service of Object.values(services)) {\n\t\tif (!options.envFiles) delete service.env_file;\n\t\tservice.logging = {\n\t\t\tdriver: LOG_ROTATION.driver,\n\t\t\toptions: { ...LOG_ROTATION.options },\n\t\t};\n\t}\n\n\treturn {\n\t\tname: project,\n\t\tservices,\n\t\tvolumes,\n\t\t...(options.edge.size > 0\n\t\t\t? { networks: { edge: { name: EDGE_NETWORK, external: true as const } } }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * A build without a layout: the workspace is the build root, with pnpm.\n * What a caller that never looked at the filesystem gets.\n */\nfunction defaultLayout(root: string): ImageLayout {\n\treturn {\n\t\tbuildRoot: root,\n\t\tgkmRoot: '.',\n\t\ttools: {\n\t\t\tpackageManager: 'pnpm',\n\t\t\tturboVersion: TURBO_VERSION,\n\t\t\tmonorepo: true,\n\t\t},\n\t\tgkmPaths: ['gkm.config.*'],\n\t};\n}\n\n/** Render an app's env file: one `KEY=value` per line, read raw by compose. */\nexport function envFile(env: Readonly<Record<string, string>>): string {\n\treturn `${Object.entries(env)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join('\\n')}\\n`;\n}\n","/**\n * The server's shared Traefik edge, in Docker: started when a stack needs it,\n * and each stack's routes written to — and removed from — the directory it\n * watches.\n *\n * Everything goes through the server's Docker engine, never its filesystem:\n * the edge's static configuration is handed to it inline, and the directories\n * it watches are volumes each stack writes into with `docker exec`. So the\n * deploy runs anywhere that reaches the engine — a CI runner over SSH — and\n * nothing it writes depends on a path on that machine.\n *\n * gkm-edge (compose project)\n * traefik.yml its static configuration (inline config)\n * dynamic/<project>.yml one per stack: routers, services, middlewares\n * certs/<project>.crt|.key a stack's own certificate, where it has one\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { GkmError } from '../errors';\nimport type {\n\tComposeDocker,\n\tDockerEngine,\n\tPortHolder,\n\tStackRef,\n} from './docker.js';\nimport type { ComposeProxy } from './routes.js';\nimport {\n\tEDGE_CERTS_DIR,\n\tEDGE_DYNAMIC_DIR,\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 compose project, as docker is asked about it. */\nexport function edgeRef(\n\tfile: string,\n\toptions: Pick<StackRef, 'output' | 'signal' | 'host'> = {},\n): StackRef {\n\treturn {\n\t\tproject: EDGE_PROJECT,\n\t\tfile,\n\t\tcwd: dirname(file),\n\t\t...options,\n\t};\n}\n\n/** Writing to or removing from the edge's volumes failed. */\nexport class EdgeWriteFailed extends GkmError {\n\tconstructor(\n\t\treadonly path: string,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not write ${path} in the shared edge (${EDGE_PROJECT}): ${output.trim() || 'it is not running'}. ` +\n\t\t\t\t`Check it with \\`docker compose -p ${EDGE_PROJECT} ps\\` on the server, and run gkm compose again.`,\n\t\t);\n\t\tthis.name = 'EdgeWriteFailed';\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: {\n\t\tproject: string;\n\t\tproxy: ComposeProxy;\n\t\tports: EdgePorts;\n\t\tengine: DockerEngine;\n\t},\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(options.engine, 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/**\n * Write a file into the edge's running container whole or not at all: a\n * temporary name, then a rename. Not `.yml`: the edge reads only `.yml`,\n * `.yaml` and `.toml` files, so it never sees one half written.\n */\nasync function put(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tpath: string,\n\tcontent: string,\n\tmode: '600' | '644' = '644',\n): Promise<void> {\n\tconst result = await docker.exec(\n\t\tedge,\n\t\tEDGE_SERVICE,\n\t\t[\n\t\t\t'sh',\n\t\t\t'-c',\n\t\t\t'set -e; t=\"$1.tmp\"; cat > \"$t\"; chmod \"$2\" \"$t\"; mv \"$t\" \"$1\"',\n\t\t\t'sh',\n\t\t\tpath,\n\t\t\tmode,\n\t\t],\n\t\tcontent,\n\t);\n\tif (result.code !== 0) {\n\t\tthrow new EdgeWriteFailed(path, `${result.stderr}${result.stdout}`);\n\t}\n}\n\n/** Remove files from the edge's container; whether the first was there. */\nasync function remove(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tpaths: readonly string[],\n): Promise<boolean> {\n\tconst result = await docker.exec(edge, EDGE_SERVICE, [\n\t\t'sh',\n\t\t'-c',\n\t\t'e=1; [ -f \"$1\" ] && e=0; rm -f \"$@\"; exit $e',\n\t\t'sh',\n\t\t...paths,\n\t]);\n\treturn result.code === 0;\n}\n\n/**\n * The edge, up: its network and its container — started when it is not\n * running, and recreated when its configuration changed. Idempotent: on a\n * server where it already runs as configured, `up` changes nothing. Its\n * compose file is written to `file`, on this machine: compose reads it here.\n */\nexport async function ensureEdge(\n\tdocker: ComposeDocker,\n\toptions: {\n\t\tfile: string;\n\t\tports: EdgePorts;\n\t\tlogging: { driver: string; options: Record<string, string> };\n\t\thost?: string;\n\t\toutput?: StackRef['output'];\n\t\tsignal?: AbortSignal;\n\t},\n): Promise<string[]> {\n\tconst { file, ports } = options;\n\tconst staticConfig = traefikStaticFile(ports);\n\tconst content = edgeComposeFile({\n\t\tports,\n\t\tstaticConfig,\n\t\tlogging: options.logging,\n\t});\n\tawait mkdir(dirname(file), { recursive: true });\n\tif ((await readFile(file, 'utf-8').catch(() => undefined)) !== content) {\n\t\tawait writeFile(file, content);\n\t}\n\n\tconst ref = edgeRef(file, {\n\t\t...(options.host ? { host: options.host } : {}),\n\t\t...(options.output ? { output: options.output } : {}),\n\t\t...(options.signal ? { signal: options.signal } : {}),\n\t});\n\tawait docker.ensureNetwork(ref, EDGE_NETWORK);\n\tawait docker.up(ref, [EDGE_SERVICE]);\n\treturn [file];\n}\n\n/** A stack's routes, inside the edge's container. */\nexport function routesPath(project: string): string {\n\treturn `${EDGE_DYNAMIC_DIR}/${project}.yml`;\n}\n\nfunction certificatePaths(project: string): [string, string] {\n\treturn [\n\t\t`${EDGE_CERTS_DIR}/${project}.crt`,\n\t\t`${EDGE_CERTS_DIR}/${project}.key`,\n\t];\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. The certificate is read here and written\n * through the engine. The paths written, inside the edge.\n */\nexport async function writeEdgeRoutes(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tproject: string,\n\troutes: string,\n\tcertificate?: { certFile: string; keyFile: string },\n): Promise<string[]> {\n\tconst written: string[] = [];\n\tconst [crt, key] = certificatePaths(project);\n\tif (certificate) {\n\t\tawait put(docker, edge, crt, await readFile(certificate.certFile, 'utf-8'));\n\t\tawait put(\n\t\t\tdocker,\n\t\t\tedge,\n\t\t\tkey,\n\t\t\tawait readFile(certificate.keyFile, 'utf-8'),\n\t\t\t'600',\n\t\t);\n\t\twritten.push(crt, key);\n\t} else {\n\t\tawait remove(docker, edge, [crt, key]);\n\t}\n\tawait put(docker, edge, routesPath(project), routes);\n\twritten.push(routesPath(project));\n\treturn written;\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\n/**\n * Unregister a stack: its routes, then its certificate. Whether there was\n * anything to remove — false, too, when the edge is not running.\n */\nexport async function removeEdgeRoutes(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tproject: string,\n): Promise<boolean> {\n\tconst file = routesPath(project);\n\tconst there = await docker.exec(edge, EDGE_SERVICE, ['test', '-f', file]);\n\tif (there.code !== 0) return false;\n\t// Emptied by a rename before it is removed: a watcher that misses the\n\t// removal has still seen the stack's routes go.\n\tawait put(docker, edge, file, UNREGISTERED);\n\tawait remove(docker, edge, [file, ...certificatePaths(project)]);\n\treturn true;\n}\n","/**\n * What a deployed stage's stack generates once and keeps: its seed, each\n * `secret` construct's value, the log UI's root password where its telemetry\n * is self-hosted, and the stack's Redis password where a cache lives in it.\n *\n * Pure: the compose target writes the result back to the stage's store.\n */\n\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport {\n\ttype GeneratedSecrets,\n\twithGeneratedSecrets,\n} from '../deploy/generated.js';\nimport { initStageSecrets } from '../secrets/storage.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { resolveStageTelemetry } from '../telemetry/config';\nimport { usesTelemetry } from '../telemetry/edges';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { withLogsPassword } from './logs';\nimport { runsRedis, withRedisPassword } from './redis';\n\nexport function deployedStackSecrets(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\tstored: StageSecrets | null,\n\tmanifest: ConstructManifest,\n): GeneratedSecrets {\n\tconst withSeed = withGeneratedSecrets(\n\t\tstored ?? initStageSecrets(stage),\n\t\tmanifest,\n\t);\n\t// The log UI's root password, generated once like the seed, where the\n\t// stage's telemetry is self-hosted and the stage set none.\n\tconst telemetry = resolveStageTelemetry({\n\t\t...(workspace.deploy?.telemetry\n\t\t\t? { telemetry: workspace.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal: false,\n\t\ttarget: 'compose',\n\t\truntime: 'server',\n\t\tselfHosted: true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\tconst withLogs =\n\t\ttelemetry?.provider === 'self-hosted'\n\t\t\t? withLogsPassword(withSeed.secrets)\n\t\t\t: { secrets: withSeed.secrets, generated: [] };\n\t// The stack's Redis password, the same way, where a cache lives in it.\n\tconst withRedis = runsRedis(manifest, withLogs.secrets.custom ?? {})\n\t\t? withRedisPassword(withLogs.secrets)\n\t\t: { secrets: withLogs.secrets, generated: [] };\n\treturn {\n\t\tsecrets: withRedis.secrets,\n\t\tgenerated: [\n\t\t\t...withSeed.generated,\n\t\t\t...withLogs.generated,\n\t\t\t...withRedis.generated,\n\t\t],\n\t};\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 — the local stage on this machine's Docker, a deployed stage on its\n * server's, driven over SSH (`compose/server.ts`) from wherever the deploy\n * runs.\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 — through an SSH tunnel to a\n * server's loopback — 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 { BACKUPS_SERVICE, backupsRoleStatements } from '../../backups/service';\nimport {\n\ttype HostLookup,\n\tHostNotPointingAtServer,\n\tisLocalHost,\n\tisReservedStageKey,\n\trequiredServerAddress,\n\tSERVER_IPV4_KEY,\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\tedgeRef,\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 ComposeServer,\n\tcomposeServer,\n\tdockerHost,\n\ttype ServerAccess,\n\tsshAccess,\n\tsshTarget,\n} from '../../compose/server';\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\twithCaddyConfigs,\n} from '../../compose/stack';\nimport { EDGE_PROJECT, EDGE_SERVICE } from '../../compose/traefik';\nimport { currentActor } from '../../deploy/actor.js';\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 { appEnvKeys, workerEnvKeys } from '../../reconcile/apps.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 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\t/**\n\t * A deployed stage's server, beyond its Docker engine: the SSH check\n\t * before a deploy, and the tunnels its databases are reached through.\n\t */\n\tserver: ServerAccess;\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/**\n\t * The deployed stage's server, whose Docker engine — over SSH — runs the\n\t * stack. Absent for the local stage, and for a push, which builds here.\n\t */\n\tserver?: ComposeServer;\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\tserver: sshAccess,\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// 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// 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') {\n\t\tassertRedisClient(workspace, composed, manifest, runnables);\n\t}\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\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\t// Where the stack runs: a deployed stage on its server's engine, over\n\t// SSH — never this machine's. A push builds here and runs nothing.\n\t// A domain's stage names its address before anything else is said of\n\t// its server: it is the host SSH reaches too, unless config names one.\n\tif (!push && !stack.local) {\n\t\trequiredServerAddress(stage, workspace.domains?.[stage], secrets?.custom);\n\t}\n\tconst server = push\n\t\t? undefined\n\t\t: composeServer({\n\t\t\t\tstage,\n\t\t\t\tlocal: stack.local,\n\t\t\t\tconfig: workspace.deploy?.compose?.server,\n\t\t\t\tcustom: secrets?.custom,\n\t\t\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\t...(server ? { server } : {}),\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\t...(server ? { host: dockerHost(server) } : {}),\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// ============================================================================\n// ready\n// ============================================================================\n\n/**\n * What only a compose deploy checks before it changes anything, once the\n * stage's own keys are: the stage's own certificate is there, and every\n * public host points at the stage's server — its records written where a\n * provider holds them, then confirmed — before Caddy or Traefik ask Let's\n * Encrypt for a certificate it could not issue. A build-only run never asks.\n */\nexport async function readyCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\n\t// Read when the stack starts; one that is not there stops the run here,\n\t// before anything is written or started.\n\tif (stack.tls) {\n\t\tfor (const file of [stack.tls.certFile, stack.tls.keyFile]) {\n\t\t\tif (!existsSync(file)) throw new ComposeTlsFileMissing(ctx.stage, file);\n\t\t}\n\t}\n\n\tif (stack.local) return;\n\t// The server answers before anything is written — a DNS record included.\n\t// A dry run changes nothing anywhere, and connects to nothing.\n\tif (run.server && !ctx.dryRun && !run.push) {\n\t\tawait deps.server.check(run.server);\n\t}\n\tawait stageHostsDns(\n\t\tctx,\n\t\tdeps,\n\t\tstackHosts(stack).filter((host) => !isLocalHost(host)),\n\t\trun.secrets?.custom,\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 whose process reaches 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. A process that reaches no cache registers no\n * cache driver, so it needs no client.\n */\nfunction assertRedisClient(\n\tworkspace: NormalizedWorkspace,\n\tstack: ComposeStack,\n\tmanifest: ConstructManifest,\n\trunnables: Readonly<Record<string, readonly string[]>>,\n): void {\n\tif (!stack.plan.resources.some((r) => r.kind === 'cache')) return;\n\n\tconst cacheKeys = Object.values(manifest)\n\t\t.filter((d) => d.kind === 'cache')\n\t\t.flatMap((d) => d.provides ?? []);\n\tconst reachesCache = (keys: Set<string> | undefined) =>\n\t\tcacheKeys.some((key) => keys?.has(key));\n\n\tconst hosts = new Set([\n\t\t...stack.apps\n\t\t\t.filter(\n\t\t\t\t(app) =>\n\t\t\t\t\tapp.kind === 'rest-api' &&\n\t\t\t\t\treachesCache(appEnvKeys(manifest, app.name, runnables)),\n\t\t\t)\n\t\t\t.map((a) => a.name),\n\t\t...stack.workers\n\t\t\t.filter((worker) =>\n\t\t\t\treachesCache(workerEnvKeys(manifest, worker.id, runnables)),\n\t\t\t)\n\t\t\t.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 deploy's DNS step, for a deployed stage: its server's address — required\n * where it serves a real domain — then its own hosts written through each\n * domain's provider in `dns` where they differ, read back from it, and\n * recorded in the stage's state; hosts no provider writes resolved with the\n * system resolver. A dry run prints the plan and writes nothing, and warns\n * rather than stops.\n *\n * @throws {ServerAddressMissing} when the stage has a domain and no address\n * @throws {ServerAddressInvalid} for a value that is not an address\n * @throws {HostNotPointingAtServer} when a host is not the server\n */\nasync function stageHostsDns(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n\thosts: readonly string[],\n\tcustom: Readonly<Record<string, string>> | undefined,\n): Promise<void> {\n\tconst { workspace, stage } = ctx;\n\tconst server = requiredServerAddress(\n\t\tstage,\n\t\tworkspace.domains?.[stage],\n\t\tcustom,\n\t);\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 (!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 * The stage's secrets — and, for a deployed stage, everything it generates\n * once: its seed, and each declared secret and keyring. Kept only once the\n * run goes ahead (`provision`), so a dry run, or a tag that is not there,\n * leaves the stage's secrets as it found them.\n */\nasync function stageSecrets(\n\tctx: ComposeContext,\n\tmanifest: ConstructManifest,\n): Promise<{ secrets: StageSecrets | null; generated: string[] }> {\n\tconst stored = await ctx.secrets.read();\n\tif (ctx.stage === ctx.workspace.stages.local) {\n\t\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 [key, value] of Object.entries(secrets.custom ?? {})) {\n\t\tif (!isReservedStageKey(key)) ctx.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\tengine: ref,\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\tctx.logger.info(`\\n🌐 Starting the shared edge (${EDGE_PROJECT})…`);\n\t\trun.files.push(\n\t\t\t...(await ensureEdge(deps.docker, {\n\t\t\t\tfile: edgeFile(run),\n\t\t\t\tports,\n\t\t\t\t...(ref.host ? { host: ref.host } : {}),\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 tunnel = await reach(run, deps, 'minio', 9000);\n\tlet done: Awaited<ReturnType<typeof applyBuckets>>;\n\ttry {\n\t\tconst client = deps.buckets(tunnel.port, storage);\n\t\tdone = [\n\t\t\t...(await applyBuckets(client, storage.buckets)),\n\t\t\t...(await applyPolicies(client, storage.policies)),\n\t\t];\n\t} finally {\n\t\tawait tunnel.close();\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 tunnel = await reach(run, deps, 'postgres', 5432);\n\ttry {\n\t\tawait migrateAndSeed(ctx, run, deps, tunnel.port);\n\t} finally {\n\t\tawait tunnel.close();\n\t}\n}\n\n/**\n * A port a stack's service publishes on its engine's loopback, reachable\n * from this machine: the published port itself on the local stage, and on a\n * server an SSH tunnel to it over the deploy's own login — so Postgres and\n * MinIO are never published beyond the server's loopback.\n *\n * Migrations and seeds run here, in this process, with the project's own\n * Kysely — the way `gkm migrate` runs them — through that port. No image\n * needs to carry them, and nothing is run on the server but the stack.\n */\nasync function reach(\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tservice: string,\n\tinside: number,\n): Promise<{ port: number; close: () => Promise<void> }> {\n\tconst published = await deps.docker.port(run.ref, service, inside);\n\tif (!run.server) return { port: published, close: async () => {} };\n\treturn deps.server.tunnel(run.server, published);\n}\n\nasync function migrateAndSeed(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tport: number,\n): Promise<void> {\n\tconst { stack } = run;\n\tconst workspace: NormalizedWorkspace = ctx.workspace;\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 = [\n\t\t...postgresStatements(stack.plan, workspace.name, stack.credential.seed),\n\t\t// The backups service's own login: it reads, and writes nothing.\n\t\t...(stack.backups ? backupsRoleStatements(stack.backups) : []),\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(ref, 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\t// The local stage is never on the edge, which is a server's.\n\tconst edge = edgeRef(edgeFile(run), {\n\t\t...(ref.host ? { host: ref.host } : {}),\n\t\t...(ref.output ? { output: ref.output } : {}),\n\t});\n\tif (stack.proxy === 'traefik' && stack.traefik) {\n\t\tconst written = await writeEdgeRoutes(\n\t\t\tdeps.docker,\n\t\t\tedge,\n\t\t\tstack.project,\n\t\t\tstack.traefik,\n\t\t\tstack.tls,\n\t\t);\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 if (!stack.local) {\n\t\tawait removeEdgeRoutes(deps.docker, 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; a deployed stage's is its\n\t// server. Either is asked directly, on its published port, with each host\n\t// as SNI and Host: what is checked is its routing and its certificate,\n\t// whatever DNS — or a record not yet propagated — says.\n\tconst edge = stack.local\n\t\t? { connectTo: '127.0.0.1' }\n\t\t: run.server\n\t\t\t? { connectTo: run.server.host, connectPort: edgePorts(deps.env).https }\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, run.server);\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\tserver: ComposeServer | undefined,\n): void {\n\tconst lines = logsAccess(logs, {\n\t\tstage: ctx.stage,\n\t\tlocal,\n\t\tuser: server?.user ?? currentUser(),\n\t\thostname: server?.host ?? hostname(),\n\t\t...(server ? { known: true } : {}),\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\n/** The shared edge's compose file, as this machine hands it to compose. */\nfunction edgeFile(run: ComposeRun): string {\n\treturn join(run.dir, `${EDGE_PROJECT}.yml`);\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\t// Caddy's files go inline, in the compose file: nothing the stack runs\n\t// mounts a path on this machine, so the same file runs on a server's\n\t// engine over SSH. With the stage's own key in it, it is owner-only.\n\tconst tls =\n\t\tstack.proxy === 'caddy' && stack.tls\n\t\t\t? {\n\t\t\t\t\tcert: await readFile(stack.tls.certFile, 'utf-8'),\n\t\t\t\t\tkey: await readFile(stack.tls.keyFile, 'utf-8'),\n\t\t\t\t}\n\t\t\t: undefined;\n\tconst compose =\n\t\tstack.caddyfile !== undefined\n\t\t\t? withCaddyConfigs(stack.compose, {\n\t\t\t\t\tcaddyfile: stack.caddyfile,\n\t\t\t\t\t...(tls ? { tls } : {}),\n\t\t\t\t})\n\t\t\t: stack.compose;\n\tawait write(\n\t\tjoin(dir, 'docker-compose.yml'),\n\t\tcomposeYaml(stack, compose),\n\t\ttls ? 0o600 : 0o644,\n\t);\n\t// For reading: the proxy's configuration — the stack's own Caddy's, or a\n\t// 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 copy of the stage's certificate an older gkm mounted from here.\n\tawait rm(join(dir, 'tls'), { recursive: true, force: true });\n\t// Env files stay on this machine: compose reads each one here and sends\n\t// its values in the call that creates the container — on a server's\n\t// engine too, where no secret is ever written as a file.\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// The backups image's build context, and its key — read from its own env\n\t// file like any app's, never from the host.\n\tif (stack.backups) {\n\t\tfor (const [name, content] of Object.entries(stack.backups.files)) {\n\t\t\tawait write(join(dir, BACKUPS_SERVICE, name), content);\n\t\t}\n\t\tif (stack.compose.services[BACKUPS_SERVICE]?.env_file) {\n\t\t\tawait write(\n\t\t\t\tjoin(dir, `${BACKUPS_SERVICE}.env`),\n\t\t\t\tenvFile(stack.backups.env),\n\t\t\t\t0o600,\n\t\t\t);\n\t\t}\n\t} else {\n\t\tawait rm(join(dir, BACKUPS_SERVICE), { recursive: true, force: true });\n\t\tawait rm(join(dir, `${BACKUPS_SERVICE}.env`), { force: true });\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(\n\tstack: ComposeStack,\n\tcompose: ComposeStack['compose'],\n): 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(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\tif (run.server) {\n\t\tctx.logger.info(` → ${sshTarget(run.server)} (docker over ssh)`);\n\t}\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\tif (stack.backups) {\n\t\tctx.logger.info(\n\t\t\t` ${BACKUPS_SERVICE.padEnd(12)} ${stack.backups.databases.map((d) => d.file).join(', ')} — ${stack.backups.backups.describe}, to ${stack.backups.prefix}/`,\n\t\t);\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 — the local stage on the machine that runs the deploy, a deployed\n * stage on its server's Docker engine, over SSH (`deploy.compose.server`).\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 * - `ready`: a deploy's own checks, after the stage's keys are — the stage's\n * certificate, its server's address, and every public host's DNS\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: no\n * readiness check runs, so a stage whose keys the deploy has yet to write\n * still builds.\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\treadyCompose,\n\treleaseCompose,\n\tvalidateCompose,\n\tverifyCompose,\n} from './phases';\n\nexport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\ttype HealthRequest,\n\tHealthRequestTimedOut,\n} from './health';\nexport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n\tstackOverrideFile,\n} from './phases';\n\nexport interface ComposeTargetOptions\n\textends Partial<ComposeDeps>,\n\t\tComposeRunOptions {\n\t/** Handed the finished run — `gkm compose` prints and returns from it. */\n\treport?: (run: ComposeRun) => void;\n}\n\n/** The compose target, with its Docker, bundler and probe as given. */\nexport function composeTarget(\n\toptions: ComposeTargetOptions = {},\n): DeployTarget<undefined, ComposeRun> {\n\tconst { mode, push, pin, report, ...given } = options;\n\tconst deps: ComposeDeps = { ...defaultDeps, ...given };\n\n\treturn defineTarget<undefined, ComposeRun>({\n\t\tname: 'compose',\n\t\truntime: 'server',\n\t\tcapabilities: {\n\t\t\trollback: false,\n\t\t\tmigrations: 'target',\n\t\t\timages: true,\n\t\t\t// The local stage runs where the deploy does — the `gkm dev`\n\t\t\t// 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`, which\n\t\t// docker sends with each pull — on a server's engine too.\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\tready: (ctx, run) => readyCompose(ctx, run, deps),\n\t\tplan: (ctx, run) => planCompose(ctx, run),\n\t\tprovision: (ctx, run) => provisionCompose(ctx, run, deps),\n\t\tbuild: (ctx, run) => buildCompose(ctx, run, deps),\n\t\trelease: (ctx, run) => releaseCompose(ctx, run, deps),\n\t\tverify: (ctx, run) => verifyCompose(ctx, run, deps),\n\t\tresult: (ctx, run) => {\n\t\t\treport?.(run);\n\t\t\treturn composeResult(ctx, run);\n\t\t},\n\t});\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compose-CYeMW2_o.cjs","names":["GkmError","spawn","run","runOutput","mkdir","dirname","GkmError","SERVER_IPV4_KEY","createServer","createConnection","spawn","CLIENT_IP_HEADER","GkmError","createHash","CLIENT_IP_HEADER","yaml","stringify","createHash","GkmError","localRolePassword","postgresSuperuser","LOCAL_RABBITMQ_USER","EMULATOR_ACCESS_KEY_ID","planFor","provisionOrder","DEFAULT_EVENTS","STACK_CACHE","proxyFor","certificateFor","workerUnits","provideKey","resolveStageTelemetry","usesTelemetry","stackLogs","externalServices","stageServiceDeclarations","stageProviderNotes","stackRedis","LOGS_SERVICE","bucketPolicies","hostFor","NoDomainForStage","appKey","networkEnv","isReservedStageKey","suppliedOnly","telemetryEnv","otlpTelemetryEnv","isTelemetryKey","publicBuildValues","appEnvKeys","scopeTelemetryEnv","telemetryOf","workerEnvKeys","stageBackups","stackBackups","join","LOGS_PORT","appDockerfile","workerDockerfile","devServicesUsed","validateImageRef","imageRef","WORKER_PORT","resolveHost","isMainFrontendApp","composeFor","portKeys","REDIS_SERVICE","redisService","logsService","BACKUPS_SERVICE","backupsService","composeBuildPaths","DEFAULT_IMAGES","TURBO_VERSION","dirname","GkmError","mkdir","readFile","writeFile","withGeneratedSecrets","initStageSecrets","resolveStageTelemetry","usesTelemetry","withLogsPassword","runsRedis","withRedisPassword","GkmError","request","GkmError","join","runOutput","pgClient","bucketClient","ensurePostgresLogin","migrateDatabases","seedDatabases","systemLookup","imageRef","discover","constructGlobs","imageLayout","loadLocalCredentials","existsSync","ComposeTlsFileMissing","stackHosts","isLocalHost","appEnvKeys","workerEnvKeys","installedFrom","requiredServerAddress","SERVER_IPV4_KEY","serverAddressHint","stageDns","DeployJournal","createComposeState","recordDnsChanges","HostNotPointingAtServer","isReservedStageKey","plannedSeeds","applyBuckets","applyPolicies","LEGACY_LOCAL_LOGIN","postgresStatements","backupsRoleStatements","applyPostgres","envFor","primaryPortKey","SeedFailed","DeploySeedsFailed","currentActor","readFile","LOGS_SERVICE","logsAccess","hostname","userInfo","mkdir","chmod","dirname","writeFile","rm","REDIS_SERVICE","BACKUPS_SERVICE","readdir","ensureDockerignore","findBuildRoot","stringify","defineTarget"],"sources":["../src/compose/docker.ts","../src/compose/server.ts","../src/compose/caddyfile.ts","../src/compose/images.ts","../src/compose/traefik.ts","../src/compose/stack.ts","../src/compose/edge.ts","../src/compose/secrets.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 * The Docker engine the stack runs on, as `DOCKER_HOST` names it: a\n\t * deployed stage's server, `ssh://user@host`. Absent for this machine's\n\t * engine — the local stage — whose environment is left as it is.\n\t *\n\t * Compose is a client: it reads the compose file and every `env_file` here\n\t * and sends their values in the API calls that create each container. A\n\t * stage's secrets therefore never land on the server as a file — they are\n\t * in the container's configuration, which only the server's Docker group\n\t * can read.\n\t */\n\thost?: 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/**\n * The environment a docker command for `engine` runs with: this process's,\n * with `DOCKER_HOST` pointing at the stack's engine when it is a server's.\n */\nexport function engineEnv(\n\tengine: Pick<StackRef, 'host'>,\n\textra: NodeJS.ProcessEnv = {},\n): NodeJS.ProcessEnv | undefined {\n\tif (!engine.host && Object.keys(extra).length === 0) return undefined;\n\treturn {\n\t\t...process.env,\n\t\t...extra,\n\t\t...(engine.host ? { DOCKER_HOST: engine.host } : {}),\n\t};\n}\n\n/** How a stack's docker commands run: where it is, where output goes. */\nfunction runOptions(stack: StackRef, extra?: NodeJS.ProcessEnv): RunOptions {\n\tconst env = engineEnv(stack, extra);\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 a command run in a container said, whatever it exited with. */\nexport interface ExecResult {\n\t/** Its exit code — null when the service has no running container. */\n\tcode: number | null;\n\tstdout: string;\n\tstderr: string;\n}\n\n/** The engine a call that is about no stack in particular is made against. */\nexport type DockerEngine = Pick<StackRef, 'host'>;\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 on the stack's engine: the registry digest a\n\t * pulled image has, or the content id of one built and never pushed.\n\t */\n\tdigest(engine: DockerEngine, ref: string): Promise<string | undefined>;\n\t/** Create a network on the engine, unless one by that name is there. */\n\tensureNetwork(engine: DockerEngine, name: string): Promise<void>;\n\t/** Every running container publishing `port` on the engine's host. */\n\tpublishers(engine: DockerEngine, port: number): Promise<PortHolder[]>;\n\t/**\n\t * Run a command in a service's running container, `input` on its stdin —\n\t * how files reach a container on a server, through the engine alone.\n\t */\n\texec(\n\t\tstack: StackRef,\n\t\tservice: string,\n\t\tcommand: readonly string[],\n\t\tinput?: string,\n\t): Promise<ExecResult>;\n\t/**\n\t * A compose project's running container for `service` on the engine, by\n\t * its labels — found without the stack's compose file.\n\t */\n\tcontainer(\n\t\tengine: DockerEngine,\n\t\tproject: string,\n\t\tservice: string,\n\t): Promise<{ id: string; image: string } | undefined>;\n\t/**\n\t * The host port a compose project's running `service` publishes for\n\t * `inside` on the engine, by its labels — found without the stack's\n\t * compose file. Undefined when it is not running or publishes none.\n\t */\n\tpublished(\n\t\tengine: DockerEngine,\n\t\tproject: string,\n\t\tservice: string,\n\t\tinside: number,\n\t): Promise<number | undefined>;\n\t/**\n\t * Run `command` once on the engine, in a new container of `image` on\n\t * `network`, removed when it ends, with `stdin` streamed in. Each of `env`\n\t * is passed by name, never on the command line. Resolves with its exit\n\t * code.\n\t */\n\trunOnce(\n\t\tengine: DockerEngine,\n\t\toptions: {\n\t\t\timage: string;\n\t\t\tnetwork: string;\n\t\t\tcommand: readonly string[];\n\t\t\tenv?: Readonly<Record<string, string>>;\n\t\t\tstdin?: NodeJS.ReadableStream;\n\t\t\toutput?: StackRef['output'];\n\t\t},\n\t): Promise<number>;\n}\n\n/** The network compose puts a project's services on. */\nexport function projectNetwork(project: string): string {\n\treturn `${project}_default`;\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/**\n * The host port a `docker ps` Ports column publishes for `inside`:\n * `127.0.0.1:54321->5432/tcp` is 54321.\n */\nexport function publishedPort(\n\tcolumn: string,\n\tinside: number,\n): number | undefined {\n\tconst match = new RegExp(\n\t\t`(?:[\\\\d.]+|\\\\[[^\\\\]]*\\\\]):(\\\\d+)->${inside}/tcp`,\n\t).exec(column);\n\treturn match ? Number(match[1]) : undefined;\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` itself failed, before it could say anything about a service. */\nexport class DockerUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly engine: string,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask Docker on ${engine} which ports its services publish ` +\n\t\t\t\t`(docker said: ${stderr.trim() || 'nothing'}). Check that ` +\n\t\t\t\t`\\`DOCKER_HOST=${engine} docker ps\\` works from here.`,\n\t\t);\n\t\tthis.name = 'DockerUnreachable';\n\t}\n}\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\toptions: { env?: NodeJS.ProcessEnv; input?: string; timeoutMs?: number } = {},\n): Promise<{ code: number | null; stdout: string; stderr: string }> {\n\tconst { timeoutMs = 60_000 } = options;\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: [options.input === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t\t...(options.env ? { env: options.env } : {}),\n\t\t});\n\t\tif (options.input !== undefined) child.stdin?.end(options.input);\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 env = engineEnv(stack);\n\t\tconst output = await runOutput(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['port', service, String(inside)]),\n\t\t\t{\n\t\t\t\tcwd: stack.cwd,\n\t\t\t\t...(env ? { env } : {}),\n\t\t\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t\t\t},\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 env = engineEnv(stack);\n\t\tconst { code, stdout } = await capture(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['ps', '--format', '{{.Health}}', service]),\n\t\t\tenv ? { env } : {},\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(engine, ref) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { code, stdout } = await capture(\n\t\t\t'docker',\n\t\t\t['image', 'inspect', '--format={{json .RepoDigests}} {{.Id}}', ref],\n\t\t\tenv ? { env } : {},\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(engine, name) {\n\t\tconst env = engineEnv(engine);\n\t\tconst options = env ? { env } : {};\n\t\tconst { code } = await capture(\n\t\t\t'docker',\n\t\t\t['network', 'inspect', name],\n\t\t\toptions,\n\t\t);\n\t\tif (code === 0) return;\n\t\tconst created = await capture(\n\t\t\t'docker',\n\t\t\t['network', 'create', name],\n\t\t\toptions,\n\t\t);\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(engine, port) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { stdout } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--format',\n\t\t\t\t'{{.Names}}\\t{{.Label \"com.docker.compose.project\"}}\\t{{.Label \"com.docker.compose.service\"}}\\t{{.Ports}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\treturn portHolders(stdout, port);\n\t},\n\n\tasync exec(stack, service, command, input) {\n\t\tconst env = engineEnv(stack);\n\t\tconst options = env ? { env } : {};\n\t\t// By its compose labels, so it needs no compose file: `--down` reaches\n\t\t// the shared edge with nothing but its project's name.\n\t\tconst { stdout: ids } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'-q',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${stack.project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t],\n\t\t\toptions,\n\t\t);\n\t\tconst container = ids.trim().split('\\n')[0];\n\t\tif (!container) {\n\t\t\treturn { code: null, stdout: '', stderr: `${service} is not running` };\n\t\t}\n\t\treturn capture(\n\t\t\t'docker',\n\t\t\t['exec', ...(input === undefined ? [] : ['-i']), container, ...command],\n\t\t\t{ ...options, ...(input === undefined ? {} : { input }) },\n\t\t);\n\t},\n\n\tasync container(engine, project, service) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { stdout } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t\t'--format',\n\t\t\t\t'{{.ID}}\\t{{.Image}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\tconst [id, image] = stdout.trim().split('\\n')[0]?.split('\\t') ?? [];\n\t\treturn id && image ? { id, image } : undefined;\n\t},\n\n\tasync published(engine, project, service, inside) {\n\t\tconst env = engineEnv(engine);\n\t\tconst { code, stdout, stderr } = await capture(\n\t\t\t'docker',\n\t\t\t[\n\t\t\t\t'ps',\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.project=${project}`,\n\t\t\t\t'--filter',\n\t\t\t\t`label=com.docker.compose.service=${service}`,\n\t\t\t\t'--format',\n\t\t\t\t'{{.Ports}}',\n\t\t\t],\n\t\t\tenv ? { env } : {},\n\t\t);\n\t\t// Docker not answering is not a service that publishes nothing.\n\t\tif (code !== 0) {\n\t\t\tthrow new DockerUnreachable(engine.host ?? 'this machine', stderr);\n\t\t}\n\t\treturn publishedPort(stdout, inside);\n\t},\n\n\trunOnce(engine, options) {\n\t\treturn dockerExit(\n\t\t\t[\n\t\t\t\t'run',\n\t\t\t\t'--rm',\n\t\t\t\t...(options.stdin ? ['-i'] : []),\n\t\t\t\t'--network',\n\t\t\t\toptions.network,\n\t\t\t\t...Object.keys(options.env ?? {}).flatMap((name) => ['-e', name]),\n\t\t\t\t'--entrypoint',\n\t\t\t\t'',\n\t\t\t\toptions.image,\n\t\t\t\t...options.command,\n\t\t\t],\n\t\t\t{\n\t\t\t\tenv: engineEnv(engine, { ...options.env }) ?? process.env,\n\t\t\t\t...(options.stdin ? { stdin: options.stdin } : {}),\n\t\t\t\t...(options.output ? { output: options.output } : {}),\n\t\t\t},\n\t\t);\n\t},\n};\n\n/** Spawn `docker`, its output where `output` says; resolve with the exit code. */\nfunction dockerExit(\n\targs: readonly string[],\n\toptions: {\n\t\tenv?: NodeJS.ProcessEnv;\n\t\tstdin?: NodeJS.ReadableStream;\n\t\toutput?: StackRef['output'];\n\t} = {},\n): Promise<number> {\n\tconst output = STDIO[options.output ?? 'inherit'];\n\tconst out = Array.isArray(output) ? output : [output, output, output];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn('docker', [...args], {\n\t\t\tstdio: [options.stdin ? 'pipe' : 'ignore', out[1], out[2]] as never,\n\t\t\tenv: options.env ?? process.env,\n\t\t\tshell: false,\n\t\t});\n\t\tif (options.stdin && child.stdin) {\n\t\t\toptions.stdin.on('error', (error) => child.stdin?.destroy(error));\n\t\t\tchild.stdin.on('error', () => {});\n\t\t\toptions.stdin.pipe(child.stdin);\n\t\t}\n\t\tchild.on('error', reject);\n\t\tchild.on('close', (code) => resolve(code ?? 1));\n\t});\n}\n\n/** `docker network create` failed. */\nexport class NetworkCreateFailed extends GkmError {\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 * Where a deployed compose stage runs: its server, reached over SSH.\n *\n * gkm never runs on the server. It runs where the deploy is started — a CI\n * runner, a developer's machine — and drives the server's Docker engine over\n * SSH (`DOCKER_HOST=ssh://user@host`), so the server holds Docker, an SSH\n * login and nothing else: no gkm, no checkout, no cloud credentials.\n *\n * ```ts\n * deploy: { compose: { server: { production: { user: 'deploy' } } } }\n * ```\n *\n * The host is the stage's `GKM_SERVER_IPV4` secret — the address its DNS\n * records already point at — unless `host` names another. The local stage is\n * never given one: it runs on this machine's Docker.\n *\n * What the deploy needs from inside the server — Postgres and MinIO, published\n * on the server's loopback alone — it reaches through an SSH tunnel on the same\n * login, so neither is ever published publicly.\n */\n\nimport { spawn } from 'node:child_process';\nimport { createConnection, createServer } from 'node:net';\nimport { GkmError } from '../errors';\nimport type { ComposeServerConfig } from '../workspace/types.js';\nimport { SERVER_IPV4_KEY } from './dnsConfig';\n\n/** A stage's server, as SSH reaches it. */\nexport interface ComposeServer {\n\tuser: string;\n\thost: string;\n\tport: number;\n}\n\n/** A deployed compose stage with nowhere to run. */\nexport class ComposeServerMissing extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly missing: 'config' | 'host',\n\t) {\n\t\tsuper(\n\t\t\tmissing === 'config'\n\t\t\t\t? `'${stage}' is a deployed stage, and gkm deploys it to its server's ` +\n\t\t\t\t\t\t\"Docker over SSH — it never starts a deployed stage on this machine's \" +\n\t\t\t\t\t\t`Docker. Name the login in gkm.config.ts: deploy: { compose: { server: ` +\n\t\t\t\t\t\t`{ ${stage}: { user: 'deploy' } } } } — the host is the stage's ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} secret (gkm secrets:set ${SERVER_IPV4_KEY} '<ip>' ` +\n\t\t\t\t\t\t`--stage ${stage}), or set host there too.`\n\t\t\t\t: `deploy.compose.server.${stage} names no host, and '${stage}' has no ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} secret to default to. Set it: gkm secrets:set ` +\n\t\t\t\t\t\t`${SERVER_IPV4_KEY} '<ip>' --stage ${stage} — or set ` +\n\t\t\t\t\t\t`deploy.compose.server.${stage}.host.`,\n\t\t);\n\t\tthis.name = 'ComposeServerMissing';\n\t}\n}\n\n/** SSH to the stage's server failed before anything was changed there. */\nexport class ComposeServerUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not reach Docker on ${target} over SSH (ssh said: ${stderr.trim() || 'nothing'}). ` +\n\t\t\t\t`Check that \\`ssh ${target} docker version\\` works from here: the host key in ` +\n\t\t\t\t'~/.ssh/known_hosts, the key in your agent or ~/.ssh/config, and the user in ' +\n\t\t\t\t\"the server's docker group.\",\n\t\t);\n\t\tthis.name = 'ComposeServerUnreachable';\n\t}\n}\n\n/** An SSH tunnel to a port on the server's loopback did not open. */\nexport class ComposeTunnelFailed extends GkmError {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly remotePort: number,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not open an SSH tunnel to 127.0.0.1:${remotePort} on ${target} ` +\n\t\t\t\t`(ssh said: ${stderr.trim() || 'nothing'}). The server's sshd must allow ` +\n\t\t\t\t'TCP forwarding for the deploy user (AllowTcpForwarding yes, the default, ' +\n\t\t\t\t'or local), and its key in ~/.ssh/authorized_keys must too: a key ' +\n\t\t\t\t'installed with `restrict` refuses forwarding unless it also says ' +\n\t\t\t\t'`port-forwarding` (`restrict,port-forwarding ssh-ed25519 …`).',\n\t\t);\n\t\tthis.name = 'ComposeTunnelFailed';\n\t}\n}\n\n/**\n * The stage's server: its login from `deploy.compose.server.<stage>`, its\n * host from there or the stage's `GKM_SERVER_IPV4`. Undefined for the local\n * stage, which runs on this machine.\n *\n * @throws {ComposeServerMissing} for a deployed stage with no login or host\n */\nexport function composeServer(options: {\n\tstage: string;\n\tlocal: boolean;\n\tconfig: Readonly<Record<string, ComposeServerConfig>> | undefined;\n\tcustom: Readonly<Record<string, string>> | undefined;\n}): ComposeServer | undefined {\n\tconst { stage } = options;\n\tif (options.local) return undefined;\n\tconst config = options.config?.[stage];\n\tif (!config) throw new ComposeServerMissing(stage, 'config');\n\tconst host = config.host ?? options.custom?.[SERVER_IPV4_KEY]?.trim();\n\tif (!host) throw new ComposeServerMissing(stage, 'host');\n\treturn { user: config.user, host, port: config.port ?? 22 };\n}\n\n/** `user@host`, as a person types it after `ssh`. */\nexport function sshTarget(server: ComposeServer): string {\n\treturn `${server.user}@${server.host}`;\n}\n\n/** The server's Docker engine, as `DOCKER_HOST` names it. */\nexport function dockerHost(server: ComposeServer): string {\n\tconst host = server.host.includes(':') ? `[${server.host}]` : server.host;\n\treturn `ssh://${server.user}@${host}${server.port === 22 ? '' : `:${server.port}`}`;\n}\n\n/** The arguments every `ssh` gkm runs starts with: no prompt, ever. */\nfunction sshArgs(server: ComposeServer): string[] {\n\treturn [\n\t\t'-o',\n\t\t'BatchMode=yes',\n\t\t'-o',\n\t\t'ConnectTimeout=20',\n\t\t'-p',\n\t\tString(server.port),\n\t\tsshTarget(server),\n\t];\n}\n\n/** A local port forwarded to one on the server's loopback. */\nexport interface Tunnel {\n\t/** The port on this machine's loopback. */\n\tport: number;\n\tclose(): Promise<void>;\n}\n\n/** What the deploy does on a stage's server beyond Docker. */\nexport interface ServerAccess {\n\t/**\n\t * Whether SSH logs in and Docker answers there — read-only: `docker\n\t * version`, nothing else.\n\t */\n\tcheck(server: ComposeServer): Promise<void>;\n\t/** Forward a free local port to `remotePort` on the server's loopback. */\n\ttunnel(server: ComposeServer, remotePort: number): Promise<Tunnel>;\n}\n\nasync function freeLocalPort(): Promise<number> {\n\tconst server = createServer();\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once('error', reject);\n\t\tserver.listen(0, '127.0.0.1', resolve);\n\t});\n\tconst address = server.address();\n\tawait new Promise((resolve) => server.close(resolve));\n\tif (!address || typeof address === 'string') return 0;\n\treturn address.port;\n}\n\nfunction connects(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = createConnection({ host: '127.0.0.1', port });\n\t\tsocket.once('connect', () => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(true);\n\t\t});\n\t\tsocket.once('error', () => resolve(false));\n\t});\n}\n\n/** The real one: the system's `ssh`, with the user's keys and known hosts. */\nexport const sshAccess: ServerAccess = {\n\tcheck(server) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst child = spawn(\n\t\t\t\t'ssh',\n\t\t\t\t[\n\t\t\t\t\t...sshArgs(server),\n\t\t\t\t\t'docker',\n\t\t\t\t\t'version',\n\t\t\t\t\t'--format',\n\t\t\t\t\t'{{.Server.Version}}',\n\t\t\t\t],\n\t\t\t\t{ stdio: ['ignore', 'ignore', 'pipe'] },\n\t\t\t);\n\t\t\tlet stderr = '';\n\t\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\t\tstderr += chunk.toString();\n\t\t\t});\n\t\t\tchild.on('error', (error) =>\n\t\t\t\treject(new ComposeServerUnreachable(sshTarget(server), error.message)),\n\t\t\t);\n\t\t\tchild.on('close', (code) =>\n\t\t\t\tcode === 0\n\t\t\t\t\t? resolve()\n\t\t\t\t\t: reject(new ComposeServerUnreachable(sshTarget(server), stderr)),\n\t\t\t);\n\t\t});\n\t},\n\n\tasync tunnel(server, remotePort) {\n\t\tconst port = await freeLocalPort();\n\t\tconst child = spawn(\n\t\t\t'ssh',\n\t\t\t[\n\t\t\t\t'-N',\n\t\t\t\t'-o',\n\t\t\t\t'ExitOnForwardFailure=yes',\n\t\t\t\t// A connection of its own: through a shared master (ControlMaster\n\t\t\t\t// in ~/.ssh/config) the forward would be the master's, and this\n\t\t\t\t// process — the tunnel's lifetime — would exit at once.\n\t\t\t\t'-o',\n\t\t\t\t'ControlPath=none',\n\t\t\t\t'-L',\n\t\t\t\t`127.0.0.1:${port}:127.0.0.1:${remotePort}`,\n\t\t\t\t...sshArgs(server),\n\t\t\t],\n\t\t\t{ stdio: ['ignore', 'ignore', 'pipe'] },\n\t\t);\n\t\tlet stderr = '';\n\t\tlet exited = false;\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString();\n\t\t});\n\t\tchild.on('exit', () => {\n\t\t\texited = true;\n\t\t});\n\t\tchild.on('error', (error) => {\n\t\t\texited = true;\n\t\t\tstderr += error.message;\n\t\t});\n\t\tconst close = async () => {\n\t\t\tif (exited) return;\n\t\t\tconst gone = new Promise((resolve) => child.once('exit', resolve));\n\t\t\tchild.kill('SIGTERM');\n\t\t\tawait gone;\n\t\t};\n\n\t\t// Open once a connection to it is accepted — ssh only listens once\n\t\t// it has logged in and set the forward up.\n\t\tfor (let attempt = 0; attempt < 150; attempt++) {\n\t\t\tif (exited) break;\n\t\t\tif (await connects(port)) return { port, close };\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200));\n\t\t}\n\t\tawait close();\n\t\tthrow new ComposeTunnelFailed(sshTarget(server), remotePort, stderr);\n\t},\n};\n","/**\n * The stack's own edge, rendered for Caddy: one site block per route.\n *\n * Deployed, each host is the stage's real domain and Caddy gets it a\n * certificate from Let's Encrypt on first request — the same automatic HTTPS\n * it does anywhere, with nothing to configure but the name — or serves the\n * stage's own certificate (`deploy.compose.tls`). Locally the hosts are\n * `*.localhost` and the certificates come from Caddy's own CA, as the `gkm\n * dev` edge does, so a local stack is `https://` like a deployed one.\n *\n * Pure: the routes are data (`routes.ts`), and rendering them is one string.\n */\n\nimport { CLIENT_IP_HEADER } from '@geekmidas/manifest';\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/** Where Caddy reads a stage's own certificate, inside its container. */\nexport const CADDY_TLS_DIR = '/etc/caddy/tls';\n\nexport interface CaddyfileOptions {\n\ttls: EdgeTls;\n\t/** Where ACME sends expiry notices, when someone wants them. */\n\temail?: string;\n}\n\n/** An upstream on the stack's own network: its service name. */\nfunction address({ service, port }: Upstream): string {\n\treturn `${service}:${port}`;\n}\n\n/** The Caddyfile for a stack's edge. */\nexport function edgeCaddyfile(\n\troutes: readonly EdgeRoute[],\n\toptions: CaddyfileOptions,\n): string {\n\tconst { tls } = options;\n\tconst global =\n\t\ttls.kind === 'internal'\n\t\t\t? `{\n\t# No ACME and no public DNS: the CA is Caddy's own and the names resolve\n\t# to this machine.\n\tlocal_certs\n\tauto_https disable_redirects\n}`\n\t\t\t: options.email\n\t\t\t\t? `{\n\temail ${options.email}\n}`\n\t\t\t\t: '';\n\n\tconst certificate =\n\t\ttls.kind === 'internal'\n\t\t\t? `\n\ttls internal\n`\n\t\t\t: tls.kind === 'files'\n\t\t\t\t? `\n\ttls ${tls.certFile} ${tls.keyFile}\n`\n\t\t\t\t: '';\n\n\tconst blocks = routes.map(\n\t\t({\n\t\t\thost,\n\t\t\tupstreams,\n\t\t\tprefix,\n\t\t\tallow,\n\t\t\tstreaming,\n\t\t}) => `https://${host} {${certificate}\n\t# gkm's own header, which only a service of this stack may send: the auth\n\t# server rate-limits by the client address it carries.\n\trequest_header -${CLIENT_IP_HEADER}\n${\n\tallow\n\t\t? `\n\t# Only these addresses — the peer Caddy sees, never a header a client\n\t# could set. Everything else is refused before it reaches the upstream.\n\t@denied not remote_ip ${allow.join(' ')}\n\trespond @denied 403\n`\n\t\t: ''\n}${\n\tprefix\n\t\t? `\n\t# A bucket, served at a host of its own: the bucket is a prefix on MinIO,\n\t# which routes and signs on the Host header — so it is sent the upstream's.\n\treverse_proxy ${upstreams.map(address).join(' ')} {\n\t\trewrite ${prefix}{uri}\n\t\theader_up Host {upstream_hostport}\n\t}`\n\t\t: `\n\t# Host and X-Forwarded-* are passed through as Caddy does by default, so\n\t# an app builds redirects, cookies and links on the address a caller used.\n\treverse_proxy ${upstreams.map(address).join(' ')}${\n\t\tstreaming\n\t\t\t? ` {\n\t\t# Never buffer: a streamed response — server-sent events, a Next.js\n\t\t# RSC payload — reaches the client as each chunk is written.\n\t\tflush_interval -1\n\t}`\n\t\t\t: ''\n\t}`\n}\n}`,\n\t);\n\n\t// No blank line under the header: `caddy fmt` wants the first block there.\n\treturn `${HEADER}${global ? `${global}\\n\\n` : ''}${blocks.join('\\n\\n')}\\n`;\n}\n\nconst HEADER = `# Generated by gkm compose from the construct manifest — do not edit.\n#\n# One host per API and site, each in front of its own container, one per\n# file server in front of the stack's MinIO, and — when its logs are served\n# publicly — one for OpenObserve, to the addresses it allows.\n`;\n","/**\n * Which image each app runs — and, for a tag, whether every one exists.\n *\n * A tag is a release's identity: `--tag=v1.4.0` means the images CI pushed as\n * v1.4.0, and nothing else. So a stack is never half rolled out: every app's\n * image is asked of the registry before anything is pulled or the running\n * stack is touched, and one missing image stops the whole run naming every\n * one that is missing. Nor is a missing image quietly built instead — a build\n * of whatever is checked out here is not the release the tag names.\n */\n\nimport { GkmError } from '../errors';\nimport type { ComposeDocker } from './docker';\n\n/** One app's image, as the stack runs it. */\nexport interface AppImage {\n\tapp: string;\n\tref: string;\n\ttag: string;\n}\n\n/**\n * The tag a site's image carries for a release.\n *\n * A site's public URLs are inlined when it is built, so one bundle serves one\n * stage: `v1.4.0-production` and `v1.4.0-staging` are two images of the same\n * commit. A backend reads its URLs at runtime, so one image serves every stage\n * and its tag is the release's alone.\n */\nexport function siteTag(tag: string, stage: string): string {\n\treturn `${tag}-${stage}`;\n}\n\n/** Images a tag names that the registry does not have. */\nexport class ImageTagNotFound extends GkmError {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly refs: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The registry has no image for ${refs.length === 1 ? 'this app' : `${refs.length} apps`} at '${tag}':\\n` +\n\t\t\t\trefs.map((ref) => ` - ${ref}`).join('\\n') +\n\t\t\t\t`\\nNothing was pulled or started. Push '${tag}' for every app from CI, ` +\n\t\t\t\t`pick a tag that exists, or run without --tag to build from this checkout.`,\n\t\t);\n\t\tthis.name = 'ImageTagNotFound';\n\t}\n}\n\n/** The registry did not answer, or did not let this machine in. */\nexport class RegistryUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask the registry about ${ref}: ${detail || 'no answer'}\\n` +\n\t\t\t\t`Nothing was pulled or started. Check the registry is reachable and ` +\n\t\t\t\t`that this machine is logged in to it (\\`docker login <registry>\\`).`,\n\t\t);\n\t\tthis.name = 'RegistryUnreachable';\n\t}\n}\n\n/**\n * Assert every image exists, before anything else happens.\n *\n * Asked all at once and reported all at once: a release missing two images is\n * one problem with two names, and finding the second only after fixing the\n * first is a slower way to learn the same thing.\n *\n * @throws {RegistryUnreachable} when the registry cannot say\n * @throws {ImageTagNotFound} listing every missing image\n */\nexport async function assertImagesExist(\n\tdocker: Pick<ComposeDocker, 'lookup'>,\n\ttag: string,\n\timages: readonly AppImage[],\n): Promise<void> {\n\tconst lookups = await Promise.all(\n\t\timages.map((image) => docker.lookup(image.ref)),\n\t);\n\n\tconst unreachable = lookups.find((lookup) => lookup.status === 'unreachable');\n\tif (unreachable?.status === 'unreachable') {\n\t\tthrow new RegistryUnreachable(unreachable.ref, unreachable.detail);\n\t}\n\n\tconst missing = lookups\n\t\t.filter((lookup) => lookup.status === 'missing')\n\t\t.map((lookup) => lookup.ref);\n\tif (missing.length > 0) throw new ImageTagNotFound(tag, missing);\n}\n\n/**\n * A push or a pull with no `deploy.registry` to push to or pull from.\n *\n * Without one an image is named `<namespace>/<project>-<app>:<tag>`, which\n * Docker resolves to Docker Hub — so a release would be pushed to, or pulled\n * from, somebody else's account. It is never a fallback.\n */\nexport class RegistryRequired extends GkmError {\n\tconstructor(\n\t\t/** What needed the registry: `--push`, or a pull (`--tag`/`--pull`). */\n\t\treadonly operation: 'push' | 'pull',\n\t\t/** The ref an image would have had: a Docker Hub name. */\n\t\treadonly ref: string,\n\t) {\n\t\tsuper(\n\t\t\t`${operation === 'push' ? 'Pushing' : 'Pulling'} images needs a registry, and gkm.config.ts sets no deploy.registry: ` +\n\t\t\t\t`'${ref}' would be ${operation === 'push' ? 'pushed to' : 'pulled from'} Docker Hub. ` +\n\t\t\t\t`Set deploy.registry (e.g. registry: 'ghcr.io/acme') in gkm.config.ts.` +\n\t\t\t\t(operation === 'pull'\n\t\t\t\t\t? ' To run images built here instead, pass --build.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'RegistryRequired';\n\t}\n}\n\n/**\n * What a push reports, and what a pull can pin to: each app's image as\n * `<ref>@sha256:…` — the tag it was pushed as, and the exact image, whatever\n * that tag is later moved to.\n */\nexport type ImageDigests = Record<string, string>;\n\n/** An image pinned to its digest: `<ref>@sha256:…`. */\nexport function pinnedRef(ref: string, digest: string): string {\n\treturn `${ref.split('@')[0]}@${digest}`;\n}\n\n/** A digests file with no entry for an app the stack runs. */\nexport class ImageDigestMissing extends GkmError {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly apps: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${file} pins no digest for ${apps.join(', ')}. Use the file the ` +\n\t\t\t\t`same release's \\`gkm compose --build --push --digests-file\\` wrote, ` +\n\t\t\t\t`or run without --digests-file to pull by tag.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMissing';\n\t}\n}\n\n/** A digests file entry that is not this app's image. */\nexport class ImageDigestMismatch extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly expected: string,\n\t\treadonly found: string,\n\t) {\n\t\tsuper(\n\t\t\t`The digests file pins '${app}' to ${found}, but this release runs ` +\n\t\t\t\t`${expected}. It was written for another registry, project, stage ` +\n\t\t\t\t`or tag; use the file this stage's push of this tag wrote.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMismatch';\n\t}\n}\n\n/** A digests file that is not a JSON object of app to pinned ref. */\nexport class ImageDigestsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`${file} is not a digests file (${detail}). It should be the JSON ` +\n\t\t\t\t`object \\`gkm compose --build --push --digests-file\\` writes: ` +\n\t\t\t\t`{ \"api\": \"<registry>/<image>:<tag>@sha256:…\" }.`,\n\t\t);\n\t\tthis.name = 'ImageDigestsInvalid';\n\t}\n}\n\n/** Parse a digests file's content, checking its shape. */\nexport function parseDigests(file: string, content: string): ImageDigests {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new ImageDigestsInvalid(\n\t\t\tfile,\n\t\t\terror instanceof Error ? error.message : String(error),\n\t\t);\n\t}\n\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\tthrow new ImageDigestsInvalid(file, 'not a JSON object');\n\t}\n\tfor (const [app, value] of Object.entries(parsed)) {\n\t\tif (typeof value !== 'string' || !/@sha256:[0-9a-f]{64}$/.test(value)) {\n\t\t\tthrow new ImageDigestsInvalid(\n\t\t\t\tfile,\n\t\t\t\t`'${app}' is not an <image>:<tag>@sha256:… ref`,\n\t\t\t);\n\t\t}\n\t}\n\treturn parsed as ImageDigests;\n}\n\n/**\n * Each image pinned to the digest the file names for it.\n *\n * @throws {ImageDigestMissing} naming every app the file has no entry for\n * @throws {ImageDigestMismatch} when an entry is another image or tag\n */\nexport function pinImages<T extends AppImage>(\n\tfile: string,\n\tdigests: ImageDigests,\n\timages: readonly T[],\n): T[] {\n\tconst missing = images\n\t\t.filter((image) => !digests[image.app])\n\t\t.map((image) => image.app);\n\tif (missing.length > 0) throw new ImageDigestMissing(file, missing);\n\n\treturn images.map((image) => {\n\t\tconst pinned = digests[image.app]!;\n\t\tif (pinned.split('@')[0] !== image.ref) {\n\t\t\tthrow new ImageDigestMismatch(image.app, image.ref, pinned);\n\t\t}\n\t\treturn { ...image, ref: pinned };\n\t});\n}\n","/**\n * The server's shared edge, rendered for Traefik: what the edge itself runs\n * with, and what one stack registers with it.\n *\n * One Traefik per server owns 80 and 443, the ACME state and the redirect to\n * HTTPS. It is configured through its file provider alone: each stack writes\n * one file — its routers, services and middlewares, every name prefixed with\n * its compose project — into a directory the edge watches, and removes it\n * when it stops. There is no Docker socket: the edge never learns what runs\n * on the server except from those files.\n *\n * The edge and the stacks meet on one external Docker network. Only a\n * stack's public services join it, each under an alias prefixed with its\n * project (`<project>-api`), because the network is shared: a bare service\n * name there would be answered by every stack's `api`.\n *\n * Pure: the documents are data, and the edge's side effects are `edge.ts`'s.\n */\n\nimport { createHash } from 'node:crypto';\nimport { CLIENT_IP_HEADER } from '@geekmidas/manifest';\nimport { stringify } from 'yaml';\nimport type { EdgeRoute, EdgeTls, Upstream } from './routes.js';\n\n/**\n * The image, pinned: the edge is every stack's way in, so a new version is a\n * change to this line, not whatever `latest` is on the day a server starts.\n */\nexport const TRAEFIK_IMAGE = 'traefik:v3.7.13';\n\n/** The edge's compose project, one per server. */\nexport const EDGE_PROJECT = 'gkm-edge';\n\n/** The external network the edge and every stack's public services share. */\nexport const EDGE_NETWORK = 'gkm-edge';\n\n/** The edge's compose service. */\nexport const EDGE_SERVICE = 'traefik';\n\n/** Inside the edge's container: what it watches, and where certificates are. */\nexport const EDGE_DYNAMIC_DIR = '/etc/gkm-edge/dynamic';\nexport const EDGE_CERTS_DIR = '/etc/gkm-edge/certs';\n\n/** The certificate resolver every deployed route without its own certificate uses. */\nexport const ACME_RESOLVER = 'letsencrypt';\n\n/** The internal entrypoint the edge's health check asks; never published. */\nconst PING_PORT = 8082;\n\n/** A stack's service, as the edge — and the stack itself — reach it. */\nexport function edgeAlias(project: string, service: string): string {\n\treturn `${project}-${service}`;\n}\n\n/** A stack's certificate, as the edge's container reads it. */\nexport function edgeCertificatePaths(project: string): {\n\tcertFile: string;\n\tkeyFile: string;\n} {\n\treturn {\n\t\tcertFile: `${EDGE_CERTS_DIR}/${project}.crt`,\n\t\tkeyFile: `${EDGE_CERTS_DIR}/${project}.key`,\n\t};\n}\n\n/** The edge's ports on the host. */\nexport interface EdgePorts {\n\thttps: number;\n\thttp: number;\n}\n\n/**\n * The edge's static configuration: the entrypoints, the redirect, ACME, and\n * the directory it watches. No API and no dashboard — nothing about the edge\n * is reachable but the routes stacks register.\n */\nexport function traefikStatic(ports: EdgePorts): Record<string, unknown> {\n\treturn {\n\t\tglobal: { checkNewVersion: false, sendAnonymousUsage: false },\n\t\tentryPoints: {\n\t\t\tweb: {\n\t\t\t\taddress: ':80',\n\t\t\t\thttp: {\n\t\t\t\t\t// Every plain-HTTP request is sent to HTTPS — but an ACME\n\t\t\t\t\t// HTTP-01 challenge, which Traefik answers before the redirect.\n\t\t\t\t\tredirections: {\n\t\t\t\t\t\tentryPoint: {\n\t\t\t\t\t\t\t// The published port when it is not 443, so the redirect\n\t\t\t\t\t\t\t// lands where the edge actually listens.\n\t\t\t\t\t\t\tto: ports.https === 443 ? 'websecure' : `:${ports.https}`,\n\t\t\t\t\t\t\tscheme: 'https',\n\t\t\t\t\t\t\tpermanent: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twebsecure: { address: ':443' },\n\t\t\tping: { address: `:${PING_PORT}` },\n\t\t},\n\t\tping: { entryPoint: 'ping' },\n\t\tproviders: {\n\t\t\tfile: { directory: EDGE_DYNAMIC_DIR, watch: true },\n\t\t},\n\t\tcertificatesResolvers: {\n\t\t\t[ACME_RESOLVER]: {\n\t\t\t\tacme: {\n\t\t\t\t\tstorage: '/acme/acme.json',\n\t\t\t\t\thttpChallenge: { entryPoint: 'web' },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tlog: { level: 'INFO' },\n\t};\n}\n\n/** The edge's compose document. */\nexport function edgeCompose(options: {\n\tports: EdgePorts;\n\t/**\n\t * The static configuration, as written: handed to the container inline\n\t * (`configs.content`), so nothing is read from a path on whichever machine\n\t * runs the deploy — and its hash recreates the edge when it changes.\n\t */\n\tstaticConfig: string;\n\tlogging: { driver: string; options: Record<string, string> };\n}): Record<string, unknown> {\n\tconst { ports } = options;\n\treturn {\n\t\tname: EDGE_PROJECT,\n\t\tservices: {\n\t\t\t[EDGE_SERVICE]: {\n\t\t\t\timage: TRAEFIK_IMAGE,\n\t\t\t\trestart: 'unless-stopped',\n\t\t\t\tports: [`${ports.https}:443`, `${ports.http}:80`],\n\t\t\t\tconfigs: [{ source: 'traefik', target: '/etc/traefik/traefik.yml' }],\n\t\t\t\tvolumes: [\n\t\t\t\t\t// Volumes on the server, written through the engine (`docker\n\t\t\t\t\t// exec`): each stack's routes and certificate, replaced by a\n\t\t\t\t\t// rename the file provider sees whole.\n\t\t\t\t\t`dynamic:${EDGE_DYNAMIC_DIR}`,\n\t\t\t\t\t`certs:${EDGE_CERTS_DIR}`,\n\t\t\t\t\t'acme:/acme',\n\t\t\t\t],\n\t\t\t\t// Static configuration is read at start: a change to it is a\n\t\t\t\t// change to the service, so `up` recreates the edge.\n\t\t\t\tlabels: {\n\t\t\t\t\t'dev.geekmidas.edge.config': createHash('sha256')\n\t\t\t\t\t\t.update(options.staticConfig)\n\t\t\t\t\t\t.digest('hex')\n\t\t\t\t\t\t.slice(0, 16),\n\t\t\t\t},\n\t\t\t\tnetworks: ['edge'],\n\t\t\t\thealthcheck: {\n\t\t\t\t\ttest: ['CMD', 'traefik', 'healthcheck', '--ping'],\n\t\t\t\t\tinterval: '10s',\n\t\t\t\t\ttimeout: '5s',\n\t\t\t\t\tretries: 5,\n\t\t\t\t},\n\t\t\t\tlogging: options.logging,\n\t\t\t},\n\t\t},\n\t\tconfigs: { traefik: { content: options.staticConfig } },\n\t\tvolumes: { acme: {}, dynamic: {}, certs: {} },\n\t\tnetworks: { edge: { name: EDGE_NETWORK, external: true } },\n\t};\n}\n\n/** What a stack registers with the edge — its routes, and its certificate. */\nexport interface TraefikStackOptions {\n\tproject: string;\n\t/** ACME, or the stage's own certificate. Never the local CA: that is Caddy's. */\n\ttls: Exclude<EdgeTls, { kind: 'internal' }>;\n}\n\n/** A stack's dynamic configuration, as an object. */\nexport function traefikDynamic(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): Record<string, unknown> {\n\tconst { project, tls } = options;\n\tconst name = (route: EdgeRoute, suffix?: string) =>\n\t\t`${project}-${route.name}${suffix ? `-${suffix}` : ''}`;\n\tconst url = ({ service, port }: Upstream) =>\n\t\t`http://${edgeAlias(project, service)}:${port}`;\n\n\tconst routers: Record<string, unknown> = {};\n\tconst services: Record<string, unknown> = {};\n\tconst middlewares: Record<string, unknown> = {};\n\n\t// gkm's own header, which only a service of this stack may send — the\n\t// auth server rate-limits by the client address it carries — removed from\n\t// every request that arrives from outside. An empty value is Traefik's\n\t// way of removing a request header.\n\tconst strip = `${project}-strip-gkm-headers`;\n\tif (routes.length > 0) {\n\t\tmiddlewares[strip] = {\n\t\t\theaders: { customRequestHeaders: { [CLIENT_IP_HEADER]: '' } },\n\t\t};\n\t}\n\n\tfor (const route of routes) {\n\t\tconst chain: string[] = [strip];\n\t\tif (route.allow) {\n\t\t\t// The peer Traefik sees — never X-Forwarded-For, which a client\n\t\t\t// could set. Everything else gets 403.\n\t\t\tmiddlewares[name(route, 'allow')] = {\n\t\t\t\tipAllowList: { sourceRange: [...route.allow] },\n\t\t\t};\n\t\t\tchain.push(name(route, 'allow'));\n\t\t}\n\t\tif (route.prefix) {\n\t\t\tmiddlewares[name(route, 'prefix')] = {\n\t\t\t\taddPrefix: { prefix: route.prefix },\n\t\t\t};\n\t\t\tchain.push(name(route, 'prefix'));\n\t\t}\n\n\t\trouters[name(route)] = {\n\t\t\trule: `Host(\\`${route.host}\\`)`,\n\t\t\tentryPoints: ['websecure'],\n\t\t\tservice: name(route),\n\t\t\tmiddlewares: chain,\n\t\t\ttls: tls.kind === 'acme' ? { certResolver: ACME_RESOLVER } : {},\n\t\t};\n\n\t\tservices[name(route)] = {\n\t\t\tloadBalancer: {\n\t\t\t\tservers: route.upstreams.map((upstream) => ({ url: url(upstream) })),\n\t\t\t\t// A bucket is routed and signed on the Host header, so MinIO is\n\t\t\t\t// sent its own; an app is sent the one the caller used, which is\n\t\t\t\t// what it builds redirects, cookies and links on.\n\t\t\t\t...(route.prefix ? { passHostHeader: false } : {}),\n\t\t\t\t...(route.streaming\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t// Never buffer: each chunk of a streamed response is\n\t\t\t\t\t\t\t// flushed to the client as it is written.\n\t\t\t\t\t\t\tresponseForwarding: { flushInterval: '-1ms' },\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\t...(route.health\n\t\t\t\t\t? {\n\t\t\t\t\t\t\thealthCheck: {\n\t\t\t\t\t\t\t\tpath: route.health,\n\t\t\t\t\t\t\t\tinterval: '5s',\n\t\t\t\t\t\t\t\ttimeout: '3s',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\thttp: {\n\t\t\trouters,\n\t\t\tservices,\n\t\t\t...(Object.keys(middlewares).length > 0 ? { middlewares } : {}),\n\t\t},\n\t\t...(tls.kind === 'files'\n\t\t\t? {\n\t\t\t\t\ttls: {\n\t\t\t\t\t\tcertificates: [{ certFile: tls.certFile, keyFile: tls.keyFile }],\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/** A stack's dynamic configuration file, as written to the edge's directory. */\nexport function traefikDynamicFile(\n\troutes: readonly EdgeRoute[],\n\toptions: TraefikStackOptions,\n): string {\n\treturn `# Generated by gkm compose for ${options.project} — do not edit.\n# The shared edge (${EDGE_PROJECT}) reads every file in this directory; this\n# one is removed by gkm compose --down.\n${yaml(traefikDynamic(routes, options))}`;\n}\n\n/** The edge's static configuration file. */\nexport function traefikStaticFile(ports: EdgePorts): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n${yaml(traefikStatic(ports))}`;\n}\n\n/** The edge's compose file. */\nexport function edgeComposeFile(\n\toptions: Parameters<typeof edgeCompose>[0],\n): string {\n\treturn `# Generated by gkm compose — the server's shared edge. Do not edit.\n#\n# Started by the first stack that runs with proxy: 'traefik', and left\n# running by gkm compose --down. Stop it, once nothing uses it, with:\n#\n# docker compose -p ${EDGE_PROJECT} down\n${yaml(edgeCompose(options))}`;\n}\n\nfunction yaml(value: unknown): string {\n\treturn stringify(value, { lineWidth: 0, aliasDuplicateObjects: false });\n}\n","/**\n * The stack a workspace runs as for one stage — pure.\n *\n * Everything `gkm compose` writes is decided here, as data: the compose file,\n * the Caddyfile, one env file per backend, and the image each app runs. The\n * command around it reads the workspace, asks the registry, writes the files\n * and starts Docker; none of those decide anything, so all of it can be\n * asserted without a daemon.\n *\n * The values come from the same derivations every other target uses. The\n * plan is reconcile's `planFor`, the keys an app reads are `appEnvKeys`, and\n * every URL is `envFor`'s — asked twice, once with each app at its public\n * address and once on the compose network, because a browser and a sibling\n * service reach the same API by different names.\n */\n\nimport { createHash } from 'node:crypto';\nimport { join } from 'node:path';\nimport {\n\ttype ConstructManifest,\n\tprovideKey,\n\tprovisionOrder,\n} from '@geekmidas/manifest';\nimport { stageBackups } from '../backups/config.js';\nimport {\n\tBACKUPS_SERVICE,\n\tbackupsService,\n\ttype StackBackups,\n\tstackBackups,\n} from '../backups/service.js';\nimport { type WorkerUnit, workerUnits } from '../build/workers.js';\nimport {\n\ttype DevServiceUse,\n\tdevServicesUsed,\n\ttype ExternalServices,\n\texternalServices,\n\ttype ServiceDeclaration,\n\tstageServiceDeclarations,\n\tsuppliedOnly,\n} from '../deploy/devServices.js';\nimport { isMainFrontendApp, resolveHost } from '../deploy/domain.js';\nimport { type DeployIdentity, imageRef } from '../deploy/identity.js';\nimport { validateImageRef } from '../docker/imageRef.js';\nimport { appDockerfile, workerDockerfile } from '../docker/index.js';\nimport { composeBuildPaths, type ImageLayout } from '../docker/layout.js';\nimport { TURBO_VERSION, WORKER_PORT } from '../docker/templates.js';\nimport { GkmError } from '../errors';\nimport { stageProviderNotes } from '../providers/notes.js';\nimport { appEnvKeys, networkEnv, workerEnvKeys } from '../reconcile/apps.js';\nimport { hostFor } from '../reconcile/caddyfile.js';\nimport { type ComposeService, composeFor } from '../reconcile/compose.js';\nimport { DEFAULT_IMAGES, portKeys } from '../reconcile/containers.js';\nimport { EMULATOR_ACCESS_KEY_ID } from '../reconcile/emulator.js';\nimport { localRolePassword } from '../reconcile/env.js';\nimport {\n\ttype ContainerCredentials,\n\tLOCAL_RABBITMQ_USER,\n\ttype LocalCredentials,\n\tpostgresSuperuser,\n} from '../reconcile/localCredentials.js';\nimport { type Plan, type PlannedResource, planFor } from '../reconcile/plan.js';\nimport { bucketPolicies } from '../reconcile/provision.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport {\n\totlpTelemetryEnv,\n\ttype ResolvedTelemetry,\n\tresolveStageTelemetry,\n\ttelemetryEnv,\n} from '../telemetry/config.js';\nimport {\n\tisTelemetryKey,\n\tscopeTelemetryEnv,\n\ttelemetryOf,\n\tusesTelemetry,\n} from '../telemetry/edges.js';\nimport { DEFAULT_EVENTS } from '../types.js';\nimport { appKey } from '../workspace/derive.js';\nimport type {\n\tComposeTlsConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../workspace/types.js';\nimport { CADDY_TLS_DIR, edgeCaddyfile } from './caddyfile.js';\nimport { isReservedStageKey } from './dnsConfig.js';\nimport { type AppImage, siteTag } from './images.js';\nimport {\n\tLOGS_SERVICE,\n\tlogsService,\n\ttype StackLogs,\n\tstackLogs,\n} from './logs.js';\nimport { LOGS_PORT } from './logsConfig.js';\nimport { certificateFor, proxyFor } from './proxy.js';\nimport {\n\tREDIS_SERVICE,\n\tredisService,\n\tSTACK_CACHE,\n\ttype StackRedis,\n\tstackRedis,\n} from './redis.js';\nimport type { ComposeProxy, EdgeRoute, EdgeTls } from './routes.js';\nimport { publicBuildValues } from './siteBuild.js';\nimport {\n\tEDGE_NETWORK,\n\tedgeAlias,\n\tedgeCertificatePaths,\n\ttraefikDynamicFile,\n} from './traefik.js';\n\n/** Where a stack's files are written, relative to the workspace root. */\nexport function stackDir(stage: string): string {\n\treturn `.gkm/compose/${stage}`;\n}\n\n/**\n * The compose project a stage's stack runs as.\n *\n * The deploy identity's scope, so two workspaces with one name in different\n * namespaces never share containers or volumes — and the stage, so a\n * machine can run two stages side by side.\n */\nexport function composeProject(identity: DeployIdentity): string {\n\treturn `${identity.scope}-${identity.stage}`;\n}\n\n/** The ports the edge is published on, and the variables that move them. */\nexport const EDGE_PORT_ENV = {\n\thttps: 'GKM_COMPOSE_HTTPS_PORT',\n\thttp: 'GKM_COMPOSE_HTTP_PORT',\n} as const;\n\n/**\n * The variable that moves the local stage's OpenObserve off its loopback\n * port, 5080 — which the local stage takes from nowhere else, since it\n * ignores `deploy.telemetry`. Another stack, or another tool, may hold 5080.\n */\nexport const LOGS_PORT_ENV = 'GKM_COMPOSE_LOGS_PORT';\n\n/**\n * Containers this target does not run.\n *\n * The AWS emulator never applies: a stack is a server target, whose events\n * are pg-boss. Reconcile's Caddy fronts `gkm dev`'s host processes; the stack\n * brings its own edge.\n *\n * MinIO and Mailpit run on the local stage always, and on a deployed stage\n * only where `--allow-dev-services` allowed them and its secrets configure no\n * real bucket or mail server — see `devServices.ts`.\n */\nconst NOT_RUN: Readonly<Record<string, true>> = {\n\tlocalstack: true,\n\tcaddy: true,\n};\n\n/** The kinds a deployed stage takes from its secrets, or a dev service. */\nconst SERVICE_KINDS: Readonly<Record<string, ServiceDeclaration['kind']>> = {\n\temail: 'email',\n\tobjects: 'objects',\n\t'file-server': 'file-server',\n};\n\n/** The region MinIO is addressed with. It has no regions; the SDK wants one. */\nconst MINIO_REGION = 'us-east-1';\n\n/** The S3 client's credentials, read beside a bucket's URL when it has them. */\nconst STORAGE_KEYS = [\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_REGION',\n] as const;\n\n/**\n * Every service's Docker logs, rotated. The json-file driver keeps a\n * container's output in one file that grows until the disk is full — on a\n * small server, in weeks. Three files of 10 MB each per container is enough\n * to see what happened and never fills anything. A project's own override\n * file that sets `logging` wins over it.\n */\nexport const LOG_ROTATION = {\n\tdriver: 'json-file',\n\toptions: { 'max-size': '10m', 'max-file': '3' },\n} as const;\n\n/** Each image's build, where the stack builds rather than pulls. */\nexport interface AppBuild {\n\t/** Where the Dockerfile is written, relative to the workspace root. */\n\tdockerfile: string;\n\t/** A site's public URLs, inlined by its bundler. */\n\targs?: Record<string, string>;\n}\n\n/** One app in the stack. */\nexport interface StackApp extends AppImage {\n\t/** Its compose service name — the app key, `api`. */\n\tname: string;\n\t/** The construct it serves. */\n\tid: string;\n\tkind: 'rest-api' | 'site';\n\t/** Its directory, relative to the workspace root. */\n\tpath: string;\n\tport: number;\n\t/** The host the edge answers it on. */\n\thost: string;\n\t/** `https://<host>` — with the edge's port where it is not 443. */\n\turl: string;\n\tbuild?: AppBuild;\n\t/** A backend's environment, exactly the keys it reads. Absent for a site. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A Worker in the stack: its crons, queue consumers and subscribers in a\n * container of their own. Nothing routes to it and nothing is published —\n * its one route is the health check Docker asks.\n */\nexport interface StackWorker extends AppImage {\n\t/** Its compose service name — `jobs`. */\n\tname: string;\n\t/** The Worker construct. */\n\tid: string;\n\t/** The app whose build writes its entry, which its image is built from. */\n\thost: string;\n\t/** Where its health check answers, inside the container. */\n\tport: number;\n\tbuild?: AppBuild;\n\t/** Exactly the keys the worker's constructs read. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A mobile app, as a stage builds it: nothing in the stack runs it — EAS\n * builds it and the stores ship it — but its build reads the stage's\n * public values, resolved here the way a site's build args are.\n */\nexport interface StackMobileApp {\n\t/** Its app key — `app`. */\n\tname: string;\n\t/** The `MobileApp` construct. */\n\tid: string;\n\t/**\n\t * What its build reads, for this stage: its scheme, its edges' public\n\t * URLs under `EXPO_PUBLIC_`, and every stage secret already named so.\n\t */\n\tvalues: Record<string, string>;\n}\n\n/** A service as the stack's compose file defines it. */\nexport interface StackService {\n\timage: string;\n\tbuild?: {\n\t\tcontext: string;\n\t\tdockerfile: string;\n\t\targs?: Record<string, string>;\n\t};\n\t/** `build` for an image built on the server and never pulled. */\n\tpull_policy?: 'build';\n\trestart?: string;\n\tcommand?: string | string[];\n\tenv_file?: { path: string; format: 'raw' }[];\n\tenvironment?: Record<string, string>;\n\tports?: string[];\n\tvolumes?: string[];\n\t/** Files handed to the container inline — see {@link withCaddyConfigs}. */\n\tconfigs?: { source: string; target: string; mode?: number }[];\n\tlabels?: Record<string, string>;\n\tdepends_on?: Record<string, { condition: 'service_healthy' }>;\n\thealthcheck?: ComposeService['healthcheck'];\n\t/**\n\t * Behind the shared edge, a public service is on the stack's own network\n\t * and the edge's, by an alias unique on both.\n\t */\n\tnetworks?: Record<string, { aliases: string[] }>;\n\tlogging?: {\n\t\tdriver: string;\n\t\toptions: Record<string, string>;\n\t};\n}\n\nexport interface StackFile {\n\tname: string;\n\tservices: Record<string, StackService>;\n\tvolumes: Record<string, Record<string, never>>;\n\t/** The shared edge's network, which the stack joins but never creates. */\n\tnetworks?: Record<string, { name: string; external: true }>;\n\t/** Files the stack's containers are handed, by content. */\n\tconfigs?: Record<string, { content: string }>;\n}\n\n/**\n * The stack with Caddy's files inline: its Caddyfile and, where the stage has\n * one, its own certificate — `configs` with their `content`, which compose\n * copies into the container through the engine's API. Nothing is mounted from\n * a path, so the stack runs the same on a server's engine, over SSH, as on\n * this machine's. Their hash is a label: a changed file is a changed service,\n * which `up` recreates (compose does not, for a config's content alone).\n */\nexport function withCaddyConfigs(\n\tcompose: StackFile,\n\tfiles: { caddyfile: string; tls?: { cert: string; key: string } },\n): StackFile {\n\tconst caddy = compose.services.caddy;\n\tif (!caddy) return compose;\n\tconst configs: Record<string, { content: string }> = {\n\t\tcaddyfile: { content: files.caddyfile },\n\t\t...(files.tls\n\t\t\t? {\n\t\t\t\t\t'tls-cert': { content: files.tls.cert },\n\t\t\t\t\t'tls-key': { content: files.tls.key },\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n\tconst hash = createHash('sha256');\n\tfor (const [name, { content }] of Object.entries(configs)) {\n\t\thash.update(`${name}\\0${content}\\0`);\n\t}\n\treturn {\n\t\t...compose,\n\t\tservices: {\n\t\t\t...compose.services,\n\t\t\tcaddy: {\n\t\t\t\t...caddy,\n\t\t\t\tconfigs: [\n\t\t\t\t\t{ source: 'caddyfile', target: '/etc/caddy/Caddyfile' },\n\t\t\t\t\t...(files.tls\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{ source: 'tls-cert', target: `${CADDY_TLS_DIR}/cert.pem` },\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tsource: 'tls-key',\n\t\t\t\t\t\t\t\t\ttarget: `${CADDY_TLS_DIR}/key.pem`,\n\t\t\t\t\t\t\t\t\tmode: 0o400,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t\tlabels: {\n\t\t\t\t\t...caddy.labels,\n\t\t\t\t\t'dev.geekmidas.caddy.config': hash.digest('hex').slice(0, 16),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconfigs: { ...compose.configs, ...configs },\n\t};\n}\n\nexport interface ComposeStack {\n\tproject: string;\n\tstage: string;\n\t/** The project's local stage, served with Caddy's internal CA. */\n\tlocal: boolean;\n\tapps: StackApp[];\n\t/** Each Worker with background work, in a container of its own. */\n\tworkers: StackWorker[];\n\t/** Each mobile app, and what its build reads for this stage. */\n\tmobileApps: StackMobileApp[];\n\t/** The infrastructure containers, by compose service name. */\n\tinfra: string[];\n\tcompose: StackFile;\n\t/**\n\t * What serves the stack: its own Caddy, or the server's shared Traefik\n\t * edge (`deploy.compose.proxy`). The local stage is always Caddy.\n\t */\n\tproxy: ComposeProxy;\n\t/** Every public host and what answers it — what either proxy renders. */\n\troutes: EdgeRoute[];\n\t/** The stack's own Caddy's configuration — with `proxy: 'caddy'`. */\n\tcaddyfile?: string;\n\t/**\n\t * What the stack registers with the shared edge — with `proxy:\n\t * 'traefik'`: the dynamic configuration file written to its directory.\n\t */\n\ttraefik?: string;\n\t/**\n\t * The stage's own certificate and key, on this machine\n\t * (`deploy.compose.tls`) — copied to where the proxy reads it.\n\t */\n\ttls?: ComposeTlsConfig;\n\t/** Generated Dockerfiles, by path relative to the workspace root. */\n\tdockerfiles: Record<string, string>;\n\t/** The plan the stack was derived from — what provisioning creates. */\n\tplan: Plan;\n\t/** The containers' logins, and the seed role passwords take. */\n\tcredential: StackCredential;\n\t/**\n\t * The stack's MinIO, where it runs one: its root credential — what the\n\t * backends sign with — and the buckets and open paths provisioning\n\t * creates in it.\n\t */\n\tstorage?: StackStorage;\n\t/** The dev services a deployed stage runs (`--allow-dev-services`). */\n\tdevServices: DevServiceUse[];\n\t/**\n\t * The stack's OpenObserve, when the stage's telemetry is self-hosted —\n\t * every process with a `Telemetry` edge sends its logs and traces to it.\n\t */\n\tlogs?: StackLogs;\n\t/** Where the stage's telemetry goes, when any process uses it. */\n\ttelemetry?: ResolvedTelemetry;\n\t/**\n\t * The stack's Redis, where a declared cache lives in it — every cache\n\t * whose URL the stage's secrets do not set.\n\t */\n\tredis?: StackRedis;\n\t/**\n\t * The stage's backups, where it is deployed, runs Postgres and has not\n\t * set `deploy.backups.<stage>: false`.\n\t */\n\tbackups?: StackBackups;\n}\n\n/** What a stack's containers run with, and what its role passwords take. */\nexport interface StackCredential {\n\tcontainers: ContainerCredentials;\n\tseed: string;\n}\n\n/** The local stage's stack, without the logins `gkm dev` generates. */\nexport class LocalCredentialsMissing extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The local stage '${stage}' runs with this machine's generated logins, and none were passed. Load them with loadLocalCredentials(workspace) and pass them as localCredentials.`,\n\t\t);\n\t\tthis.name = 'LocalCredentialsMissing';\n\t}\n}\n\n/**\n * A deployed stage's container logins, derived from its seed like its role\n * passwords — so every deploy of the stage computes the same ones, and no one\n * reading the repo can.\n */\nexport function derivedCredentials(\n\tproject: string,\n\tplan: Plan,\n\tseed: string,\n): ContainerCredentials {\n\tconst derive = (purpose: string) =>\n\t\tlocalRolePassword(project, plan, purpose, seed);\n\treturn {\n\t\tpostgres: { user: postgresSuperuser(project), password: derive('master') },\n\t\tminio: { user: `${project}-minio`, password: derive('minio') },\n\t\trabbitmq: { user: LOCAL_RABBITMQ_USER, password: derive('rabbitmq') },\n\t\tredis: { password: derive('redis') },\n\t\tcacheToken: derive('cache-token'),\n\t\temulator: {\n\t\t\taccessKeyId: EMULATOR_ACCESS_KEY_ID,\n\t\t\tsecretAccessKey: derive('emulator'),\n\t\t},\n\t\t// Never read: a deployed stage's OpenObserve signs in with the root\n\t\t// login its secrets hold (`stackLogs`), and the stack hands each process\n\t\t// its telemetry keys from that, not from the derivation.\n\t\tlogs: { email: `admin@${project}`, password: derive('logs') },\n\t};\n}\n\n/** The stack's MinIO, and what is created in it. */\nexport interface StackStorage {\n\tuser: string;\n\tpassword: string;\n\t/** Each bucket's stage-scoped name. */\n\tbuckets: string[];\n\t/** The open paths of each served bucket. */\n\tpolicies: { bucket: string; open: string[] }[];\n}\n\nexport interface StackInput {\n\tworkspace: NormalizedWorkspace;\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/**\n\t * Each Worker's crons', queues' and subscribers' files, from discovery —\n\t * which workers run, and which app each is built from.\n\t */\n\tbackground?: Readonly<Record<string, readonly string[]>>;\n\tstage: string;\n\tidentity: DeployIdentity;\n\timages: {\n\t\tmode: 'build' | 'pull';\n\t\t/** A release tag, or — building — the commit. */\n\t\ttag: string;\n\t\tregistry?: string;\n\t};\n\t/** The stage's secrets — set by hand, and what a deployed stage generated. */\n\tsecrets?: StageSecrets | null;\n\t/**\n\t * This machine's generated local logins — required for the local stage,\n\t * which runs with the same ones `gkm dev` does. See `localCredentials.ts`.\n\t */\n\tlocalCredentials?: LocalCredentials;\n\t/**\n\t * `--allow-dev-services`: a deployed stage runs the dev service for every\n\t * bucket and mail it does not account for. The local stage runs both\n\t * regardless.\n\t */\n\tallowDevServices?: boolean;\n\t/** The edge's published ports. 443 and 80 by default. */\n\tports?: {\n\t\thttps?: number;\n\t\thttp?: number;\n\t\t/** The local stage's OpenObserve port — see {@link LOGS_PORT_ENV}. */\n\t\tlogs?: number;\n\t};\n\t/**\n\t * The stack only builds its images, to push them (`--build --push`): no\n\t * backend's or worker's runtime environment is resolved and no service\n\t * reads an env file, so building needs none of the stage's backend\n\t * secrets. A site's build args — its public URLs — are still resolved.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * For builds: where the images are built from and with what — the build\n\t * root, its package manager and turbo. The workspace's root, with pnpm,\n\t * when not given.\n\t */\n\tlayout?: ImageLayout;\n}\n\n/** A value only the stage's secrets can hold, and they do not. */\nexport class StageSecretMissing extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${app}' reads ${key}, and the stage '${stage}' has none. Nothing in ` +\n\t\t\t\t`the stack can derive it; set it in the stage's secrets: ` +\n\t\t\t\t`gkm secrets:set ${key} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'StageSecretMissing';\n\t}\n}\n\n/** A deployed stage's secrets with no seed to derive its passwords from. */\nexport class StageSeedMissing extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' has no seed in its secrets, and a deployed stage's ` +\n\t\t\t\t`database passwords are derived from it. Run gkm compose --stage ${stage} ` +\n\t\t\t\t`without --dry-run once, or gkm deploy, to generate it.`,\n\t\t);\n\t\tthis.name = 'StageSeedMissing';\n\t}\n}\n\n/** A workspace with no API and no site to run. */\nexport class NothingToCompose extends GkmError {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`${root} declares no RestApi, no site and no Worker with work to do, ` +\n\t\t\t\t`so a stack would run nothing. Mobile apps ship through their own ` +\n\t\t\t\t`toolchain.`,\n\t\t);\n\t\tthis.name = 'NothingToCompose';\n\t}\n}\n\n/** A value that cannot be written to an env file a line at a time. */\nexport class EnvValueMultiline extends GkmError {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t) {\n\t\tsuper(\n\t\t\t`${key} for '${app}' spans more than one line, and an env file holds ` +\n\t\t\t\t`one value per line. Store it on one line — base64, or JSON — and ` +\n\t\t\t\t`decode it where it is read.`,\n\t\t);\n\t\tthis.name = 'EnvValueMultiline';\n\t}\n}\n\n/** The services a stack's apps wait on and the edge waits on in turn. */\nconst HEALTHY = { condition: 'service_healthy' } as const;\n\n/**\n * An app's health check: its own server, asked on 127.0.0.1 — not\n * `localhost`, which resolves to `::1` first in an Alpine container while a\n * server may listen on IPv4 alone.\n */\nfunction probe(port: number, path: string): StackService['healthcheck'] {\n\treturn {\n\t\ttest: [\n\t\t\t'CMD',\n\t\t\t'wget',\n\t\t\t'-q',\n\t\t\t'-O',\n\t\t\t'/dev/null',\n\t\t\t`http://127.0.0.1:${port}${path}`,\n\t\t],\n\t\tinterval: '5s',\n\t\ttimeout: '3s',\n\t\tretries: 20,\n\t\tstart_period: '10s',\n\t};\n}\n\n/**\n * What a stage's stack provisions: reconcile's plan, with a server target's\n * backends whatever `deploy.default` says — the stack is one machine running\n * containers, so events are pg-boss beside the declared database, and every\n * cache, one declared from that database included, is in the stack's own\n * Redis.\n */\nexport function stackPlan(\n\tworkspace: Pick<NormalizedWorkspace, 'stages'>,\n\tmanifest: ConstructManifest,\n\tstage: string,\n): Plan {\n\treturn planFor(manifest, stage, provisionOrder(manifest), {\n\t\tlocalStage: workspace.stages.local,\n\t\tevents: DEFAULT_EVENTS.server,\n\t\tcache: STACK_CACHE,\n\t\t// The stack brings its own edge; reconcile's would front the host.\n\t\tedge: false,\n\t});\n}\n\n/** The stack for one stage. */\nexport function composeStack(input: StackInput): ComposeStack {\n\tconst { workspace, manifest, stage, identity } = input;\n\tconst local = stage === workspace.stages.local;\n\tconst project = composeProject(identity);\n\tconst custom = input.secrets?.custom ?? {};\n\tconst https = input.ports?.https ?? 443;\n\tconst http = input.ports?.http ?? 80;\n\tconst proxy = proxyFor(workspace.deploy?.compose, stage, local);\n\tconst certificate = local\n\t\t? undefined\n\t\t: certificateFor(workspace.deploy?.compose, stage, workspace.root);\n\n\t// A server target's backends, whatever `deploy.default` says: the stack is\n\t// one machine running containers, so events are pg-boss beside the\n\t// declared database — and every cache, one declared from that database\n\t// included, is in the stack's own Redis.\n\tconst plan = stackPlan(workspace, manifest, stage);\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\n\t// The local stage's logins are the ones `gkm dev` generated for this\n\t// machine, so the two run their containers with the same; a deployed\n\t// stage's are derived from its seed.\n\tif (local && !input.localCredentials) {\n\t\tthrow new LocalCredentialsMissing(stage);\n\t}\n\tconst seed = local ? input.localCredentials!.seed : input.secrets?.seed;\n\tif (!seed) throw new StageSeedMissing(stage);\n\tconst containers: ContainerCredentials = local\n\t\t? input.localCredentials!\n\t\t: derivedCredentials(workspace.name, plan, seed);\n\tconst credential: StackCredential = {\n\t\tcontainers: {\n\t\t\t...containers,\n\t\t\t// The stage's own key pair, where it set one, is what MinIO runs as.\n\t\t\tminio: {\n\t\t\t\tuser: custom.AWS_ACCESS_KEY_ID ?? containers.minio.user,\n\t\t\t\tpassword: custom.AWS_SECRET_ACCESS_KEY ?? containers.minio.password,\n\t\t\t},\n\t\t},\n\t\tseed,\n\t};\n\n\tconst apps = stackApps(workspace, manifest, plan, {\n\t\tlocal,\n\t\tstage,\n\t\thttps,\n\t\tidentity,\n\t\timages: input.images,\n\t});\n\tconst workers = stackWorkers(\n\t\tworkerUnits(workspace, manifest, input.background ?? {}),\n\t\t{ stage, identity, images: input.images },\n\t);\n\tif (apps.length === 0 && workers.length === 0) {\n\t\tthrow new NothingToCompose(workspace.root);\n\t}\n\n\t// Which construct each key belongs to, so a key is resolved by what it is\n\t// rather than by its spelling.\n\tconst owners = new Map<string, PlannedResource>();\n\tfor (const resource of plan.resources) {\n\t\towners.set(resource.envKey, resource);\n\t\tif (resource.kind === 'email') {\n\t\t\towners.set(provideKey(resource.id, 'from'), resource);\n\t\t\towners.set(provideKey(resource.id, 'inboxUrl'), resource);\n\t\t}\n\t\tif (resource.kind === 'external-api') {\n\t\t\towners.set(provideKey(resource.id, 'credentials'), resource);\n\t\t}\n\t}\n\n\tconst domain = workspace.domains?.[stage];\n\n\t// Where the stage's telemetry goes, when a process uses a `Telemetry`\n\t// node: the local stage always to OpenObserve, a deployed one where\n\t// `deploy.telemetry` says — and OpenObserve when it says nothing.\n\tconst telemetry = resolveStageTelemetry({\n\t\t...(workspace.deploy?.telemetry\n\t\t\t? { telemetry: workspace.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal,\n\t\ttarget: 'compose',\n\t\truntime: 'server',\n\t\tselfHosted: true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\n\t// The log UI, when the stage's telemetry is self-hosted: its root login,\n\t// how it is reached, and what each process with the edge is handed to send\n\t// to it.\n\tconst logsBase =\n\t\ttelemetry?.provider === 'self-hosted'\n\t\t\t? stackLogs({\n\t\t\t\t\tconfig:\n\t\t\t\t\t\tlocal && input.ports?.logs\n\t\t\t\t\t\t\t? { ...telemetry.selfHosted, port: input.ports.logs }\n\t\t\t\t\t\t\t: telemetry.selfHosted,\n\t\t\t\t\tstage,\n\t\t\t\t\tlocal,\n\t\t\t\t\tproject: workspace.name,\n\t\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\t\tcustom,\n\t\t\t\t\thttps,\n\t\t\t\t\t...(local ? { localLogin: input.localCredentials!.logs } : {}),\n\t\t\t\t})\n\t\t\t: undefined;\n\n\t// Mail and storage: the local stage runs Mailpit and MinIO for all of it.\n\t// A deployed stage takes each from its secrets — or, where allowed, from a\n\t// dev service. Only decided here: whether the stage lacks a key is the\n\t// deploy's readiness check's to say, once, and a build asks no such thing.\n\tconst services: ExternalServices = local\n\t\t? {\n\t\t\t\tmissing: [],\n\t\t\t\tminio: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'objects')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t\tmailpit: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'email')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t}\n\t\t: externalServices({\n\t\t\t\tstage,\n\t\t\t\tdeclarations: stageServiceDeclarations({\n\t\t\t\t\tmanifest,\n\t\t\t\t\t...(input.runnables ? { runnables: input.runnables } : {}),\n\t\t\t\t}),\n\t\t\t\tsupplied: custom,\n\t\t\t\tallow: input.allowDevServices === true,\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\tproviders: stageProviderNotes(workspace, stage),\n\t\t\t});\n\n\t// The caches: in the stack's Redis, unless the stage set a cache's URL —\n\t// a managed Redis — and with every one set, there is no Redis to run.\n\tconst redis = stackRedis({\n\t\tplan,\n\t\tstage,\n\t\tlocal,\n\t\tcustom,\n\t\t...(local ? { localPassword: input.localCredentials!.redis.password } : {}),\n\t});\n\n\tconst infra = [\n\t\t...plan.containers\n\t\t\t.filter((c) => !NOT_RUN[c])\n\t\t\t// Run as the stack's own, below, with the stage's login.\n\t\t\t.filter((c) => c !== LOGS_SERVICE)\n\t\t\t.filter((c) => c !== 'minio' || services.minio.length > 0)\n\t\t\t.filter((c) => c !== 'mailpit' || services.mailpit.length > 0)\n\t\t\t.filter((c) => c !== REDIS_SERVICE || redis !== undefined),\n\t\t...(logsBase ? [LOGS_SERVICE] : []),\n\t].sort();\n\n\t// The stack's MinIO signs with the stage's own key pair where it set one,\n\t// and otherwise with the stage's login: the local one `gkm dev` generated,\n\t// or — deployed — one derived from the stage's seed.\n\tconst storage: StackStorage | undefined = infra.includes('minio')\n\t\t? (() => {\n\t\t\t\tconst buckets = services.minio\n\t\t\t\t\t.map((id) => byId.get(id)?.name)\n\t\t\t\t\t.filter((name): name is string => Boolean(name))\n\t\t\t\t\t.sort();\n\t\t\t\treturn {\n\t\t\t\t\t...credential.containers.minio,\n\t\t\t\t\tbuckets,\n\t\t\t\t\tpolicies: bucketPolicies(plan).filter((p) =>\n\t\t\t\t\t\tbuckets.includes(p.bucket),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t})()\n\t\t: undefined;\n\n\t// Each file server over the stack's MinIO, at a host of its own on the\n\t// edge — the shape it has deployed: a domain serving a bucket.\n\tconst fileServers = new Map<string, { url: string; route: EdgeRoute }>();\n\tif (storage) {\n\t\tfor (const resource of plan.resources) {\n\t\t\tif (resource.kind !== 'file-server' || !resource.of) continue;\n\t\t\tif (!services.minio.includes(resource.of)) continue;\n\t\t\tif (custom[resource.envKey] !== undefined) continue;\n\t\t\tconst bucket = byId.get(resource.of);\n\t\t\tif (!bucket) continue;\n\n\t\t\tlet host: string;\n\t\t\tif (local) {\n\t\t\t\thost = hostFor(resource, workspace.name);\n\t\t\t} else {\n\t\t\t\tif (!domain) throw new NoDomainForStage(stage);\n\t\t\t\thost = `${resource.subdomain ?? appKey(resource.id)}.${domain}`;\n\t\t\t}\n\t\t\tfileServers.set(resource.id, {\n\t\t\t\turl: `https://${host}${local && https !== 443 ? `:${https}` : ''}`,\n\t\t\t\troute: {\n\t\t\t\t\tname: `files-${appKey(resource.id)}`,\n\t\t\t\t\thost,\n\t\t\t\t\tupstreams: [{ service: 'minio', port: 9000 }],\n\t\t\t\t\tstreaming: false,\n\t\t\t\t\tprefix: `/${bucket.name}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// Behind the shared edge, the services it routes to are on a network\n\t// every stack's public services share, where a bare name — `api` — would\n\t// be answered by each stack's. They are reached, from the edge and from\n\t// inside the stack alike, by an alias prefixed with the project.\n\tconst edgeServices = new Set(\n\t\tproxy === 'traefik'\n\t\t\t? [\n\t\t\t\t\t...apps.map((app) => app.name),\n\t\t\t\t\t...(fileServers.size > 0 ? ['minio'] : []),\n\t\t\t\t\t...(logsBase?.host && logsBase.public ? [LOGS_SERVICE] : []),\n\t\t\t\t]\n\t\t\t: [],\n\t);\n\tconst hostOf = (service: string) =>\n\t\tedgeServices.has(service) ? edgeAlias(project, service) : service;\n\tconst logs: StackLogs | undefined = logsBase && {\n\t\t...logsBase,\n\t\tappEnv: {\n\t\t\t...logsBase.appEnv,\n\t\t\tOTEL_EXPORTER_OTLP_ENDPOINT:\n\t\t\t\tlogsBase.appEnv.OTEL_EXPORTER_OTLP_ENDPOINT.replace(\n\t\t\t\t\t`//${LOGS_SERVICE}:`,\n\t\t\t\t\t`//${hostOf(LOGS_SERVICE)}:`,\n\t\t\t\t),\n\t\t},\n\t};\n\n\t// Every key the stage resolves, twice: with each app at its public address\n\t// — what a browser is handed, and what an app says it is — and with each on\n\t// the compose network, which is how one service reaches another.\n\tconst derivation = {\n\t\tproject: workspace.name,\n\t\tcredentials: credential.containers,\n\t\tseed: credential.seed,\n\t\t// Mailpit on a deployed stage sends as the stage's domain.\n\t\t...(!local && domain ? { mailFrom: `noreply@${domain}` } : {}),\n\t};\n\tconst outside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(apps.map((app) => [app.id, app.url])),\n\t\t},\n\t\thostOf,\n\t);\n\tconst inside = networkEnv(\n\t\tplan,\n\t\t{\n\t\t\t...derivation,\n\t\t\taddresses: Object.fromEntries(\n\t\t\t\tapps.map((app) => [app.id, `http://${hostOf(app.name)}:${app.port}`]),\n\t\t\t),\n\t\t},\n\t\thostOf,\n\t);\n\n\tconst surfaceUrls = new Map(\n\t\tplan.resources\n\t\t\t.filter((r) => r.kind === 'rest-api' || r.kind === 'site')\n\t\t\t.map((r) => [r.envKey, r.id]),\n\t);\n\tconst appById = new Map(apps.map((app) => [app.id, app]));\n\n\t/**\n\t * What a key resolves to for one app, from the stage's secrets where only\n\t * they can hold it, and the derivations otherwise.\n\t */\n\tconst valueFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkey: string,\n\t\towner: PlannedResource | undefined,\n\t): string | undefined => {\n\t\t// The server's address is gkm's own: never in an app's environment.\n\t\tif (isReservedStageKey(key)) return undefined;\n\t\t// A deployed stage has no inbox: Mailpit runs only locally — not for a\n\t\t// backend, a site's bundle or a phone.\n\t\tif (!local && owner?.kind === 'email' && key.endsWith('_INBOX_URL')) {\n\t\t\treturn undefined;\n\t\t}\n\t\t// Mail and storage: what the stage set — a real server, a real bucket —\n\t\t// and otherwise the dev service it runs, which `services` has already\n\t\t// checked it may.\n\t\tif (owner && SERVICE_KINDS[owner.kind]) {\n\t\t\tif (custom[key] !== undefined) return custom[key];\n\t\t\tif (owner.kind === 'file-server') return fileServers.get(owner.id)?.url;\n\t\t\treturn outside[key];\n\t\t}\n\n\t\t// Supplied by somebody: a third party's credentials, and — deployed —\n\t\t// the secrets the stage generated.\n\t\tif (owner && suppliedOnly(owner.kind, owner.id, key, local)) {\n\t\t\tconst value = custom[key];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new StageSecretMissing(app.name, key, stage);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// Set by hand wins over derived: it is the stage saying what it is.\n\t\tif (custom[key] !== undefined) return custom[key];\n\n\t\t// A cache, in the stack's Redis, by its name on the network.\n\t\tif (owner?.kind === 'cache') return redis?.urls[key];\n\n\t\t// A backend reaches a sibling surface on the compose network; its own\n\t\t// address is the public one, which is what it builds links on. A site\n\t\t// runs in a browser, which has only the public addresses.\n\t\tconst surface = surfaceUrls.get(key);\n\t\tif (app.kind === 'rest-api' && surface && surface !== app.id) {\n\t\t\treturn inside[key];\n\t\t}\n\n\t\treturn outside[key];\n\t};\n\n\t// What the stage resolves for its `Telemetry` node, before a process is\n\t// named: the stack's OpenObserve, or the provider `deploy.telemetry` names.\n\tconst telemetryValues: Record<string, string> | undefined = logs\n\t\t? telemetryEnv(\n\t\t\t\t{\n\t\t\t\t\tendpoint: logs.appEnv.OTEL_EXPORTER_OTLP_ENDPOINT,\n\t\t\t\t\theaders: logs.appEnv.OTEL_EXPORTER_OTLP_HEADERS,\n\t\t\t\t},\n\t\t\t\ttelemetry?.sampleRate ?? 1,\n\t\t\t)\n\t\t: telemetry?.provider === 'otlp'\n\t\t\t? otlpTelemetryEnv(telemetry)\n\t\t\t: undefined;\n\n\t/** Each key one backend process reads, resolved for this stage. */\n\tconst valuesFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkeys: ReadonlySet<string>,\n\t): Record<string, string> => {\n\t\tconst values: Record<string, string> = {};\n\t\tfor (const key of [...keys].sort()) {\n\t\t\t// The node's keys are the stage's telemetry, added per process.\n\t\t\tif (isTelemetryKey(key)) continue;\n\t\t\tconst owner = owners.get(key) ?? storageOwner(key, plan);\n\t\t\tif ((STORAGE_KEYS as readonly string[]).includes(key)) {\n\t\t\t\t// The stage's own key pair where it set one — an external bucket\n\t\t\t\t// signs with it — and otherwise the stack's MinIO's.\n\t\t\t\tconst value = custom[key] ?? storageValue(key, storage);\n\t\t\t\tif (value !== undefined) values[key] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = valueFor(app, key, owner);\n\t\t\tif (value !== undefined) values[key] = value;\n\t\t}\n\t\treturn values;\n\t};\n\n\tfor (const app of apps) {\n\t\tif (app.kind === 'site') {\n\t\t\tconst site = manifest[app.id];\n\t\t\tif (site?.kind !== 'site') continue;\n\n\t\t\tconst args = publicBuildValues(\n\t\t\t\tsite,\n\t\t\t\tmanifest,\n\t\t\t\t(key) => valueFor(app, key, owners.get(key)),\n\t\t\t\tcustom,\n\t\t\t);\n\t\t\tif (app.build && Object.keys(args).length > 0) app.build.args = args;\n\t\t\tcontinue;\n\t\t}\n\t\t// Built to be pushed, a backend's image is every stage's: what it reads\n\t\t// at runtime is the deploy's business, not the build's.\n\t\tif (input.buildOnly) continue;\n\n\t\tconst keys = appEnvKeys(manifest, app.name, input.runnables) ?? new Set();\n\t\tconst values = valuesFor(app, keys);\n\n\t\t// The origins Better Auth trusts are the browser's and, now, each\n\t\t// service that calls this surface across the compose network: its CSRF\n\t\t// check applies to every caller, and a sibling's request carries its\n\t\t// own origin, not a browser's.\n\t\tconst trusted = provideKey(app.id, 'trustedOrigins');\n\t\tif (keys.has(trusted)) {\n\t\t\tconst internal = (byId.get(app.id)?.callers ?? [])\n\t\t\t\t.map((caller) => appById.get(caller))\n\t\t\t\t.filter((caller): caller is StackApp => caller?.kind === 'rest-api')\n\t\t\t\t.map((caller) => `http://${hostOf(caller.name)}:${caller.port}`);\n\t\t\tconst origins = [\n\t\t\t\t...(values[trusted] ?? '').split(',').filter(Boolean),\n\t\t\t\t...internal,\n\t\t\t];\n\t\t\tvalues[trusted] = [...new Set(origins)].join(',');\n\t\t}\n\n\t\t// Telemetry: the stage's, to a process with an edge to the node.\n\t\tapp.env = {\n\t\t\t...scopeTelemetryEnv(values, {\n\t\t\t\tuses: telemetryOf(manifest, app.id) !== undefined,\n\t\t\t\tserviceName: app.name,\n\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t}),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(app.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\n\t\tfor (const [key, value] of Object.entries(app.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(app.name, key);\n\t\t}\n\t}\n\n\t// A mobile app runs on a phone, which has only the public addresses — as\n\t// a browser does — so its values resolve as a site's do.\n\tconst mobileApps: StackMobileApp[] = [];\n\tfor (const declaration of Object.values(manifest)) {\n\t\tif (declaration.kind !== 'mobile-app') continue;\n\t\tconst app = {\n\t\t\tname: appKey(declaration.id),\n\t\t\tid: declaration.id,\n\t\t\tkind: 'site' as const,\n\t\t};\n\t\tmobileApps.push({\n\t\t\tname: app.name,\n\t\t\tid: app.id,\n\t\t\tvalues: publicBuildValues(\n\t\t\t\tdeclaration,\n\t\t\t\tmanifest,\n\t\t\t\t(key) => valueFor(app, key, owners.get(key)),\n\t\t\t\tcustom,\n\t\t\t),\n\t\t});\n\t}\n\n\t// A worker reaches every surface across the compose network: it is never\n\t// one, so no address is its own.\n\tfor (const worker of input.buildOnly ? [] : workers) {\n\t\tconst keys =\n\t\t\tworkerEnvKeys(manifest, worker.id, input.runnables) ?? new Set();\n\t\tworker.env = {\n\t\t\t...scopeTelemetryEnv(\n\t\t\t\tvaluesFor({ name: worker.name, id: worker.id, kind: 'rest-api' }, keys),\n\t\t\t\t{\n\t\t\t\t\tuses: telemetryOf(manifest, worker.id) !== undefined,\n\t\t\t\t\tserviceName: worker.name,\n\t\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t\t},\n\t\t\t),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(worker.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(worker.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(worker.name, key);\n\t\t}\n\t}\n\n\t// A deployed stage's certificates: its own, where it set one, as the\n\t// proxy's container reads them — otherwise Let's Encrypt's.\n\tconst deployedTls: Exclude<EdgeTls, { kind: 'internal' }> = certificate\n\t\t? {\n\t\t\t\tkind: 'files',\n\t\t\t\t...(proxy === 'caddy'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcertFile: `${CADDY_TLS_DIR}/cert.pem`,\n\t\t\t\t\t\t\tkeyFile: `${CADDY_TLS_DIR}/key.pem`,\n\t\t\t\t\t\t}\n\t\t\t\t\t: edgeCertificatePaths(project)),\n\t\t\t}\n\t\t: { kind: 'acme' };\n\tconst tls: EdgeTls = local ? { kind: 'internal' } : deployedTls;\n\n\t// The stage's backups: a deployed stage with Postgres, unless it said\n\t// `false`. A stack that only builds runs nothing, so has none.\n\tconst backupsChoice = input.buildOnly\n\t\t? undefined\n\t\t: stageBackups(workspace, manifest, stage);\n\tconst backups =\n\t\tbackupsChoice?.mode === 'on' && infra.includes('postgres')\n\t\t\t? stackBackups({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tstage,\n\t\t\t\t\tproject,\n\t\t\t\t\tplan,\n\t\t\t\t\tbackups: backupsChoice.backups,\n\t\t\t\t\tcustom,\n\t\t\t\t\tseed,\n\t\t\t\t\tsuperuser: credential.containers.postgres,\n\t\t\t\t\t...(telemetryValues ? { telemetry: telemetryValues } : {}),\n\t\t\t\t})\n\t\t\t: undefined;\n\n\tconst layout = input.layout ?? defaultLayout(workspace.root);\n\tconst compose = stackFile({\n\t\tproject,\n\t\tplan,\n\t\tinfra,\n\t\tapps,\n\t\tworkers,\n\t\tcredentials: credential.containers,\n\t\t...(storage ? { storage } : {}),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\t...(backups ? { backups } : {}),\n\t\thttps,\n\t\thttp,\n\t\tcomposeDir: join(workspace.root, stackDir(stage)),\n\t\tbuildRoot: layout.buildRoot,\n\t\tworkspaceRoot: workspace.root,\n\t\tenvFiles: !input.buildOnly,\n\t\tproxy,\n\t\tedge: new Map(\n\t\t\t[...edgeServices].map((service) => [service, hostOf(service)]),\n\t\t),\n\t});\n\n\t// One route per public host — the data both proxies render.\n\tconst routes: EdgeRoute[] = [\n\t\t...apps.map(\n\t\t\t(app): EdgeRoute => ({\n\t\t\t\tname: app.name,\n\t\t\t\thost: app.host,\n\t\t\t\tupstreams: [{ service: app.name, port: app.port }],\n\t\t\t\tstreaming: true,\n\t\t\t\thealth: app.kind === 'site' ? '/' : '/health',\n\t\t\t}),\n\t\t),\n\t\t...[...fileServers.values()].map(({ route }) => route),\n\t\t...(logs?.host && logs.public\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: LOGS_SERVICE,\n\t\t\t\t\t\thost: logs.host,\n\t\t\t\t\t\tupstreams: [{ service: LOGS_SERVICE, port: LOGS_PORT }],\n\t\t\t\t\t\tstreaming: true,\n\t\t\t\t\t\tallow: logs.public.allow,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\tconst dockerfiles: Record<string, string> = {};\n\tfor (const app of apps) {\n\t\tif (!app.build) continue;\n\t\t// The same Dockerfile `gkm docker` writes: the image is built inside\n\t\t// Docker from a pruned slice of the build root, and nothing is built\n\t\t// here first.\n\t\tdockerfiles[app.build.dockerfile] = appDockerfile(\n\t\t\tapp.name,\n\t\t\tworkspace.apps[app.name]!,\n\t\t\t{\n\t\t\t\tlayout,\n\t\t\t\tworkspaceRoot: workspace.root,\n\t\t\t\tapps: workspace.apps,\n\t\t\t\tmanifest,\n\t\t\t\tcache: STACK_CACHE,\n\t\t\t\t// A site's clients trace at this stage's sample rate.\n\t\t\t\tworkspace,\n\t\t\t\tstage,\n\t\t\t\t// Every build argument the site is handed, declared, or the\n\t\t\t\t// build drops it.\n\t\t\t\t...(app.kind === 'site' && app.build.args\n\t\t\t\t\t? { publicUrlArgs: Object.keys(app.build.args) }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\tif (!worker.build) continue;\n\t\tdockerfiles[worker.build.dockerfile] = workerDockerfile(\n\t\t\t{ id: worker.id, name: worker.name, app: worker.host },\n\t\t\tworkspace.apps[worker.host]!,\n\t\t\t{ layout, workspaceRoot: workspace.root, cache: STACK_CACHE },\n\t\t);\n\t}\n\n\treturn {\n\t\tproject,\n\t\tstage,\n\t\tlocal,\n\t\tapps,\n\t\tworkers,\n\t\tmobileApps,\n\t\tinfra,\n\t\tcompose,\n\t\tproxy,\n\t\troutes,\n\t\t...(proxy === 'caddy'\n\t\t\t? { caddyfile: edgeCaddyfile(routes, { tls }) }\n\t\t\t: {\n\t\t\t\t\ttraefik: traefikDynamicFile(routes, {\n\t\t\t\t\t\tproject,\n\t\t\t\t\t\ttls: deployedTls,\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t...(certificate ? { tls: certificate } : {}),\n\t\tdockerfiles,\n\t\tplan,\n\t\tcredential,\n\t\t...(storage ? { storage } : {}),\n\t\tdevServices: local ? [] : devServicesUsed(services),\n\t\t...(logs ? { logs } : {}),\n\t\t...(telemetry ? { telemetry } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\t...(backups ? { backups } : {}),\n\t};\n}\n\n/** The stack's MinIO's value for one of the S3 client's keys. */\nfunction storageValue(\n\tkey: string,\n\tstorage: StackStorage | undefined,\n): string | undefined {\n\tif (!storage) return undefined;\n\tif (key === 'AWS_ACCESS_KEY_ID') return storage.user;\n\tif (key === 'AWS_SECRET_ACCESS_KEY') return storage.password;\n\tif (key === 'AWS_REGION') return MINIO_REGION;\n\treturn undefined;\n}\n\n/** Which bucket an S3 credential key belongs to — the first one declared. */\nfunction storageOwner(key: string, plan: Plan): PlannedResource | undefined {\n\tif (!(STORAGE_KEYS as readonly string[]).includes(key)) return undefined;\n\treturn plan.resources.find((r) => r.kind === 'objects');\n}\n\n/** The apps a stack runs: every API and every site, at its stage address. */\nfunction stackApps(\n\tworkspace: NormalizedWorkspace,\n\tmanifest: ConstructManifest,\n\tplan: Plan,\n\toptions: {\n\t\tlocal: boolean;\n\t\tstage: string;\n\t\thttps: number;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackApp[] {\n\tconst apps: StackApp[] = [];\n\tconst resources = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'site')\n\t\t\tcontinue;\n\n\t\tconst name = appKey(id);\n\t\tconst app = workspace.apps[name];\n\t\tconst resource = resources.get(id);\n\t\tif (!app || !resource || !app.port) continue;\n\n\t\tconst host = hostOf(name, app, workspace, resource, options);\n\t\tconst site = declaration.kind === 'site';\n\t\tconst tag = site\n\t\t\t? siteTag(options.images.tag, options.stage)\n\t\t\t: options.images.tag;\n\t\tconst ref = validateImageRef(\n\t\t\timageRef(options.identity, name, options.images.registry, tag),\n\t\t);\n\n\t\tapps.push({\n\t\t\tapp: name,\n\t\t\tname,\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tpath: app.path,\n\t\t\tport: app.port,\n\t\t\thost,\n\t\t\turl: `https://${host}${options.local && options.https !== 443 ? `:${options.https}` : ''}`,\n\t\t\tref,\n\t\t\ttag,\n\t\t\t...(options.images.mode === 'build'\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${name}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\treturn apps.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Each worker's image, and where it is built from. */\nfunction stackWorkers(\n\tunits: readonly WorkerUnit[],\n\toptions: {\n\t\tstage: string;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackWorker[] {\n\treturn units.map((unit) => ({\n\t\tapp: unit.name,\n\t\tname: unit.name,\n\t\tid: unit.id,\n\t\thost: unit.app,\n\t\tport: WORKER_PORT,\n\t\tref: validateImageRef(\n\t\t\timageRef(\n\t\t\t\toptions.identity,\n\t\t\t\tunit.name,\n\t\t\t\toptions.images.registry,\n\t\t\t\toptions.images.tag,\n\t\t\t),\n\t\t),\n\t\ttag: options.images.tag,\n\t\t...(options.images.mode === 'build'\n\t\t\t? {\n\t\t\t\t\tbuild: {\n\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${unit.name}`,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\n/**\n * The host an app answers on for a stage: the `gkm dev` edge's\n * `*.localhost` names for the local stage, and the stage's domain — by the\n * same rule a deploy follows — for any other.\n */\nfunction hostOf(\n\tname: string,\n\tapp: NormalizedAppConfig,\n\tworkspace: NormalizedWorkspace,\n\tresource: PlannedResource,\n\toptions: { local: boolean; stage: string },\n): string {\n\tif (options.local) return hostFor(resource, workspace.name);\n\n\treturn resolveHost(\n\t\tname,\n\t\tapp,\n\t\toptions.stage,\n\t\tworkspace.domains,\n\t\tisMainFrontendApp(name, app, workspace.apps),\n\t);\n}\n\n/** The compose document: the infrastructure, the apps, and the edge. */\nfunction stackFile(options: {\n\tproject: string;\n\tplan: Plan;\n\tinfra: readonly string[];\n\tapps: readonly StackApp[];\n\tworkers: readonly StackWorker[];\n\tcredentials: ContainerCredentials;\n\tstorage?: StackStorage;\n\tlogs?: StackLogs;\n\tredis?: StackRedis;\n\tbackups?: StackBackups;\n\thttps: number;\n\thttp: number;\n\tcomposeDir: string;\n\tbuildRoot: string;\n\tworkspaceRoot: string;\n\t/** Whether services read env files — not in a stack that only builds. */\n\tenvFiles: boolean;\n\tproxy: ComposeProxy;\n\t/** Behind the shared edge: each service it routes to, and its alias. */\n\tedge: ReadonlyMap<string, string>;\n}): StackFile {\n\tconst { project, plan, apps } = options;\n\t// What reconcile defines; OpenObserve is the stack's own.\n\tconst infra = options.infra.filter((name) => name !== LOGS_SERVICE);\n\n\t// Reconcile's definitions — images, health checks, volumes — with nothing\n\t// published to the host. Ports are allocation's business there; here the\n\t// edge is the only way in.\n\tconst derived = composeFor(\n\t\t{ ...plan, containers: [...infra] },\n\t\t{\n\t\t\tproject,\n\t\t\tports: Object.fromEntries(\n\t\t\t\tportKeys(infra, plan.fakes).map((key) => [key, 0]),\n\t\t\t),\n\t\t\tcredentials: options.credentials,\n\t\t},\n\t);\n\n\tconst services: Record<string, StackService> = {};\n\tconst volumes: Record<string, Record<string, never>> = {\n\t\t...derived.volumes,\n\t\t...(options.proxy === 'caddy'\n\t\t\t? { 'caddy-data': {}, 'caddy-config': {} }\n\t\t\t: {}),\n\t\t...(options.logs ? { 'openobserve-data': {} } : {}),\n\t};\n\n\tfor (const name of infra) {\n\t\tconst {\n\t\t\tports: _ports,\n\t\t\tdepends_on,\n\t\t\tprofiles: _profiles,\n\t\t\t...service\n\t\t} = derived.services[name]!;\n\t\tservices[name] = {\n\t\t\t...service,\n\t\t\t...(depends_on?.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tdepends_on.map((dep) => [dep, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tconst postgres = services.postgres;\n\tif (postgres) {\n\t\t// Loopback only, on a port Docker picks: gkm creates the databases and\n\t\t// roles and runs the migrations from this machine, and nothing else\n\t\t// should reach the database from outside the stack.\n\t\tpostgres.ports = ['127.0.0.1::5432'];\n\t}\n\n\tconst minio = services.minio;\n\tif (minio && options.storage) {\n\t\tminio.environment = {\n\t\t\t...minio.environment,\n\t\t\tMINIO_ROOT_USER: options.storage.user,\n\t\t\tMINIO_ROOT_PASSWORD: options.storage.password,\n\t\t};\n\t\t// Loopback only, like Postgres: gkm creates the buckets and their\n\t\t// policies from this machine. The apps reach it on the network, and a\n\t\t// browser through a file server's host on the edge.\n\t\tminio.ports = ['127.0.0.1::9000'];\n\t}\n\n\t// Its own definition rather than reconcile's: `gkm dev`'s Redis is an\n\t// open, unbounded scratch store; this one is a production cache.\n\tif (services[REDIS_SERVICE] && options.redis) {\n\t\tservices[REDIS_SERVICE] = redisService(options.redis);\n\t}\n\n\t// Started with the infrastructure, but nothing waits on it: an app whose\n\t// telemetry cannot be delivered still serves.\n\tif (options.logs) services[LOGS_SERVICE] = logsService(options.logs);\n\n\t// The stage's backups: on the stack's network, from nothing on the host.\n\tif (options.backups) {\n\t\tservices[BACKUPS_SERVICE] = backupsService(\n\t\t\toptions.backups,\n\t\t\toptions.envFiles,\n\t\t);\n\t}\n\n\tfor (const app of apps) {\n\t\tservices[app.name] = {\n\t\t\timage: app.ref,\n\t\t\t...(app.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\t...composeBuildPaths({\n\t\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\t\tdockerfile: app.build.dockerfile,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(app.build.args ? { args: app.build.args } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\t// A site is a bundle and reads nothing at runtime; a backend reads\n\t\t\t// exactly the keys in its own file.\n\t\t\t...(app.kind === 'rest-api'\n\t\t\t\t? {\n\t\t\t\t\t\tenv_file: [{ path: `./${app.name}.env`, format: 'raw' as const }],\n\t\t\t\t\t\t...(infra.length\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(app.port, app.kind === 'site' ? '/' : '/health'),\n\t\t};\n\t}\n\n\t// A worker: no route, no published port — its health check is Docker's.\n\tfor (const worker of options.workers) {\n\t\tservices[worker.name] = {\n\t\t\timage: worker.ref,\n\t\t\t...(worker.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: composeBuildPaths({\n\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\tdockerfile: worker.build.dockerfile,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\tenv_file: [{ path: `./${worker.name}.env`, format: 'raw' as const }],\n\t\t\t...(infra.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(worker.port, '/health'),\n\t\t};\n\t}\n\n\tif (options.proxy === 'caddy') {\n\t\tservices.caddy = {\n\t\t\timage: DEFAULT_IMAGES.caddy!,\n\t\t\trestart: 'unless-stopped',\n\t\t\tports: [`${options.https}:443`, `${options.http}:80`],\n\t\t\t// The Caddyfile and the stage's own certificate are inline configs,\n\t\t\t// added as the file is written (`withCaddyConfigs`).\n\t\t\tvolumes: ['caddy-data:/data', 'caddy-config:/config'],\n\t\t\tdepends_on: Object.fromEntries(apps.map((app) => [app.name, HEALTHY])),\n\t\t\thealthcheck: {\n\t\t\t\ttest: ['CMD', 'caddy', 'version'],\n\t\t\t\tinterval: '10s',\n\t\t\t\ttimeout: '5s',\n\t\t\t\tretries: 5,\n\t\t\t},\n\t\t};\n\t}\n\n\t// Behind the shared edge: each service it routes to joins its network,\n\t// under the alias the edge reaches it by — and keeps the stack's own,\n\t// with the same alias, which is how the stack's services reach it too.\n\t// Everything else — the databases, Redis, the workers — stays off it.\n\tfor (const [service, alias] of options.edge) {\n\t\tconst definition = services[service];\n\t\tif (!definition) continue;\n\t\tdefinition.networks = {\n\t\t\tdefault: { aliases: [alias] },\n\t\t\tedge: { aliases: [alias] },\n\t\t};\n\t}\n\n\tfor (const service of Object.values(services)) {\n\t\tif (!options.envFiles) delete service.env_file;\n\t\tservice.logging = {\n\t\t\tdriver: LOG_ROTATION.driver,\n\t\t\toptions: { ...LOG_ROTATION.options },\n\t\t};\n\t}\n\n\treturn {\n\t\tname: project,\n\t\tservices,\n\t\tvolumes,\n\t\t...(options.edge.size > 0\n\t\t\t? { networks: { edge: { name: EDGE_NETWORK, external: true as const } } }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * A build without a layout: the workspace is the build root, with pnpm.\n * What a caller that never looked at the filesystem gets.\n */\nfunction defaultLayout(root: string): ImageLayout {\n\treturn {\n\t\tbuildRoot: root,\n\t\tgkmRoot: '.',\n\t\ttools: {\n\t\t\tpackageManager: 'pnpm',\n\t\t\tturboVersion: TURBO_VERSION,\n\t\t\tmonorepo: true,\n\t\t},\n\t\tgkmPaths: ['gkm.config.*'],\n\t};\n}\n\n/** Render an app's env file: one `KEY=value` per line, read raw by compose. */\nexport function envFile(env: Readonly<Record<string, string>>): string {\n\treturn `${Object.entries(env)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join('\\n')}\\n`;\n}\n","/**\n * The server's shared Traefik edge, in Docker: started when a stack needs it,\n * and each stack's routes written to — and removed from — the directory it\n * watches.\n *\n * Everything goes through the server's Docker engine, never its filesystem:\n * the edge's static configuration is handed to it inline, and the directories\n * it watches are volumes each stack writes into with `docker exec`. So the\n * deploy runs anywhere that reaches the engine — a CI runner over SSH — and\n * nothing it writes depends on a path on that machine.\n *\n * gkm-edge (compose project)\n * traefik.yml its static configuration (inline config)\n * dynamic/<project>.yml one per stack: routers, services, middlewares\n * certs/<project>.crt|.key a stack's own certificate, where it has one\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { GkmError } from '../errors';\nimport type {\n\tComposeDocker,\n\tDockerEngine,\n\tPortHolder,\n\tStackRef,\n} from './docker.js';\nimport type { ComposeProxy } from './routes.js';\nimport {\n\tEDGE_CERTS_DIR,\n\tEDGE_DYNAMIC_DIR,\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 compose project, as docker is asked about it. */\nexport function edgeRef(\n\tfile: string,\n\toptions: Pick<StackRef, 'output' | 'signal' | 'host'> = {},\n): StackRef {\n\treturn {\n\t\tproject: EDGE_PROJECT,\n\t\tfile,\n\t\tcwd: dirname(file),\n\t\t...options,\n\t};\n}\n\n/** Writing to or removing from the edge's volumes failed. */\nexport class EdgeWriteFailed extends GkmError {\n\tconstructor(\n\t\treadonly path: string,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not write ${path} in the shared edge (${EDGE_PROJECT}): ${output.trim() || 'it is not running'}. ` +\n\t\t\t\t`Check it with \\`docker compose -p ${EDGE_PROJECT} ps\\` on the server, and run gkm compose again.`,\n\t\t);\n\t\tthis.name = 'EdgeWriteFailed';\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: {\n\t\tproject: string;\n\t\tproxy: ComposeProxy;\n\t\tports: EdgePorts;\n\t\tengine: DockerEngine;\n\t},\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(options.engine, 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/**\n * Write a file into the edge's running container whole or not at all: a\n * temporary name, then a rename. Not `.yml`: the edge reads only `.yml`,\n * `.yaml` and `.toml` files, so it never sees one half written.\n */\nasync function put(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tpath: string,\n\tcontent: string,\n\tmode: '600' | '644' = '644',\n): Promise<void> {\n\tconst result = await docker.exec(\n\t\tedge,\n\t\tEDGE_SERVICE,\n\t\t[\n\t\t\t'sh',\n\t\t\t'-c',\n\t\t\t'set -e; t=\"$1.tmp\"; cat > \"$t\"; chmod \"$2\" \"$t\"; mv \"$t\" \"$1\"',\n\t\t\t'sh',\n\t\t\tpath,\n\t\t\tmode,\n\t\t],\n\t\tcontent,\n\t);\n\tif (result.code !== 0) {\n\t\tthrow new EdgeWriteFailed(path, `${result.stderr}${result.stdout}`);\n\t}\n}\n\n/** Remove files from the edge's container; whether the first was there. */\nasync function remove(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tpaths: readonly string[],\n): Promise<boolean> {\n\tconst result = await docker.exec(edge, EDGE_SERVICE, [\n\t\t'sh',\n\t\t'-c',\n\t\t'e=1; [ -f \"$1\" ] && e=0; rm -f \"$@\"; exit $e',\n\t\t'sh',\n\t\t...paths,\n\t]);\n\treturn result.code === 0;\n}\n\n/**\n * The edge, up: its network and its container — started when it is not\n * running, and recreated when its configuration changed. Idempotent: on a\n * server where it already runs as configured, `up` changes nothing. Its\n * compose file is written to `file`, on this machine: compose reads it here.\n */\nexport async function ensureEdge(\n\tdocker: ComposeDocker,\n\toptions: {\n\t\tfile: string;\n\t\tports: EdgePorts;\n\t\tlogging: { driver: string; options: Record<string, string> };\n\t\thost?: string;\n\t\toutput?: StackRef['output'];\n\t\tsignal?: AbortSignal;\n\t},\n): Promise<string[]> {\n\tconst { file, ports } = options;\n\tconst staticConfig = traefikStaticFile(ports);\n\tconst content = edgeComposeFile({\n\t\tports,\n\t\tstaticConfig,\n\t\tlogging: options.logging,\n\t});\n\tawait mkdir(dirname(file), { recursive: true });\n\tif ((await readFile(file, 'utf-8').catch(() => undefined)) !== content) {\n\t\tawait writeFile(file, content);\n\t}\n\n\tconst ref = edgeRef(file, {\n\t\t...(options.host ? { host: options.host } : {}),\n\t\t...(options.output ? { output: options.output } : {}),\n\t\t...(options.signal ? { signal: options.signal } : {}),\n\t});\n\tawait docker.ensureNetwork(ref, EDGE_NETWORK);\n\tawait docker.up(ref, [EDGE_SERVICE]);\n\treturn [file];\n}\n\n/** A stack's routes, inside the edge's container. */\nexport function routesPath(project: string): string {\n\treturn `${EDGE_DYNAMIC_DIR}/${project}.yml`;\n}\n\nfunction certificatePaths(project: string): [string, string] {\n\treturn [\n\t\t`${EDGE_CERTS_DIR}/${project}.crt`,\n\t\t`${EDGE_CERTS_DIR}/${project}.key`,\n\t];\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. The certificate is read here and written\n * through the engine. The paths written, inside the edge.\n */\nexport async function writeEdgeRoutes(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tproject: string,\n\troutes: string,\n\tcertificate?: { certFile: string; keyFile: string },\n): Promise<string[]> {\n\tconst written: string[] = [];\n\tconst [crt, key] = certificatePaths(project);\n\tif (certificate) {\n\t\tawait put(docker, edge, crt, await readFile(certificate.certFile, 'utf-8'));\n\t\tawait put(\n\t\t\tdocker,\n\t\t\tedge,\n\t\t\tkey,\n\t\t\tawait readFile(certificate.keyFile, 'utf-8'),\n\t\t\t'600',\n\t\t);\n\t\twritten.push(crt, key);\n\t} else {\n\t\tawait remove(docker, edge, [crt, key]);\n\t}\n\tawait put(docker, edge, routesPath(project), routes);\n\twritten.push(routesPath(project));\n\treturn written;\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\n/**\n * Unregister a stack: its routes, then its certificate. Whether there was\n * anything to remove — false, too, when the edge is not running.\n */\nexport async function removeEdgeRoutes(\n\tdocker: ComposeDocker,\n\tedge: StackRef,\n\tproject: string,\n): Promise<boolean> {\n\tconst file = routesPath(project);\n\tconst there = await docker.exec(edge, EDGE_SERVICE, ['test', '-f', file]);\n\tif (there.code !== 0) return false;\n\t// Emptied by a rename before it is removed: a watcher that misses the\n\t// removal has still seen the stack's routes go.\n\tawait put(docker, edge, file, UNREGISTERED);\n\tawait remove(docker, edge, [file, ...certificatePaths(project)]);\n\treturn true;\n}\n","/**\n * What a deployed stage's stack generates once and keeps: its seed, each\n * `secret` construct's value, the log UI's root password where its telemetry\n * is self-hosted, and the stack's Redis password where a cache lives in it.\n *\n * Pure: the compose target writes the result back to the stage's store.\n */\n\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport {\n\ttype GeneratedSecrets,\n\twithGeneratedSecrets,\n} from '../deploy/generated.js';\nimport { initStageSecrets } from '../secrets/storage.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { resolveStageTelemetry } from '../telemetry/config';\nimport { usesTelemetry } from '../telemetry/edges';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { withLogsPassword } from './logs';\nimport { runsRedis, withRedisPassword } from './redis';\n\nexport function deployedStackSecrets(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\tstored: StageSecrets | null,\n\tmanifest: ConstructManifest,\n): GeneratedSecrets {\n\tconst withSeed = withGeneratedSecrets(\n\t\tstored ?? initStageSecrets(stage),\n\t\tmanifest,\n\t);\n\t// The log UI's root password, generated once like the seed, where the\n\t// stage's telemetry is self-hosted and the stage set none.\n\tconst telemetry = resolveStageTelemetry({\n\t\t...(workspace.deploy?.telemetry\n\t\t\t? { telemetry: workspace.deploy.telemetry }\n\t\t\t: {}),\n\t\tstage,\n\t\tlocal: false,\n\t\ttarget: 'compose',\n\t\truntime: 'server',\n\t\tselfHosted: true,\n\t\tused: usesTelemetry(manifest),\n\t});\n\tconst withLogs =\n\t\ttelemetry?.provider === 'self-hosted'\n\t\t\t? withLogsPassword(withSeed.secrets)\n\t\t\t: { secrets: withSeed.secrets, generated: [] };\n\t// The stack's Redis password, the same way, where a cache lives in it.\n\tconst withRedis = runsRedis(manifest, withLogs.secrets.custom ?? {})\n\t\t? withRedisPassword(withLogs.secrets)\n\t\t: { secrets: withLogs.secrets, generated: [] };\n\treturn {\n\t\tsecrets: withRedis.secrets,\n\t\tgenerated: [\n\t\t\t...withSeed.generated,\n\t\t\t...withLogs.generated,\n\t\t\t...withRedis.generated,\n\t\t],\n\t};\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 — the local stage on this machine's Docker, a deployed stage on its\n * server's, driven over SSH (`compose/server.ts`) from wherever the deploy\n * runs.\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 — through an SSH tunnel to a\n * server's loopback — 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 { BACKUPS_SERVICE, backupsRoleStatements } from '../../backups/service';\nimport {\n\ttype HostLookup,\n\tHostNotPointingAtServer,\n\tisLocalHost,\n\tisReservedStageKey,\n\trequiredServerAddress,\n\tSERVER_IPV4_KEY,\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\tedgeRef,\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 ComposeServer,\n\tcomposeServer,\n\tdockerHost,\n\ttype ServerAccess,\n\tsshAccess,\n\tsshTarget,\n} from '../../compose/server';\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\twithCaddyConfigs,\n} from '../../compose/stack';\nimport { EDGE_PROJECT, EDGE_SERVICE } from '../../compose/traefik';\nimport { currentActor } from '../../deploy/actor.js';\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 { appEnvKeys, workerEnvKeys } from '../../reconcile/apps.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 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\t/**\n\t * A deployed stage's server, beyond its Docker engine: the SSH check\n\t * before a deploy, and the tunnels its databases are reached through.\n\t */\n\tserver: ServerAccess;\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/**\n\t * The deployed stage's server, whose Docker engine — over SSH — runs the\n\t * stack. Absent for the local stage, and for a push, which builds here.\n\t */\n\tserver?: ComposeServer;\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\tserver: sshAccess,\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// 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// 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') {\n\t\tassertRedisClient(workspace, composed, manifest, runnables);\n\t}\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\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\t// Where the stack runs: a deployed stage on its server's engine, over\n\t// SSH — never this machine's. A push builds here and runs nothing.\n\t// A domain's stage names its address before anything else is said of\n\t// its server: it is the host SSH reaches too, unless config names one.\n\tif (!push && !stack.local) {\n\t\trequiredServerAddress(stage, workspace.domains?.[stage], secrets?.custom);\n\t}\n\tconst server = push\n\t\t? undefined\n\t\t: composeServer({\n\t\t\t\tstage,\n\t\t\t\tlocal: stack.local,\n\t\t\t\tconfig: workspace.deploy?.compose?.server,\n\t\t\t\tcustom: secrets?.custom,\n\t\t\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\t...(server ? { server } : {}),\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\t...(server ? { host: dockerHost(server) } : {}),\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// ============================================================================\n// ready\n// ============================================================================\n\n/**\n * What only a compose deploy checks before it changes anything, once the\n * stage's own keys are: the stage's own certificate is there, and every\n * public host points at the stage's server — its records written where a\n * provider holds them, then confirmed — before Caddy or Traefik ask Let's\n * Encrypt for a certificate it could not issue. A build-only run never asks.\n */\nexport async function readyCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\n\t// Read when the stack starts; one that is not there stops the run here,\n\t// before anything is written or started.\n\tif (stack.tls) {\n\t\tfor (const file of [stack.tls.certFile, stack.tls.keyFile]) {\n\t\t\tif (!existsSync(file)) throw new ComposeTlsFileMissing(ctx.stage, file);\n\t\t}\n\t}\n\n\tif (stack.local) return;\n\t// The server answers before anything is written — a DNS record included.\n\t// A dry run changes nothing anywhere, and connects to nothing.\n\tif (run.server && !ctx.dryRun && !run.push) {\n\t\tawait deps.server.check(run.server);\n\t}\n\tawait stageHostsDns(\n\t\tctx,\n\t\tdeps,\n\t\tstackHosts(stack).filter((host) => !isLocalHost(host)),\n\t\trun.secrets?.custom,\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 whose process reaches 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. A process that reaches no cache registers no\n * cache driver, so it needs no client.\n */\nfunction assertRedisClient(\n\tworkspace: NormalizedWorkspace,\n\tstack: ComposeStack,\n\tmanifest: ConstructManifest,\n\trunnables: Readonly<Record<string, readonly string[]>>,\n): void {\n\tif (!stack.plan.resources.some((r) => r.kind === 'cache')) return;\n\n\tconst cacheKeys = Object.values(manifest)\n\t\t.filter((d) => d.kind === 'cache')\n\t\t.flatMap((d) => d.provides ?? []);\n\tconst reachesCache = (keys: Set<string> | undefined) =>\n\t\tcacheKeys.some((key) => keys?.has(key));\n\n\tconst hosts = new Set([\n\t\t...stack.apps\n\t\t\t.filter(\n\t\t\t\t(app) =>\n\t\t\t\t\tapp.kind === 'rest-api' &&\n\t\t\t\t\treachesCache(appEnvKeys(manifest, app.name, runnables)),\n\t\t\t)\n\t\t\t.map((a) => a.name),\n\t\t...stack.workers\n\t\t\t.filter((worker) =>\n\t\t\t\treachesCache(workerEnvKeys(manifest, worker.id, runnables)),\n\t\t\t)\n\t\t\t.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 deploy's DNS step, for a deployed stage: its server's address — required\n * where it serves a real domain — then its own hosts written through each\n * domain's provider in `dns` where they differ, read back from it, and\n * recorded in the stage's state; hosts no provider writes resolved with the\n * system resolver. A dry run prints the plan and writes nothing, and warns\n * rather than stops.\n *\n * @throws {ServerAddressMissing} when the stage has a domain and no address\n * @throws {ServerAddressInvalid} for a value that is not an address\n * @throws {HostNotPointingAtServer} when a host is not the server\n */\nasync function stageHostsDns(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n\thosts: readonly string[],\n\tcustom: Readonly<Record<string, string>> | undefined,\n): Promise<void> {\n\tconst { workspace, stage } = ctx;\n\tconst server = requiredServerAddress(\n\t\tstage,\n\t\tworkspace.domains?.[stage],\n\t\tcustom,\n\t);\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 (!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 * The stage's secrets — and, for a deployed stage, everything it generates\n * once: its seed, and each declared secret and keyring. Kept only once the\n * run goes ahead (`provision`), so a dry run, or a tag that is not there,\n * leaves the stage's secrets as it found them.\n */\nasync function stageSecrets(\n\tctx: ComposeContext,\n\tmanifest: ConstructManifest,\n): Promise<{ secrets: StageSecrets | null; generated: string[] }> {\n\tconst stored = await ctx.secrets.read();\n\tif (ctx.stage === ctx.workspace.stages.local) {\n\t\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 [key, value] of Object.entries(secrets.custom ?? {})) {\n\t\tif (!isReservedStageKey(key)) ctx.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\tengine: ref,\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\tctx.logger.info(`\\n🌐 Starting the shared edge (${EDGE_PROJECT})…`);\n\t\trun.files.push(\n\t\t\t...(await ensureEdge(deps.docker, {\n\t\t\t\tfile: edgeFile(run),\n\t\t\t\tports,\n\t\t\t\t...(ref.host ? { host: ref.host } : {}),\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 tunnel = await reach(run, deps, 'minio', 9000);\n\tlet done: Awaited<ReturnType<typeof applyBuckets>>;\n\ttry {\n\t\tconst client = deps.buckets(tunnel.port, storage);\n\t\tdone = [\n\t\t\t...(await applyBuckets(client, storage.buckets)),\n\t\t\t...(await applyPolicies(client, storage.policies)),\n\t\t];\n\t} finally {\n\t\tawait tunnel.close();\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 tunnel = await reach(run, deps, 'postgres', 5432);\n\ttry {\n\t\tawait migrateAndSeed(ctx, run, deps, tunnel.port);\n\t} finally {\n\t\tawait tunnel.close();\n\t}\n}\n\n/**\n * A port a stack's service publishes on its engine's loopback, reachable\n * from this machine: the published port itself on the local stage, and on a\n * server an SSH tunnel to it over the deploy's own login — so Postgres and\n * MinIO are never published beyond the server's loopback.\n *\n * Migrations and seeds run here, in this process, with the project's own\n * Kysely — the way `gkm migrate` runs them — through that port. No image\n * needs to carry them, and nothing is run on the server but the stack.\n */\nasync function reach(\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tservice: string,\n\tinside: number,\n): Promise<{ port: number; close: () => Promise<void> }> {\n\tconst published = await deps.docker.port(run.ref, service, inside);\n\tif (!run.server) return { port: published, close: async () => {} };\n\treturn deps.server.tunnel(run.server, published);\n}\n\nasync function migrateAndSeed(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tport: number,\n): Promise<void> {\n\tconst { stack } = run;\n\tconst workspace: NormalizedWorkspace = ctx.workspace;\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 = [\n\t\t...postgresStatements(stack.plan, workspace.name, stack.credential.seed),\n\t\t// The backups service's own login: it reads, and writes nothing.\n\t\t...(stack.backups ? backupsRoleStatements(stack.backups) : []),\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(ref, 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\t// The local stage is never on the edge, which is a server's.\n\tconst edge = edgeRef(edgeFile(run), {\n\t\t...(ref.host ? { host: ref.host } : {}),\n\t\t...(ref.output ? { output: ref.output } : {}),\n\t});\n\tif (stack.proxy === 'traefik' && stack.traefik) {\n\t\tconst written = await writeEdgeRoutes(\n\t\t\tdeps.docker,\n\t\t\tedge,\n\t\t\tstack.project,\n\t\t\tstack.traefik,\n\t\t\tstack.tls,\n\t\t);\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 if (!stack.local) {\n\t\tawait removeEdgeRoutes(deps.docker, 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; a deployed stage's is its\n\t// server. Either is asked directly, on its published port, with each host\n\t// as SNI and Host: what is checked is its routing and its certificate,\n\t// whatever DNS — or a record not yet propagated — says.\n\tconst edge = stack.local\n\t\t? { connectTo: '127.0.0.1' }\n\t\t: run.server\n\t\t\t? { connectTo: run.server.host, connectPort: edgePorts(deps.env).https }\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, run.server);\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\tserver: ComposeServer | undefined,\n): void {\n\tconst lines = logsAccess(logs, {\n\t\tstage: ctx.stage,\n\t\tlocal,\n\t\tuser: server?.user ?? currentUser(),\n\t\thostname: server?.host ?? hostname(),\n\t\t...(server ? { known: true } : {}),\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\n/** The shared edge's compose file, as this machine hands it to compose. */\nfunction edgeFile(run: ComposeRun): string {\n\treturn join(run.dir, `${EDGE_PROJECT}.yml`);\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\t// Caddy's files go inline, in the compose file: nothing the stack runs\n\t// mounts a path on this machine, so the same file runs on a server's\n\t// engine over SSH. With the stage's own key in it, it is owner-only.\n\tconst tls =\n\t\tstack.proxy === 'caddy' && stack.tls\n\t\t\t? {\n\t\t\t\t\tcert: await readFile(stack.tls.certFile, 'utf-8'),\n\t\t\t\t\tkey: await readFile(stack.tls.keyFile, 'utf-8'),\n\t\t\t\t}\n\t\t\t: undefined;\n\tconst compose =\n\t\tstack.caddyfile !== undefined\n\t\t\t? withCaddyConfigs(stack.compose, {\n\t\t\t\t\tcaddyfile: stack.caddyfile,\n\t\t\t\t\t...(tls ? { tls } : {}),\n\t\t\t\t})\n\t\t\t: stack.compose;\n\tawait write(\n\t\tjoin(dir, 'docker-compose.yml'),\n\t\tcomposeYaml(stack, compose),\n\t\ttls ? 0o600 : 0o644,\n\t);\n\t// For reading: the proxy's configuration — the stack's own Caddy's, or a\n\t// 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 copy of the stage's certificate an older gkm mounted from here.\n\tawait rm(join(dir, 'tls'), { recursive: true, force: true });\n\t// Env files stay on this machine: compose reads each one here and sends\n\t// its values in the call that creates the container — on a server's\n\t// engine too, where no secret is ever written as a file.\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// The backups image's build context, and its key — read from its own env\n\t// file like any app's, never from the host.\n\tif (stack.backups) {\n\t\tfor (const [name, content] of Object.entries(stack.backups.files)) {\n\t\t\tawait write(join(dir, BACKUPS_SERVICE, name), content);\n\t\t}\n\t\tif (stack.compose.services[BACKUPS_SERVICE]?.env_file) {\n\t\t\tawait write(\n\t\t\t\tjoin(dir, `${BACKUPS_SERVICE}.env`),\n\t\t\t\tenvFile(stack.backups.env),\n\t\t\t\t0o600,\n\t\t\t);\n\t\t}\n\t} else {\n\t\tawait rm(join(dir, BACKUPS_SERVICE), { recursive: true, force: true });\n\t\tawait rm(join(dir, `${BACKUPS_SERVICE}.env`), { force: true });\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(\n\tstack: ComposeStack,\n\tcompose: ComposeStack['compose'],\n): 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(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\tif (run.server) {\n\t\tctx.logger.info(` → ${sshTarget(run.server)} (docker over ssh)`);\n\t}\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\tif (stack.backups) {\n\t\tctx.logger.info(\n\t\t\t` ${BACKUPS_SERVICE.padEnd(12)} ${stack.backups.databases.map((d) => d.file).join(', ')} — ${stack.backups.backups.describe}, to ${stack.backups.prefix}/`,\n\t\t);\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 — the local stage on the machine that runs the deploy, a deployed\n * stage on its server's Docker engine, over SSH (`deploy.compose.server`).\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 * - `ready`: a deploy's own checks, after the stage's keys are — the stage's\n * certificate, its server's address, and every public host's DNS\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: no\n * readiness check runs, so a stage whose keys the deploy has yet to write\n * still builds.\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\treadyCompose,\n\treleaseCompose,\n\tvalidateCompose,\n\tverifyCompose,\n} from './phases';\n\nexport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\ttype HealthRequest,\n\tHealthRequestTimedOut,\n} from './health';\nexport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n\tstackOverrideFile,\n} from './phases';\n\nexport interface ComposeTargetOptions\n\textends Partial<ComposeDeps>,\n\t\tComposeRunOptions {\n\t/** Handed the finished run — `gkm compose` prints and returns from it. */\n\treport?: (run: ComposeRun) => void;\n}\n\n/** The compose target, with its Docker, bundler and probe as given. */\nexport function composeTarget(\n\toptions: ComposeTargetOptions = {},\n): DeployTarget<undefined, ComposeRun> {\n\tconst { mode, push, pin, report, ...given } = options;\n\tconst deps: ComposeDeps = { ...defaultDeps, ...given };\n\n\treturn defineTarget<undefined, ComposeRun>({\n\t\tname: 'compose',\n\t\truntime: 'server',\n\t\tcapabilities: {\n\t\t\trollback: false,\n\t\t\tmigrations: 'target',\n\t\t\timages: true,\n\t\t\t// The local stage runs where the deploy does — the `gkm dev`\n\t\t\t// 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`, which\n\t\t// docker sends with each pull — on a server's engine too.\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\tready: (ctx, run) => readyCompose(ctx, run, deps),\n\t\tplan: (ctx, run) => planCompose(ctx, run),\n\t\tprovision: (ctx, run) => provisionCompose(ctx, run, deps),\n\t\tbuild: (ctx, run) => buildCompose(ctx, run, deps),\n\t\trelease: (ctx, run) => releaseCompose(ctx, run, deps),\n\t\tverify: (ctx, run) => verifyCompose(ctx, run, deps),\n\t\tresult: (ctx, run) => {\n\t\t\treport?.(run);\n\t\t\treturn composeResult(ctx, run);\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,MAAM,QAAsE;CAC3E,SAAS;CACT,QAAQ;EAAC;EAAU;EAAG;CAAC;CACvB,QAAQ;AACT;;;;;AAMA,SAAgB,UACf,QACA,QAA2B,CAAC,GACI;CAChC,IAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO,KAAA;CAC5D,OAAO;EACN,GAAG,QAAQ;EACX,GAAG;EACH,GAAI,OAAO,OAAO,EAAE,aAAa,OAAO,KAAK,IAAI,CAAC;CACnD;AACD;;AAGA,SAAS,WAAW,OAAiB,OAAuC;CAC3E,MAAM,MAAM,UAAU,OAAO,KAAK;CAClC,OAAO;EACN,KAAK,MAAM;EACX,OAAO,MAAM,MAAM,UAAU;EAC7B,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACrB,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;CAChD;AACD;;AAyHA,SAAgB,eAAe,SAAyB;CACvD,OAAO,GAAG,QAAQ;AACnB;;;;;AAMA,SAAgB,eAAe,QAA0B;CACxD,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,SAAS,OAAO,SAC1B,2CACD,GAAG;EACF,MAAM,QAAQ,OAAO,MAAM,EAAE;EAC7B,MAAM,OAAO,MAAM,KAAK,OAAO,MAAM,EAAE,IAAI;EAC3C,KAAK,IAAI,OAAO,OAAO,QAAQ,MAAM,QAAQ,MAAM,IAAI,IAAI;CAC5D;CACA,OAAO,CAAC,GAAG,KAAK;AACjB;;;;;AAMA,SAAgB,cACf,QACA,QACqB;CACrB,MAAM,QAAQ,IAAI,OACjB,qCAAqC,OAAO,KAC7C,CAAC,CAAC,KAAK,MAAM;CACb,OAAO,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAA;AACnC;;AAGA,SAAgB,YAAY,QAAgB,MAA4B;CACvE,OAAO,OACL,MAAM,IAAI,CAAC,CACX,OAAO,OAAO,CAAC,CACf,KAAK,SAAS,KAAK,MAAM,GAAI,CAAC,CAAC,CAC/B,QAAQ,OAAO,SAAS,QAAQ,eAAe,MAAM,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CACtE,KAAK,CAAC,YAAY,IAAI,SAAS,cAAc;EAC7C;EACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC9B,EAAE;AACJ;;AAGA,MAAM,iBAAiB;;AAGvB,IAAa,oBAAb,cAAuCA,eAAAA,SAAS;CAErC;CACA;CAFV,YACC,QACA,QACC;EACD,MACC,2BAA2B,OAAO,kDAChB,OAAO,KAAK,KAAK,UAAU,8BAC3B,OAAO,8BAC1B;EAPS,KAAA,SAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,qBAAb,cAAwCA,eAAAA,SAAS;CAEtC;CACA;CACA;CAHV,YACC,SACA,QACA,QACC;EACD,MACC,IAAI,QAAQ,+BAA+B,OAAO,iBAAiB,OAAO,KAAK,KAAK,UAAU,yDAC/F;EANS,KAAA,UAAA;EACA,KAAA,SAAA;EACA,KAAA,SAAA;EAKT,KAAK,OAAO;CACb;AACD;;;;;;;AAQA,SAAgB,mBAAmB,KAAsB;CACxD,MAAM,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC;CAC7B,IAAI,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,mBAAmB,KAAK,KAAK,GAAG,OAAO;CAClE,MAAM,OAAO,MAAM,QAAQ,SAAS,EAAE;CACtC,OAAO,SAAS,eAAe,wBAAwB,KAAK,IAAI;AACjE;;AAGA,IAAa,oBAAb,cAAuCA,eAAAA,SAAS;CAErC;CACA;CAFV,YACC,KACA,QACC;EACD,MACC,UAAU,IAAI,sEACA,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,KAAK,KAAK,UAAU,4DAChB,IAAI,IAChE;EAPS,KAAA,MAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,aAAa,QAAoC;CAEhE,OAAO,CADU,GAAG,OAAO,SAAS,gCAAgC,CACvD,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG;AACzB;AAEA,SAAS,QAAQ,OAAiB,MAAmC;CACpE,OAAO;EACN;EACA;EACA,MAAM;EACN;EACA,MAAM;EACN,IAAI,MAAM,aAAa,CAAC,EAAA,CAAG,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC;EACzD,GAAG;CACJ;AACD;;AAGA,SAAS,QACR,SACA,MACA,UAA2E,CAAC,GACT;CACnE,MAAM,EAAE,YAAY,QAAW;CAC/B,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,SAAA,GAAQC,mBAAAA,MAAAA,CAAM,SAAS,CAAC,GAAG,IAAI,GAAG;GACvC,OAAO;IAAC,QAAQ,UAAU,KAAA,IAAY,WAAW;IAAQ;IAAQ;GAAM;GACvE,OAAO;GACP,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC3C,CAAC;EACD,IAAI,QAAQ,UAAU,KAAA,GAAW,MAAM,OAAO,IAAI,QAAQ,KAAK;EAC/D,IAAI,SAAS;EACb,IAAI,SAAS;EACb,MAAM,QAAQ,GAAG,SAAS,UAAkB;GAC3C,UAAU,MAAM,SAAS;EAC1B,CAAC;EACD,MAAM,QAAQ,GAAG,SAAS,UAAkB;GAC3C,UAAU,MAAM,SAAS;EAC1B,CAAC;EACD,MAAM,QAAQ,iBAAiB,MAAM,KAAK,SAAS,GAAG,SAAS;EAC/D,MAAM,QAAQ;EACd,MAAM,GAAG,UAAU,UAAU;GAC5B,aAAa,KAAK;GAClB,OAAO,KAAK;EACb,CAAC;EACD,MAAM,GAAG,UAAU,SAAS;GAC3B,aAAa,KAAK;GAClB,QAAQ;IAAE;IAAM;IAAQ;GAAO,CAAC;EACjC,CAAC;CACF,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,kBAAkB,QAAyB;CAC1D,OAAO,mFAAmF,KACzF,MACD;AACD;AAEA,MAAa,gBAA+B;CAC3C,MAAM,OAAO,KAAK;EACjB,MAAM,EAAE,MAAM,QAAQ,WAAW,MAAM,QAAQ,UAAU;GACxD;GACA;GACA,GAAI,mBAAmB,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC;GAChD;EACD,CAAC;EACD,IAAI,SAAS,GAAG,OAAO;GAAE;GAAK,QAAQ;EAAQ;EAE9C,MAAM,SAAS,GAAG,OAAO,IAAI,SAAS,KAAK;EAC3C,OAAO,kBAAkB,MAAM,IAC5B;GAAE;GAAK,QAAQ;EAAU,IACzB;GAAE;GAAK,QAAQ;GAAe,QAAQ;EAAO;CACjD;CAEA,MAAM,MAAM,OAAO,UAAU;EAC5B,MAAMC,YAAAA,IACL,UACA,QAAQ,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC,GACrC,WAAW,OAAO;GAAE,GAAG,QAAQ;GAAK,iBAAiB;EAAI,CAAC,CAC3D;CACD;CAEA,MAAM,KAAK,OAAO,UAAU;EAC3B,MAAMA,YAAAA,IACL,UACA,QAAQ,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,GACpC,WAAW,KAAK,CACjB;CACD;CAEA,MAAM,GAAG,OAAO,UAAU;EACzB,MAAMA,YAAAA,IACL,UACA,QAAQ,OAAO;GACd;GACA;GACA;GACA,kBAAkB;GAGlB,GAAI,WAAW,CAAC,IAAI,CAAC,kBAAkB;GACvC,GAAI,YAAY,CAAC;EAClB,CAAC,GACD,WAAW,KAAK,CACjB;CACD;CAEA,MAAM,KAAK,OAAO;EACjB,MAAMA,YAAAA,IAAI,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,GAAG,WAAW,KAAK,CAAC;CAChE;CAEA,MAAM,KAAK,OAAO,SAAS,QAAQ;EAClC,MAAM,MAAM,UAAU,KAAK;EAC3B,MAAM,SAAS,MAAMC,YAAAA,UACpB,UACA,QAAQ,OAAO;GAAC;GAAQ;GAAS,OAAO,MAAM;EAAC,CAAC,GAChD;GACC,KAAK,MAAM;GACX,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;GACrB,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAChD,CACD;EAEA,MAAM,OAAO,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;EAClD,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,QAAQ,GACtC,MAAM,IAAI,mBAAmB,SAAS,QAAQ,MAAM;EAErD,OAAO;CACR;CAEA,MAAM,OAAO,OAAO,SAAS;EAC5B,MAAM,MAAM,UAAU,KAAK;EAC3B,MAAM,EAAE,MAAM,WAAW,MAAM,QAC9B,UACA,QAAQ,OAAO;GAAC;GAAM;GAAY;GAAe;EAAO,CAAC,GACzD,MAAM,EAAE,IAAI,IAAI,CAAC,CAClB;EACA,IAAI,SAAS,GAAG,OAAO,KAAA;EACvB,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAA;CACxC;CAEA,MAAM,QAAQ,OAAO,SAAS,MAAM,IAAI;EACvC,OAAA,GAAMC,iBAAAA,MAAAA,EAAAA,GAAMC,UAAAA,QAAAA,CAAQ,EAAE,GAAG,EAAE,WAAW,KAAK,CAAC;EAC5C,MAAMH,YAAAA,IACL,UACA,QAAQ,OAAO;GAAC;GAAM,GAAG,QAAQ,GAAG;GAAQ;EAAE,CAAC,GAC/C,WAAW,KAAK,CACjB;CACD;CAEA,MAAM,KAAK,OAAO,KAAK;EAGtB,MAAM,SAAS,MAAMC,YAAAA,UAAU,UAAU,CAAC,QAAQ,GAAG,GAAG;GACvD,KAAK,MAAM;GACX,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAChD,CAAC;EACD,MAAM,SAAS,aAAa,MAAM;EAClC,IAAI,CAAC,QAAQ,MAAM,IAAI,kBAAkB,KAAK,MAAM;EACpD,OAAO;CACR;CAEA,MAAM,OAAO,QAAQ,KAAK;EACzB,MAAM,MAAM,UAAU,MAAM;EAC5B,MAAM,EAAE,MAAM,WAAW,MAAM,QAC9B,UACA;GAAC;GAAS;GAAW;GAA0C;EAAG,GAClE,MAAM,EAAE,IAAI,IAAI,CAAC,CAClB;EACA,IAAI,SAAS,GAAG,OAAO,KAAA;EAEvB,MAAM,CAAC,OAAO,MAAM,MAAM,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG;EACjD,MAAM,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE,CAAE,QAAQ,iBAAiB,EAAE;EACjE,IAAI;GACH,MAAM,UAAU,KAAK,MAAM,IAAI;GAC/B,MAAM,QAAQ,MAAM,QAAQ,OAAO,IAChC,QAAQ,MACP,UACA,OAAO,UAAU,YAAY,MAAM,WAAW,GAAG,WAAW,EAAE,CAChE,IACC,KAAA;GACH,IAAI,OAAO,OAAO,MAAM,MAAM,WAAW,SAAS,CAAC;EACpD,QAAQ,CAER;EACA,OAAO,MAAM,KAAA;CACd;CAEA,MAAM,cAAc,QAAQ,MAAM;EACjC,MAAM,MAAM,UAAU,MAAM;EAC5B,MAAM,UAAU,MAAM,EAAE,IAAI,IAAI,CAAC;EACjC,MAAM,EAAE,SAAS,MAAM,QACtB,UACA;GAAC;GAAW;GAAW;EAAI,GAC3B,OACD;EACA,IAAI,SAAS,GAAG;EAChB,MAAM,UAAU,MAAM,QACrB,UACA;GAAC;GAAW;GAAU;EAAI,GAC1B,OACD;EAEA,IAAI,QAAQ,SAAS,KAAK,CAAC,iBAAiB,KAAK,QAAQ,MAAM,GAC9D,MAAM,IAAI,oBAAoB,MAAM,QAAQ,MAAM;CAEpD;CAEA,MAAM,WAAW,QAAQ,MAAM;EAC9B,MAAM,MAAM,UAAU,MAAM;EAC5B,MAAM,EAAE,WAAW,MAAM,QACxB,UACA;GACC;GACA;GACA;EACD,GACA,MAAM,EAAE,IAAI,IAAI,CAAC,CAClB;EACA,OAAO,YAAY,QAAQ,IAAI;CAChC;CAEA,MAAM,KAAK,OAAO,SAAS,SAAS,OAAO;EAC1C,MAAM,MAAM,UAAU,KAAK;EAC3B,MAAM,UAAU,MAAM,EAAE,IAAI,IAAI,CAAC;EAGjC,MAAM,EAAE,QAAQ,QAAQ,MAAM,QAC7B,UACA;GACC;GACA;GACA;GACA,oCAAoC,MAAM;GAC1C;GACA,oCAAoC;EACrC,GACA,OACD;EACA,MAAM,YAAY,IAAI,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;EACzC,IAAI,CAAC,WACJ,OAAO;GAAE,MAAM;GAAM,QAAQ;GAAI,QAAQ,GAAG,QAAQ;EAAiB;EAEtE,OAAO,QACN,UACA;GAAC;GAAQ,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI;GAAI;GAAW,GAAG;EAAO,GACtE;GAAE,GAAG;GAAS,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EAAG,CACzD;CACD;CAEA,MAAM,UAAU,QAAQ,SAAS,SAAS;EACzC,MAAM,MAAM,UAAU,MAAM;EAC5B,MAAM,EAAE,WAAW,MAAM,QACxB,UACA;GACC;GACA;GACA,oCAAoC;GACpC;GACA,oCAAoC;GACpC;GACA;EACD,GACA,MAAM,EAAE,IAAI,IAAI,CAAC,CAClB;EACA,MAAM,CAAC,IAAI,SAAS,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,GAAI,KAAK,CAAC;EAClE,OAAO,MAAM,QAAQ;GAAE;GAAI;EAAM,IAAI,KAAA;CACtC;CAEA,MAAM,UAAU,QAAQ,SAAS,SAAS,QAAQ;EACjD,MAAM,MAAM,UAAU,MAAM;EAC5B,MAAM,EAAE,MAAM,QAAQ,WAAW,MAAM,QACtC,UACA;GACC;GACA;GACA,oCAAoC;GACpC;GACA,oCAAoC;GACpC;GACA;EACD,GACA,MAAM,EAAE,IAAI,IAAI,CAAC,CAClB;EAEA,IAAI,SAAS,GACZ,MAAM,IAAI,kBAAkB,OAAO,QAAQ,gBAAgB,MAAM;EAElE,OAAO,cAAc,QAAQ,MAAM;CACpC;CAEA,QAAQ,QAAQ,SAAS;EACxB,OAAO,WACN;GACC;GACA;GACA,GAAI,QAAQ,QAAQ,CAAC,IAAI,IAAI,CAAC;GAC9B;GACA,QAAQ;GACR,GAAG,OAAO,KAAK,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC;GAChE;GACA;GACA,QAAQ;GACR,GAAG,QAAQ;EACZ,GACA;GACC,KAAK,UAAU,QAAQ,EAAE,GAAG,QAAQ,IAAI,CAAC,KAAK,QAAQ;GACtD,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAChD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACpD,CACD;CACD;AACD;;AAGA,SAAS,WACR,MACA,UAII,CAAC,GACa;CAClB,MAAM,SAAS,MAAM,QAAQ,UAAU;CACvC,MAAM,MAAM,MAAM,QAAQ,MAAM,IAAI,SAAS;EAAC;EAAQ;EAAQ;CAAM;CACpE,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,SAAA,GAAQF,mBAAAA,MAAAA,CAAM,UAAU,CAAC,GAAG,IAAI,GAAG;GACxC,OAAO;IAAC,QAAQ,QAAQ,SAAS;IAAU,IAAI;IAAI,IAAI;GAAE;GACzD,KAAK,QAAQ,OAAO,QAAQ;GAC5B,OAAO;EACR,CAAC;EACD,IAAI,QAAQ,SAAS,MAAM,OAAO;GACjC,QAAQ,MAAM,GAAG,UAAU,UAAU,MAAM,OAAO,QAAQ,KAAK,CAAC;GAChE,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC;GAChC,QAAQ,MAAM,KAAK,MAAM,KAAK;EAC/B;EACA,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAC/C,CAAC;AACF;;AAGA,IAAa,sBAAb,cAAyCD,eAAAA,SAAS;CAEvC;CACA;CAFV,YACC,SACA,QACC;EACD,MACC,wCAAwC,QAAQ,kBAAkB,OAAO,KAAK,KAAK,UAAU,oDAAoD,QAAQ,kBAC1J;EALS,KAAA,UAAA;EACA,KAAA,SAAA;EAKT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;;;;;;;;AC9nBA,IAAa,uBAAb,cAA0CM,eAAAA,SAAS;CAExC;CACA;CAFV,YACC,OACA,SACC;EACD,MACC,YAAY,WACT,IAAI,MAAM,yMAGL,MAAM,uDACRC,kBAAAA,gBAAgB,2BAA2BA,kBAAAA,gBAAgB,kBACnD,MAAM,6BACjB,yBAAyB,MAAM,uBAAuB,MAAM,WACzDA,kBAAAA,gBAAgB,iDAChBA,kBAAAA,gBAAgB,kBAAkB,MAAM,kCAClB,MAAM,OACnC;EAfS,KAAA,QAAA;EACA,KAAA,UAAA;EAeT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,2BAAb,cAA8CD,eAAAA,SAAS;CAE5C;CACA;CAFV,YACC,QACA,QACC;EACD,MACC,6BAA6B,OAAO,uBAAuB,OAAO,KAAK,KAAK,UAAU,sBACjE,OAAO,0JAG7B;EARS,KAAA,SAAA;EACA,KAAA,SAAA;EAQT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyCA,eAAAA,SAAS;CAEvC;CACA;CACA;CAHV,YACC,QACA,YACA,QACC;EACD,MACC,6CAA6C,WAAW,MAAM,OAAO,cACtD,OAAO,KAAK,KAAK,UAAU,+SAK3C;EAXS,KAAA,SAAA;EACA,KAAA,aAAA;EACA,KAAA,SAAA;EAUT,KAAK,OAAO;CACb;AACD;;;;;;;;AASA,SAAgB,cAAc,SAKA;CAC7B,MAAM,EAAE,UAAU;CAClB,IAAI,QAAQ,OAAO,OAAO,KAAA;CAC1B,MAAM,SAAS,QAAQ,SAAS;CAChC,IAAI,CAAC,QAAQ,MAAM,IAAI,qBAAqB,OAAO,QAAQ;CAC3D,MAAM,OAAO,OAAO,QAAQ,QAAQ,SAAA,kBAAyB,EAAE,KAAK;CACpE,IAAI,CAAC,MAAM,MAAM,IAAI,qBAAqB,OAAO,MAAM;CACvD,OAAO;EAAE,MAAM,OAAO;EAAM;EAAM,MAAM,OAAO,QAAQ;CAAG;AAC3D;;AAGA,SAAgB,UAAU,QAA+B;CACxD,OAAO,GAAG,OAAO,KAAK,GAAG,OAAO;AACjC;;AAGA,SAAgB,WAAW,QAA+B;CACzD,MAAM,OAAO,OAAO,KAAK,SAAS,GAAG,IAAI,IAAI,OAAO,KAAK,KAAK,OAAO;CACrE,OAAO,SAAS,OAAO,KAAK,GAAG,OAAO,OAAO,SAAS,KAAK,KAAK,IAAI,OAAO;AAC5E;;AAGA,SAAS,QAAQ,QAAiC;CACjD,OAAO;EACN;EACA;EACA;EACA;EACA;EACA,OAAO,OAAO,IAAI;EAClB,UAAU,MAAM;CACjB;AACD;AAoBA,eAAe,gBAAiC;CAC/C,MAAM,UAAA,GAASE,SAAAA,aAAAA,CAAa;CAC5B,MAAM,IAAI,SAAe,SAAS,WAAW;EAC5C,OAAO,KAAK,SAAS,MAAM;EAC3B,OAAO,OAAO,GAAG,aAAa,OAAO;CACtC,CAAC;CACD,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,IAAI,SAAS,YAAY,OAAO,MAAM,OAAO,CAAC;CACpD,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO;CACpD,OAAO,QAAQ;AAChB;AAEA,SAAS,SAAS,MAAgC;CACjD,OAAO,IAAI,SAAS,YAAY;EAC/B,MAAM,UAAA,GAASC,SAAAA,iBAAAA,CAAiB;GAAE,MAAM;GAAa;EAAK,CAAC;EAC3D,OAAO,KAAK,iBAAiB;GAC5B,OAAO,QAAQ;GACf,QAAQ,IAAI;EACb,CAAC;EACD,OAAO,KAAK,eAAe,QAAQ,KAAK,CAAC;CAC1C,CAAC;AACF;;AAGA,MAAa,YAA0B;CACtC,MAAM,QAAQ;EACb,OAAO,IAAI,SAAS,SAAS,WAAW;GACvC,MAAM,SAAA,GAAQC,mBAAAA,MAAAA,CACb,OACA;IACC,GAAG,QAAQ,MAAM;IACjB;IACA;IACA;IACA;GACD,GACA,EAAE,OAAO;IAAC;IAAU;IAAU;GAAM,EAAE,CACvC;GACA,IAAI,SAAS;GACb,MAAM,OAAO,GAAG,SAAS,UAAkB;IAC1C,UAAU,MAAM,SAAS;GAC1B,CAAC;GACD,MAAM,GAAG,UAAU,UAClB,OAAO,IAAI,yBAAyB,UAAU,MAAM,GAAG,MAAM,OAAO,CAAC,CACtE;GACA,MAAM,GAAG,UAAU,SAClB,SAAS,IACN,QAAQ,IACR,OAAO,IAAI,yBAAyB,UAAU,MAAM,GAAG,MAAM,CAAC,CAClE;EACD,CAAC;CACF;CAEA,MAAM,OAAO,QAAQ,YAAY;EAChC,MAAM,OAAO,MAAM,cAAc;EACjC,MAAM,SAAA,GAAQA,mBAAAA,MAAAA,CACb,OACA;GACC;GACA;GACA;GAIA;GACA;GACA;GACA,aAAa,KAAK,aAAa;GAC/B,GAAG,QAAQ,MAAM;EAClB,GACA,EAAE,OAAO;GAAC;GAAU;GAAU;EAAM,EAAE,CACvC;EACA,IAAI,SAAS;EACb,IAAI,SAAS;EACb,MAAM,OAAO,GAAG,SAAS,UAAkB;GAC1C,UAAU,MAAM,SAAS;EAC1B,CAAC;EACD,MAAM,GAAG,cAAc;GACtB,SAAS;EACV,CAAC;EACD,MAAM,GAAG,UAAU,UAAU;GAC5B,SAAS;GACT,UAAU,MAAM;EACjB,CAAC;EACD,MAAM,QAAQ,YAAY;GACzB,IAAI,QAAQ;GACZ,MAAM,OAAO,IAAI,SAAS,YAAY,MAAM,KAAK,QAAQ,OAAO,CAAC;GACjE,MAAM,KAAK,SAAS;GACpB,MAAM;EACP;EAIA,KAAK,IAAI,UAAU,GAAG,UAAU,KAAK,WAAW;GAC/C,IAAI,QAAQ;GACZ,IAAI,MAAM,SAAS,IAAI,GAAG,OAAO;IAAE;IAAM;GAAM;GAC/C,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;EACxD;EACA,MAAM,MAAM;EACZ,MAAM,IAAI,oBAAoB,UAAU,MAAM,GAAG,YAAY,MAAM;CACpE;AACD;;;;;;;;;;;;;;;;AChPA,MAAa,gBAAgB;;AAS7B,SAAS,QAAQ,EAAE,SAAS,QAA0B;CACrD,OAAO,GAAG,QAAQ,GAAG;AACtB;;AAGA,SAAgB,cACf,QACA,SACS;CACT,MAAM,EAAE,QAAQ;CAChB,MAAM,SACL,IAAI,SAAS,aACV;;;;;KAMA,QAAQ,QACP;SACG,QAAQ,MAAM;KAEjB;CAEL,MAAM,cACL,IAAI,SAAS,aACV;;IAGA,IAAI,SAAS,UACZ;OACC,IAAI,SAAS,GAAG,IAAI,QAAQ;IAE7B;CAEL,MAAM,SAAS,OAAO,KACpB,EACA,MACA,WACA,QACA,OACA,gBACK,WAAW,KAAK,IAAI,YAAY;;;mBAGrBC,oBAAAA,iBAAiB;EAEnC,QACG;;;yBAGqB,MAAM,KAAK,GAAG,EAAE;;IAGrC,KAEH,SACG;;;iBAGa,UAAU,IAAI,OAAO,CAAC,CAAC,KAAK,GAAG,EAAE;YACtC,OAAO;;MAGf;;;iBAGa,UAAU,IAAI,OAAO,CAAC,CAAC,KAAK,GAAG,IAC9C,YACG;;;;MAKA,KAEJ;EAEA;CAGA,OAAO,GAAG,SAAS,SAAS,GAAG,OAAO,QAAQ,KAAK,OAAO,KAAK,MAAM,EAAE;AACxE;AAEA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;ACjFf,SAAgB,QAAQ,KAAa,OAAuB;CAC3D,OAAO,GAAG,IAAI,GAAG;AAClB;;AAGA,IAAa,mBAAb,cAAsCC,eAAAA,SAAS;CAEpC;CACA;CAFV,YACC,KACA,MACC;EACD,MACC,iCAAiC,KAAK,WAAW,IAAI,aAAa,GAAG,KAAK,OAAO,OAAO,OAAO,IAAI,QAClG,KAAK,KAAK,QAAQ,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,IACzC,0CAA0C,IAAI,mGAEhD;EARS,KAAA,MAAA;EACA,KAAA,OAAA;EAQT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyCA,eAAAA,SAAS;CAEvC;CACA;CAFV,YACC,KACA,QACC;EACD,MACC,oCAAoC,IAAI,IAAI,UAAU,YAAY,yIAGnE;EAPS,KAAA,MAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;AAYA,eAAsB,kBACrB,QACA,KACA,QACgB;CAChB,MAAM,UAAU,MAAM,QAAQ,IAC7B,OAAO,KAAK,UAAU,OAAO,OAAO,MAAM,GAAG,CAAC,CAC/C;CAEA,MAAM,cAAc,QAAQ,MAAM,WAAW,OAAO,WAAW,aAAa;CAC5E,IAAI,aAAa,WAAW,eAC3B,MAAM,IAAI,oBAAoB,YAAY,KAAK,YAAY,MAAM;CAGlE,MAAM,UAAU,QACd,QAAQ,WAAW,OAAO,WAAW,SAAS,CAAC,CAC/C,KAAK,WAAW,OAAO,GAAG;CAC5B,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,iBAAiB,KAAK,OAAO;AAChE;;;;;;;;AASA,IAAa,mBAAb,cAAsCA,eAAAA,SAAS;CAGpC;CAEA;CAJV,YAEC,WAEA,KACC;EACD,MACC,GAAG,cAAc,SAAS,YAAY,UAAU,wEAC3C,IAAI,aAAa,cAAc,SAAS,cAAc,cAAc,uFAEvE,cAAc,SACZ,qDACA,GACL;EAXS,KAAA,YAAA;EAEA,KAAA,MAAA;EAUT,KAAK,OAAO;CACb;AACD;;AAUA,SAAgB,UAAU,KAAa,QAAwB;CAC9D,OAAO,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG;AAChC;;AAGA,IAAa,qBAAb,cAAwCA,eAAAA,SAAS;CAEtC;CACA;CAFV,YACC,MACA,MACC;EACD,MACC,GAAG,KAAK,sBAAsB,KAAK,KAAK,IAAI,EAAE,qIAG/C;EAPS,KAAA,OAAA;EACA,KAAA,OAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyCA,eAAAA,SAAS;CAEvC;CACA;CACA;CAHV,YACC,KACA,UACA,OACC;EACD,MACC,0BAA0B,IAAI,OAAO,MAAM,0BACvC,SAAS,gHAEd;EARS,KAAA,MAAA;EACA,KAAA,WAAA;EACA,KAAA,QAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyCA,eAAAA,SAAS;CAEvC;CACA;CAFV,YACC,MACA,QACC;EACD,MACC,GAAG,KAAK,0BAA0B,OAAO,sIAG1C;EAPS,KAAA,OAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,aAAa,MAAc,SAA+B;CACzE,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,OAAO;CAC5B,SAAS,OAAO;EACf,MAAM,IAAI,oBACT,MACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACtD;CACD;CACA,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAChE,MAAM,IAAI,oBAAoB,MAAM,mBAAmB;CAExD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC/C,IAAI,OAAO,UAAU,YAAY,CAAC,wBAAwB,KAAK,KAAK,GACnE,MAAM,IAAI,oBACT,MACA,IAAI,IAAI,uCACT;CAGF,OAAO;AACR;;;;;;;AAQA,SAAgB,UACf,MACA,SACA,QACM;CACN,MAAM,UAAU,OACd,QAAQ,UAAU,CAAC,QAAQ,MAAM,IAAI,CAAC,CACtC,KAAK,UAAU,MAAM,GAAG;CAC1B,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,mBAAmB,MAAM,OAAO;CAElE,OAAO,OAAO,KAAK,UAAU;EAC5B,MAAM,SAAS,QAAQ,MAAM;EAC7B,IAAI,OAAO,MAAM,GAAG,CAAC,CAAC,OAAO,MAAM,KAClC,MAAM,IAAI,oBAAoB,MAAM,KAAK,MAAM,KAAK,MAAM;EAE3D,OAAO;GAAE,GAAG;GAAO,KAAK;EAAO;CAChC,CAAC;AACF;;;;;;;;;;;;;;;;;;;;;;;;;ACtMA,MAAa,gBAAgB;;AAG7B,MAAa,eAAe;;AAG5B,MAAa,eAAe;;AAG5B,MAAa,eAAe;;AAG5B,MAAa,mBAAmB;AAChC,MAAa,iBAAiB;;AAG9B,MAAa,gBAAgB;;AAG7B,MAAM,YAAY;;AAGlB,SAAgB,UAAU,SAAiB,SAAyB;CACnE,OAAO,GAAG,QAAQ,GAAG;AACtB;;AAGA,SAAgB,qBAAqB,SAGnC;CACD,OAAO;EACN,UAAU,GAAG,eAAe,GAAG,QAAQ;EACvC,SAAS,GAAG,eAAe,GAAG,QAAQ;CACvC;AACD;;;;;;AAaA,SAAgB,cAAc,OAA2C;CACxE,OAAO;EACN,QAAQ;GAAE,iBAAiB;GAAO,oBAAoB;EAAM;EAC5D,aAAa;GACZ,KAAK;IACJ,SAAS;IACT,MAAM,EAGL,cAAc,EACb,YAAY;KAGX,IAAI,MAAM,UAAU,MAAM,cAAc,IAAI,MAAM;KAClD,QAAQ;KACR,WAAW;IACZ,EACD,EACD;GACD;GACA,WAAW,EAAE,SAAS,OAAO;GAC7B,MAAM,EAAE,SAAS,IAAI,YAAY;EAClC;EACA,MAAM,EAAE,YAAY,OAAO;EAC3B,WAAW,EACV,MAAM;GAAE,WAAW;GAAkB,OAAO;EAAK,EAClD;EACA,uBAAuB,GACrB,gBAAgB,EAChB,MAAM;GACL,SAAS;GACT,eAAe,EAAE,YAAY,MAAM;EACpC,EACD,EACD;EACA,KAAK,EAAE,OAAO,OAAO;CACtB;AACD;;AAGA,SAAgB,YAAY,SASA;CAC3B,MAAM,EAAE,UAAU;CAClB,OAAO;EACN,MAAM;EACN,UAAU,GACR,eAAe;GACf,OAAO;GACP,SAAS;GACT,OAAO,CAAC,GAAG,MAAM,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI;GAChD,SAAS,CAAC;IAAE,QAAQ;IAAW,QAAQ;GAA2B,CAAC;GACnE,SAAS;IAIR,WAAW;IACX,SAAS;IACT;GACD;GAGA,QAAQ,EACP,8BAAA,GAA6BC,YAAAA,WAAAA,CAAW,QAAQ,CAAC,CAC/C,OAAO,QAAQ,YAAY,CAAC,CAC5B,OAAO,KAAK,CAAC,CACb,MAAM,GAAG,EAAE,EACd;GACA,UAAU,CAAC,MAAM;GACjB,aAAa;IACZ,MAAM;KAAC;KAAO;KAAW;KAAe;IAAQ;IAChD,UAAU;IACV,SAAS;IACT,SAAS;GACV;GACA,SAAS,QAAQ;EAClB,EACD;EACA,SAAS,EAAE,SAAS,EAAE,SAAS,QAAQ,aAAa,EAAE;EACtD,SAAS;GAAE,MAAM,CAAC;GAAG,SAAS,CAAC;GAAG,OAAO,CAAC;EAAE;EAC5C,UAAU,EAAE,MAAM;GAAE,MAAM;GAAc,UAAU;EAAK,EAAE;CAC1D;AACD;;AAUA,SAAgB,eACf,QACA,SAC0B;CAC1B,MAAM,EAAE,SAAS,QAAQ;CACzB,MAAM,QAAQ,OAAkB,WAC/B,GAAG,QAAQ,GAAG,MAAM,OAAO,SAAS,IAAI,WAAW;CACpD,MAAM,OAAO,EAAE,SAAS,WACvB,UAAU,UAAU,SAAS,OAAO,EAAE,GAAG;CAE1C,MAAM,UAAmC,CAAC;CAC1C,MAAM,WAAoC,CAAC;CAC3C,MAAM,cAAuC,CAAC;CAM9C,MAAM,QAAQ,GAAG,QAAQ;CACzB,IAAI,OAAO,SAAS,GACnB,YAAY,SAAS,EACpB,SAAS,EAAE,sBAAsB,GAAGC,oBAAAA,mBAAmB,GAAG,EAAE,EAC7D;CAGD,KAAK,MAAM,SAAS,QAAQ;EAC3B,MAAM,QAAkB,CAAC,KAAK;EAC9B,IAAI,MAAM,OAAO;GAGhB,YAAY,KAAK,OAAO,OAAO,KAAK,EACnC,aAAa,EAAE,aAAa,CAAC,GAAG,MAAM,KAAK,EAAE,EAC9C;GACA,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;EAChC;EACA,IAAI,MAAM,QAAQ;GACjB,YAAY,KAAK,OAAO,QAAQ,KAAK,EACpC,WAAW,EAAE,QAAQ,MAAM,OAAO,EACnC;GACA,MAAM,KAAK,KAAK,OAAO,QAAQ,CAAC;EACjC;EAEA,QAAQ,KAAK,KAAK,KAAK;GACtB,MAAM,UAAU,MAAM,KAAK;GAC3B,aAAa,CAAC,WAAW;GACzB,SAAS,KAAK,KAAK;GACnB,aAAa;GACb,KAAK,IAAI,SAAS,SAAS,EAAE,cAAc,cAAc,IAAI,CAAC;EAC/D;EAEA,SAAS,KAAK,KAAK,KAAK,EACvB,cAAc;GACb,SAAS,MAAM,UAAU,KAAK,cAAc,EAAE,KAAK,IAAI,QAAQ,EAAE,EAAE;GAInE,GAAI,MAAM,SAAS,EAAE,gBAAgB,MAAM,IAAI,CAAC;GAChD,GAAI,MAAM,YACP,EAGA,oBAAoB,EAAE,eAAe,OAAO,EAC7C,IACC,CAAC;GACJ,GAAI,MAAM,SACP,EACA,aAAa;IACZ,MAAM,MAAM;IACZ,UAAU;IACV,SAAS;GACV,EACD,IACC,CAAC;EACL,EACD;CACD;CAEA,OAAO;EACN,MAAM;GACL;GACA;GACA,GAAI,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,YAAY,IAAI,CAAC;EAC9D;EACA,GAAI,IAAI,SAAS,UACd,EACA,KAAK,EACJ,cAAc,CAAC;GAAE,UAAU,IAAI;GAAU,SAAS,IAAI;EAAQ,CAAC,EAChE,EACD,IACC,CAAC;CACL;AACD;;AAGA,SAAgB,mBACf,QACA,SACS;CACT,OAAO,kCAAkC,QAAQ,QAAQ;qBACrC,aAAa;;EAEhCC,OAAK,eAAe,QAAQ,OAAO,CAAC;AACtC;;AAGA,SAAgB,kBAAkB,OAA0B;CAC3D,OAAO;EACNA,OAAK,cAAc,KAAK,CAAC;AAC3B;;AAGA,SAAgB,gBACf,SACS;CACT,OAAO;;;;;wBAKgB,aAAa;EACnCA,OAAK,YAAY,OAAO,CAAC;AAC3B;AAEA,SAASA,OAAK,OAAwB;CACrC,QAAA,GAAOC,KAAAA,UAAAA,CAAU,OAAO;EAAE,WAAW;EAAG,uBAAuB;CAAM,CAAC;AACvE;;;;;;;;;;;;;;;;;;;AC7LA,SAAgB,SAAS,OAAuB;CAC/C,OAAO,gBAAgB;AACxB;;;;;;;;AASA,SAAgB,eAAe,UAAkC;CAChE,OAAO,GAAG,SAAS,MAAM,GAAG,SAAS;AACtC;;AAGA,MAAa,gBAAgB;CAC5B,OAAO;CACP,MAAM;AACP;;;;;;AAOA,MAAa,gBAAgB;;;;;;;;;;;;AAa7B,MAAM,UAA0C;CAC/C,YAAY;CACZ,OAAO;AACR;;AAGA,MAAM,gBAAsE;CAC3E,OAAO;CACP,SAAS;CACT,eAAe;AAChB;;AAGA,MAAM,eAAe;;AAGrB,MAAM,eAAe;CACpB;CACA;CACA;AACD;;;;;;;;AASA,MAAa,eAAe;CAC3B,QAAQ;CACR,SAAS;EAAE,YAAY;EAAO,YAAY;CAAI;AAC/C;;;;;;;;;AAmHA,SAAgB,iBACf,SACA,OACY;CACZ,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,UAA+C;EACpD,WAAW,EAAE,SAAS,MAAM,UAAU;EACtC,GAAI,MAAM,MACP;GACA,YAAY,EAAE,SAAS,MAAM,IAAI,KAAK;GACtC,WAAW,EAAE,SAAS,MAAM,IAAI,IAAI;EACrC,IACC,CAAC;CACL;CACA,MAAM,QAAA,GAAOC,YAAAA,WAAAA,CAAW,QAAQ;CAChC,KAAK,MAAM,CAAC,MAAM,EAAE,cAAc,OAAO,QAAQ,OAAO,GACvD,KAAK,OAAO,GAAG,KAAK,IAAI,QAAQ,GAAG;CAEpC,OAAO;EACN,GAAG;EACH,UAAU;GACT,GAAG,QAAQ;GACX,OAAO;IACN,GAAG;IACH,SAAS,CACR;KAAE,QAAQ;KAAa,QAAQ;IAAuB,GACtD,GAAI,MAAM,MACP,CACA;KAAE,QAAQ;KAAY,QAAQ,GAAG,cAAc;IAAW,GAC1D;KACC,QAAQ;KACR,QAAQ,GAAG,cAAc;KACzB,MAAM;IACP,CACD,IACC,CAAC,CACL;IACA,QAAQ;KACP,GAAG,MAAM;KACT,8BAA8B,KAAK,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;IAC7D;GACD;EACD;EACA,SAAS;GAAE,GAAG,QAAQ;GAAS,GAAG;EAAQ;CAC3C;AACD;;AA0EA,IAAa,0BAAb,cAA6CC,eAAAA,SAAS;CAChC;CAArB,YAAY,OAAwB;EACnC,MACC,oBAAoB,MAAM,qJAC3B;EAHoB,KAAA,QAAA;EAIpB,KAAK,OAAO;CACb;AACD;;;;;;AAOA,SAAgB,mBACf,SACA,MACA,MACuB;CACvB,MAAM,UAAU,YACfC,cAAAA,kBAAkB,SAAS,MAAM,SAAS,IAAI;CAC/C,OAAO;EACN,UAAU;GAAE,MAAMC,cAAAA,kBAAkB,OAAO;GAAG,UAAU,OAAO,QAAQ;EAAE;EACzE,OAAO;GAAE,MAAM,GAAG,QAAQ;GAAS,UAAU,OAAO,OAAO;EAAE;EAC7D,UAAU;GAAE,MAAMC,cAAAA;GAAqB,UAAU,OAAO,UAAU;EAAE;EACpE,OAAO,EAAE,UAAU,OAAO,OAAO,EAAE;EACnC,YAAY,OAAO,aAAa;EAChC,UAAU;GACT,aAAaC,cAAAA;GACb,iBAAiB,OAAO,UAAU;EACnC;EAIA,MAAM;GAAE,OAAO,SAAS;GAAW,UAAU,OAAO,MAAM;EAAE;CAC7D;AACD;;AAkEA,IAAa,qBAAb,cAAwCJ,eAAAA,SAAS;CAEtC;CACA;CACA;CAHV,YACC,KACA,KACA,OACC;EACD,MACC,IAAI,IAAI,UAAU,IAAI,mBAAmB,MAAM,iGAE3B,IAAI,eAAe,OACxC;EARS,KAAA,MAAA;EACA,KAAA,MAAA;EACA,KAAA,QAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,mBAAb,cAAsCA,eAAAA,SAAS;CACzB;CAArB,YAAY,OAAwB;EACnC,MACC,cAAc,MAAM,uHACgD,MAAM,wDAE3E;EALoB,KAAA,QAAA;EAMpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,mBAAb,cAAsCA,eAAAA,SAAS;CACzB;CAArB,YAAY,MAAuB;EAClC,MACC,GAAG,KAAK,yIAGT;EALoB,KAAA,OAAA;EAMpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,oBAAb,cAAuCA,eAAAA,SAAS;CAErC;CACA;CAFV,YACC,KACA,KACC;EACD,MACC,GAAG,IAAI,QAAQ,IAAI,+IAGpB;EAPS,KAAA,MAAA;EACA,KAAA,MAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,MAAM,UAAU,EAAE,WAAW,kBAAkB;;;;;;AAO/C,SAAS,MAAM,MAAc,MAA2C;CACvE,OAAO;EACN,MAAM;GACL;GACA;GACA;GACA;GACA;GACA,oBAAoB,OAAO;EAC5B;EACA,UAAU;EACV,SAAS;EACT,SAAS;EACT,cAAc;CACf;AACD;;;;;;;;AASA,SAAgB,UACf,WACA,UACA,OACO;CACP,OAAOK,cAAAA,QAAQ,UAAU,QAAA,GAAOC,oBAAAA,eAAAA,CAAe,QAAQ,GAAG;EACzD,YAAY,UAAU,OAAO;EAC7B,QAAQC,4BAAAA,eAAe;EACvB,OAAOC,cAAAA;EAEP,MAAM;CACP,CAAC;AACF;;AAGA,SAAgB,aAAa,OAAiC;CAC7D,MAAM,EAAE,WAAW,UAAU,OAAO,aAAa;CACjD,MAAM,QAAQ,UAAU,UAAU,OAAO;CACzC,MAAM,UAAU,eAAe,QAAQ;CACvC,MAAM,SAAS,MAAM,SAAS,UAAU,CAAC;CACzC,MAAM,QAAQ,MAAM,OAAO,SAAS;CACpC,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,MAAM,QAAQC,kBAAAA,SAAS,UAAU,QAAQ,SAAS,OAAO,KAAK;CAC9D,MAAM,cAAc,QACjB,KAAA,IACAC,kBAAAA,eAAe,UAAU,QAAQ,SAAS,OAAO,UAAU,IAAI;CAMlE,MAAM,OAAO,UAAU,WAAW,UAAU,KAAK;CACjD,MAAM,OAAO,IAAI,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CAKzD,IAAI,SAAS,CAAC,MAAM,kBACnB,MAAM,IAAI,wBAAwB,KAAK;CAExC,MAAM,OAAO,QAAQ,MAAM,iBAAkB,OAAO,MAAM,SAAS;CACnE,IAAI,CAAC,MAAM,MAAM,IAAI,iBAAiB,KAAK;CAC3C,MAAM,aAAmC,QACtC,MAAM,mBACN,mBAAmB,UAAU,MAAM,MAAM,IAAI;CAChD,MAAM,aAA8B;EACnC,YAAY;GACX,GAAG;GAEH,OAAO;IACN,MAAM,OAAO,qBAAqB,WAAW,MAAM;IACnD,UAAU,OAAO,yBAAyB,WAAW,MAAM;GAC5D;EACD;EACA;CACD;CAEA,MAAM,OAAO,UAAU,WAAW,UAAU,MAAM;EACjD;EACA;EACA;EACA;EACA,QAAQ,MAAM;CACf,CAAC;CACD,MAAM,UAAU,aACfC,cAAAA,YAAY,WAAW,UAAU,MAAM,cAAc,CAAC,CAAC,GACvD;EAAE;EAAO;EAAU,QAAQ,MAAM;CAAO,CACzC;CACA,IAAI,KAAK,WAAW,KAAK,QAAQ,WAAW,GAC3C,MAAM,IAAI,iBAAiB,UAAU,IAAI;CAK1C,MAAM,yBAAS,IAAI,IAA6B;CAChD,KAAK,MAAM,YAAY,KAAK,WAAW;EACtC,OAAO,IAAI,SAAS,QAAQ,QAAQ;EACpC,IAAI,SAAS,SAAS,SAAS;GAC9B,OAAO,KAAA,GAAIC,oBAAAA,WAAAA,CAAW,SAAS,IAAI,MAAM,GAAG,QAAQ;GACpD,OAAO,KAAA,GAAIA,oBAAAA,WAAAA,CAAW,SAAS,IAAI,UAAU,GAAG,QAAQ;EACzD;EACA,IAAI,SAAS,SAAS,gBACrB,OAAO,KAAA,GAAIA,oBAAAA,WAAAA,CAAW,SAAS,IAAI,aAAa,GAAG,QAAQ;CAE7D;CAEA,MAAM,SAAS,UAAU,UAAU;CAKnC,MAAM,YAAYC,kBAAAA,sBAAsB;EACvC,GAAI,UAAU,QAAQ,YACnB,EAAE,WAAW,UAAU,OAAO,UAAU,IACxC,CAAC;EACJ;EACA;EACA,QAAQ;EACR,SAAS;EACT,YAAY;EACZ,MAAMC,cAAAA,cAAc,QAAQ;CAC7B,CAAC;CAKD,MAAM,WACL,WAAW,aAAa,gBACrBC,cAAAA,UAAU;EACV,QACC,SAAS,MAAM,OAAO,OACnB;GAAE,GAAG,UAAU;GAAY,MAAM,MAAM,MAAM;EAAK,IAClD,UAAU;EACd;EACA;EACA,SAAS,UAAU;EACnB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B;EACA;EACA,GAAI,QAAQ,EAAE,YAAY,MAAM,iBAAkB,KAAK,IAAI,CAAC;CAC7D,CAAC,IACA,KAAA;CAMJ,MAAM,WAA6B,QAChC;EACA,SAAS,CAAC;EACV,OAAO,KAAK,UACV,QAAQ,MAAM,EAAE,SAAS,SAAS,CAAC,CACnC,KAAK,MAAM,EAAE,EAAE;EACjB,SAAS,KAAK,UACZ,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CACjC,KAAK,MAAM,EAAE,EAAE;CAClB,IACCC,cAAAA,iBAAiB;EACjB;EACA,cAAcC,cAAAA,yBAAyB;GACtC;GACA,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;EACzD,CAAC;EACD,UAAU;EACV,OAAO,MAAM,qBAAqB;EAClC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,WAAWC,cAAAA,mBAAmB,WAAW,KAAK;CAC/C,CAAC;CAIH,MAAM,QAAQC,cAAAA,WAAW;EACxB;EACA;EACA;EACA;EACA,GAAI,QAAQ,EAAE,eAAe,MAAM,iBAAkB,MAAM,SAAS,IAAI,CAAC;CAC1E,CAAC;CAED,MAAM,QAAQ,CACb,GAAG,KAAK,WACN,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC,CAE1B,QAAQ,MAAM,MAAMC,cAAAA,YAAY,CAAC,CACjC,QAAQ,MAAM,MAAM,WAAW,SAAS,MAAM,SAAS,CAAC,CAAC,CACzD,QAAQ,MAAM,MAAM,aAAa,SAAS,QAAQ,SAAS,CAAC,CAAC,CAC7D,QAAQ,MAAM,MAAA,WAAuB,UAAU,KAAA,CAAS,GAC1D,GAAI,WAAW,CAACA,cAAAA,YAAY,IAAI,CAAC,CAClC,CAAC,CAAC,KAAK;CAKP,MAAM,UAAoC,MAAM,SAAS,OAAO,WACtD;EACP,MAAM,UAAU,SAAS,MACvB,KAAK,OAAO,KAAK,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAC/B,QAAQ,SAAyB,QAAQ,IAAI,CAAC,CAAC,CAC/C,KAAK;EACP,OAAO;GACN,GAAG,WAAW,WAAW;GACzB;GACA,UAAUC,cAAAA,eAAe,IAAI,CAAC,CAAC,QAAQ,MACtC,QAAQ,SAAS,EAAE,MAAM,CAC1B;EACD;CACD,EAAA,CAAG,IACF,KAAA;CAIH,MAAM,8BAAc,IAAI,IAA+C;CACvE,IAAI,SACH,KAAK,MAAM,YAAY,KAAK,WAAW;EACtC,IAAI,SAAS,SAAS,iBAAiB,CAAC,SAAS,IAAI;EACrD,IAAI,CAAC,SAAS,MAAM,SAAS,SAAS,EAAE,GAAG;EAC3C,IAAI,OAAO,SAAS,YAAY,KAAA,GAAW;EAC3C,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;EACnC,IAAI,CAAC,QAAQ;EAEb,IAAI;EACJ,IAAI,OACH,OAAOC,cAAAA,QAAQ,UAAU,UAAU,IAAI;OACjC;GACN,IAAI,CAAC,QAAQ,MAAM,IAAIC,cAAAA,iBAAiB,KAAK;GAC7C,OAAO,GAAG,SAAS,aAAaC,eAAAA,OAAO,SAAS,EAAE,EAAE,GAAG;EACxD;EACA,YAAY,IAAI,SAAS,IAAI;GAC5B,KAAK,WAAW,OAAO,SAAS,UAAU,MAAM,IAAI,UAAU;GAC9D,OAAO;IACN,MAAM,SAASA,eAAAA,OAAO,SAAS,EAAE;IACjC;IACA,WAAW,CAAC;KAAE,SAAS;KAAS,MAAM;IAAK,CAAC;IAC5C,WAAW;IACX,QAAQ,IAAI,OAAO;GACpB;EACD,CAAC;CACF;CAOD,MAAM,eAAe,IAAI,IACxB,UAAU,YACP;EACA,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI;EAC7B,GAAI,YAAY,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC;EACxC,GAAI,UAAU,QAAQ,SAAS,SAAS,CAACJ,cAAAA,YAAY,IAAI,CAAC;CAC3D,IACC,CAAC,CACL;CACA,MAAM,UAAU,YACf,aAAa,IAAI,OAAO,IAAI,UAAU,SAAS,OAAO,IAAI;CAC3D,MAAM,OAA8B,YAAY;EAC/C,GAAG;EACH,QAAQ;GACP,GAAG,SAAS;GACZ,6BACC,SAAS,OAAO,4BAA4B,QAC3C,kBACA,KAAK,OAAA,aAAmB,EAAE,EAC3B;EACF;CACD;CAKA,MAAM,aAAa;EAClB,SAAS,UAAU;EACnB,aAAa,WAAW;EACxB,MAAM,WAAW;EAEjB,GAAI,CAAC,SAAS,SAAS,EAAE,UAAU,WAAW,SAAS,IAAI,CAAC;CAC7D;CACA,MAAM,UAAUK,cAAAA,WACf,MACA;EACC,GAAG;EACH,WAAW,OAAO,YAAY,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;CACnE,GACA,MACD;CACA,MAAM,SAASA,cAAAA,WACd,MACA;EACC,GAAG;EACH,WAAW,OAAO,YACjB,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,UAAU,OAAO,IAAI,IAAI,EAAE,GAAG,IAAI,MAAM,CAAC,CACrE;CACD,GACA,MACD;CAEA,MAAM,cAAc,IAAI,IACvB,KAAK,UACH,QAAQ,MAAM,EAAE,SAAS,cAAc,EAAE,SAAS,MAAM,CAAC,CACzD,KAAK,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,CAC9B;CACA,MAAM,UAAU,IAAI,IAAI,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;;;;;CAMxD,MAAM,YACL,KACA,KACA,UACwB;EAExB,IAAIC,kBAAAA,mBAAmB,GAAG,GAAG,OAAO,KAAA;EAGpC,IAAI,CAAC,SAAS,OAAO,SAAS,WAAW,IAAI,SAAS,YAAY,GACjE;EAKD,IAAI,SAAS,cAAc,MAAM,OAAO;GACvC,IAAI,OAAO,SAAS,KAAA,GAAW,OAAO,OAAO;GAC7C,IAAI,MAAM,SAAS,eAAe,OAAO,YAAY,IAAI,MAAM,EAAE,CAAC,EAAE;GACpE,OAAO,QAAQ;EAChB;EAIA,IAAI,SAASC,cAAAA,aAAa,MAAM,MAAM,MAAM,IAAI,KAAK,KAAK,GAAG;GAC5D,MAAM,QAAQ,OAAO;GACrB,IAAI,UAAU,KAAA,GACb,MAAM,IAAI,mBAAmB,IAAI,MAAM,KAAK,KAAK;GAElD,OAAO;EACR;EAGA,IAAI,OAAO,SAAS,KAAA,GAAW,OAAO,OAAO;EAG7C,IAAI,OAAO,SAAS,SAAS,OAAO,OAAO,KAAK;EAKhD,MAAM,UAAU,YAAY,IAAI,GAAG;EACnC,IAAI,IAAI,SAAS,cAAc,WAAW,YAAY,IAAI,IACzD,OAAO,OAAO;EAGf,OAAO,QAAQ;CAChB;CAIA,MAAM,kBAAsD,OACzDC,kBAAAA,aACA;EACC,UAAU,KAAK,OAAO;EACtB,SAAS,KAAK,OAAO;CACtB,GACA,WAAW,cAAc,CAC1B,IACC,WAAW,aAAa,SACvBC,kBAAAA,iBAAiB,SAAS,IAC1B,KAAA;;CAGJ,MAAM,aACL,KACA,SAC4B;EAC5B,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;GAEnC,IAAIC,cAAAA,eAAe,GAAG,GAAG;GACzB,MAAM,QAAQ,OAAO,IAAI,GAAG,KAAK,aAAa,KAAK,IAAI;GACvD,IAAK,aAAmC,SAAS,GAAG,GAAG;IAGtD,MAAM,QAAQ,OAAO,QAAQ,aAAa,KAAK,OAAO;IACtD,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;IACvC;GACD;GAEA,MAAM,QAAQ,SAAS,KAAK,KAAK,KAAK;GACtC,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;EACxC;EACA,OAAO;CACR;CAEA,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,IAAI,SAAS,QAAQ;GACxB,MAAM,OAAO,SAAS,IAAI;GAC1B,IAAI,MAAM,SAAS,QAAQ;GAE3B,MAAM,OAAOC,cAAAA,kBACZ,MACA,WACC,QAAQ,SAAS,KAAK,KAAK,OAAO,IAAI,GAAG,CAAC,GAC3C,MACD;GACA,IAAI,IAAI,SAAS,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,MAAM,OAAO;GAChE;EACD;EAGA,IAAI,MAAM,WAAW;EAErB,MAAM,OAAOC,cAAAA,WAAW,UAAU,IAAI,MAAM,MAAM,SAAS,qBAAK,IAAI,IAAI;EACxE,MAAM,SAAS,UAAU,KAAK,IAAI;EAMlC,MAAM,WAAA,GAAUpB,oBAAAA,WAAAA,CAAW,IAAI,IAAI,gBAAgB;EACnD,IAAI,KAAK,IAAI,OAAO,GAAG;GACtB,MAAM,YAAY,KAAK,IAAI,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC,EAAA,CAC9C,KAAK,WAAW,QAAQ,IAAI,MAAM,CAAC,CAAC,CACpC,QAAQ,WAA+B,QAAQ,SAAS,UAAU,CAAC,CACnE,KAAK,WAAW,UAAU,OAAO,OAAO,IAAI,EAAE,GAAG,OAAO,MAAM;GAChE,MAAM,UAAU,CACf,IAAI,OAAO,YAAY,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,GACpD,GAAG,QACJ;GACA,OAAO,WAAW,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;EACjD;EAGA,IAAI,MAAM;GACT,GAAGqB,cAAAA,kBAAkB,QAAQ;IAC5B,MAAMC,cAAAA,YAAY,UAAU,IAAI,EAAE,MAAM,KAAA;IACxC,aAAa,IAAI;IACjB,GAAI,kBAAkB,EAAE,WAAW,gBAAgB,IAAI,CAAC;GACzD,CAAC;GACD,UAAU;GACV,MAAM,OAAO,IAAI,IAAI;GACrB,OAAO;EACR;EAEA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG,GAChD,IAAI,SAAS,KAAK,KAAK,GAAG,MAAM,IAAI,kBAAkB,IAAI,MAAM,GAAG;CAErE;CAIA,MAAM,aAA+B,CAAC;CACtC,KAAK,MAAM,eAAe,OAAO,OAAO,QAAQ,GAAG;EAClD,IAAI,YAAY,SAAS,cAAc;EACvC,MAAM,MAAM;GACX,MAAMV,eAAAA,OAAO,YAAY,EAAE;GAC3B,IAAI,YAAY;GAChB,MAAM;EACP;EACA,WAAW,KAAK;GACf,MAAM,IAAI;GACV,IAAI,IAAI;GACR,QAAQO,cAAAA,kBACP,aACA,WACC,QAAQ,SAAS,KAAK,KAAK,OAAO,IAAI,GAAG,CAAC,GAC3C,MACD;EACD,CAAC;CACF;CAIA,KAAK,MAAM,UAAU,MAAM,YAAY,CAAC,IAAI,SAAS;EACpD,MAAM,OACLI,cAAAA,cAAc,UAAU,OAAO,IAAI,MAAM,SAAS,qBAAK,IAAI,IAAI;EAChE,OAAO,MAAM;GACZ,GAAGF,cAAAA,kBACF,UAAU;IAAE,MAAM,OAAO;IAAM,IAAI,OAAO;IAAI,MAAM;GAAW,GAAG,IAAI,GACtE;IACC,MAAMC,cAAAA,YAAY,UAAU,OAAO,EAAE,MAAM,KAAA;IAC3C,aAAa,OAAO;IACpB,GAAI,kBAAkB,EAAE,WAAW,gBAAgB,IAAI,CAAC;GACzD,CACD;GACA,UAAU;GACV,MAAM,OAAO,OAAO,IAAI;GACxB,OAAO;EACR;EACA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAAG,GACnD,IAAI,SAAS,KAAK,KAAK,GAAG,MAAM,IAAI,kBAAkB,OAAO,MAAM,GAAG;CAExE;CAIA,MAAM,cAAsD,cACzD;EACA,MAAM;EACN,GAAI,UAAU,UACX;GACA,UAAU,GAAG,cAAc;GAC3B,SAAS,GAAG,cAAc;EAC3B,IACC,qBAAqB,OAAO;CAChC,IACC,EAAE,MAAM,OAAO;CAClB,MAAM,MAAe,QAAQ,EAAE,MAAM,WAAW,IAAI;CAIpD,MAAM,gBAAgB,MAAM,YACzB,KAAA,IACAE,YAAAA,aAAa,WAAW,UAAU,KAAK;CAC1C,MAAM,UACL,eAAe,SAAS,QAAQ,MAAM,SAAS,UAAU,IACtDC,YAAAA,aAAa;EACb;EACA;EACA;EACA;EACA,SAAS,cAAc;EACvB;EACA;EACA,WAAW,WAAW,WAAW;EACjC,GAAI,kBAAkB,EAAE,WAAW,gBAAgB,IAAI,CAAC;CACzD,CAAC,IACA,KAAA;CAEJ,MAAM,SAAS,MAAM,UAAU,cAAc,UAAU,IAAI;CAC3D,MAAM,UAAU,UAAU;EACzB;EACA;EACA;EACA;EACA;EACA,aAAa,WAAW;EACxB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B;EACA;EACA,aAAA,GAAYC,UAAAA,KAAAA,CAAK,UAAU,MAAM,SAAS,KAAK,CAAC;EAChD,WAAW,OAAO;EAClB,eAAe,UAAU;EACzB,UAAU,CAAC,MAAM;EACjB;EACA,MAAM,IAAI,IACT,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,YAAY,CAAC,SAAS,OAAO,OAAO,CAAC,CAAC,CAC9D;CACD,CAAC;CAGD,MAAM,SAAsB;EAC3B,GAAG,KAAK,KACN,SAAoB;GACpB,MAAM,IAAI;GACV,MAAM,IAAI;GACV,WAAW,CAAC;IAAE,SAAS,IAAI;IAAM,MAAM,IAAI;GAAK,CAAC;GACjD,WAAW;GACX,QAAQ,IAAI,SAAS,SAAS,MAAM;EACrC,EACD;EACA,GAAG,CAAC,GAAG,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK;EACrD,GAAI,MAAM,QAAQ,KAAK,SACpB,CACA;GACC,MAAMlB,cAAAA;GACN,MAAM,KAAK;GACX,WAAW,CAAC;IAAE,SAASA,cAAAA;IAAc,MAAMmB,kBAAAA;GAAU,CAAC;GACtD,WAAW;GACX,OAAO,KAAK,OAAO;EACpB,CACD,IACC,CAAC;CACL;CACA,MAAM,cAAsC,CAAC;CAC7C,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,CAAC,IAAI,OAAO;EAIhB,YAAY,IAAI,MAAM,cAAcC,cAAAA,cACnC,IAAI,MACJ,UAAU,KAAK,IAAI,OACnB;GACC;GACA,eAAe,UAAU;GACzB,MAAM,UAAU;GAChB;GACA,OAAOhC,cAAAA;GAEP;GACA;GAGA,GAAI,IAAI,SAAS,UAAU,IAAI,MAAM,OAClC,EAAE,eAAe,OAAO,KAAK,IAAI,MAAM,IAAI,EAAE,IAC7C,CAAC;EACL,CACD;CACD;CACA,KAAK,MAAM,UAAU,SAAS;EAC7B,IAAI,CAAC,OAAO,OAAO;EACnB,YAAY,OAAO,MAAM,cAAciC,cAAAA,iBACtC;GAAE,IAAI,OAAO;GAAI,MAAM,OAAO;GAAM,KAAK,OAAO;EAAK,GACrD,UAAU,KAAK,OAAO,OACtB;GAAE;GAAQ,eAAe,UAAU;GAAM,OAAOjC,cAAAA;EAAY,CAC7D;CACD;CAEA,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAI,UAAU,UACX,EAAE,WAAW,cAAc,QAAQ,EAAE,IAAI,CAAC,EAAE,IAC5C,EACA,SAAS,mBAAmB,QAAQ;GACnC;GACA,KAAK;EACN,CAAC,EACF;EACF,GAAI,cAAc,EAAE,KAAK,YAAY,IAAI,CAAC;EAC1C;EACA;EACA;EACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,aAAa,QAAQ,CAAC,IAAIkC,cAAAA,gBAAgB,QAAQ;EAClD,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC9B;AACD;;AAGA,SAAS,aACR,KACA,SACqB;CACrB,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,QAAQ,qBAAqB,OAAO,QAAQ;CAChD,IAAI,QAAQ,yBAAyB,OAAO,QAAQ;CACpD,IAAI,QAAQ,cAAc,OAAO;AAElC;;AAGA,SAAS,aAAa,KAAa,MAAyC;CAC3E,IAAI,CAAE,aAAmC,SAAS,GAAG,GAAG,OAAO,KAAA;CAC/D,OAAO,KAAK,UAAU,MAAM,MAAM,EAAE,SAAS,SAAS;AACvD;;AAGA,SAAS,UACR,WACA,UACA,MACA,SAOa;CACb,MAAM,OAAmB,CAAC;CAC1B,MAAM,YAAY,IAAI,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CAE9D,KAAK,MAAM,CAAC,IAAI,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;EACzD,IAAI,YAAY,SAAS,cAAc,YAAY,SAAS,QAC3D;EAED,MAAM,OAAOlB,eAAAA,OAAO,EAAE;EACtB,MAAM,MAAM,UAAU,KAAK;EAC3B,MAAM,WAAW,UAAU,IAAI,EAAE;EACjC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,MAAM;EAEpC,MAAM,OAAO,OAAO,MAAM,KAAK,WAAW,UAAU,OAAO;EAE3D,MAAM,MADO,YAAY,SAAS,SAE/B,QAAQ,QAAQ,OAAO,KAAK,QAAQ,KAAK,IACzC,QAAQ,OAAO;EAClB,MAAM,MAAMmB,cAAAA,iBACXC,iBAAAA,SAAS,QAAQ,UAAU,MAAM,QAAQ,OAAO,UAAU,GAAG,CAC9D;EAEA,KAAK,KAAK;GACT,KAAK;GACL;GACA;GACA,MAAM,YAAY;GAClB,MAAM,IAAI;GACV,MAAM,IAAI;GACV;GACA,KAAK,WAAW,OAAO,QAAQ,SAAS,QAAQ,UAAU,MAAM,IAAI,QAAQ,UAAU;GACtF;GACA;GACA,GAAI,QAAQ,OAAO,SAAS,UACzB,EACA,OAAO,EACN,YAAY,GAAG,SAAS,QAAQ,KAAK,EAAE,cAAc,OACtD,EACD,IACC,CAAC;EACL,CAAC;CACF;CAEA,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACxD;;AAGA,SAAS,aACR,OACA,SAKgB;CAChB,OAAO,MAAM,KAAK,UAAU;EAC3B,KAAK,KAAK;EACV,MAAM,KAAK;EACX,IAAI,KAAK;EACT,MAAM,KAAK;EACX,MAAMC,cAAAA;EACN,KAAKF,cAAAA,iBACJC,iBAAAA,SACC,QAAQ,UACR,KAAK,MACL,QAAQ,OAAO,UACf,QAAQ,OAAO,GAChB,CACD;EACA,KAAK,QAAQ,OAAO;EACpB,GAAI,QAAQ,OAAO,SAAS,UACzB,EACA,OAAO,EACN,YAAY,GAAG,SAAS,QAAQ,KAAK,EAAE,cAAc,KAAK,OAC3D,EACD,IACC,CAAC;CACL,EAAE;AACH;;;;;;AAOA,SAAS,OACR,MACA,KACA,WACA,UACA,SACS;CACT,IAAI,QAAQ,OAAO,OAAOtB,cAAAA,QAAQ,UAAU,UAAU,IAAI;CAE1D,OAAOwB,cAAAA,YACN,MACA,KACA,QAAQ,OACR,UAAU,SACVC,cAAAA,kBAAkB,MAAM,KAAK,UAAU,IAAI,CAC5C;AACD;;AAGA,SAAS,UAAU,SAqBL;CACb,MAAM,EAAE,SAAS,MAAM,SAAS;CAEhC,MAAM,QAAQ,QAAQ,MAAM,QAAQ,SAAS,SAAS3B,cAAAA,YAAY;CAKlE,MAAM,UAAU4B,cAAAA,WACf;EAAE,GAAG;EAAM,YAAY,CAAC,GAAG,KAAK;CAAE,GAClC;EACC;EACA,OAAO,OAAO,YACbC,cAAAA,SAAS,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAClD;EACA,aAAa,QAAQ;CACtB,CACD;CAEA,MAAM,WAAyC,CAAC;CAChD,MAAM,UAAiD;EACtD,GAAG,QAAQ;EACX,GAAI,QAAQ,UAAU,UACnB;GAAE,cAAc,CAAC;GAAG,gBAAgB,CAAC;EAAE,IACvC,CAAC;EACJ,GAAI,QAAQ,OAAO,EAAE,oBAAoB,CAAC,EAAE,IAAI,CAAC;CAClD;CAEA,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,EACL,OAAO,QACP,YACA,UAAU,WACV,GAAG,YACA,QAAQ,SAAS;EACrB,SAAS,QAAQ;GAChB,GAAG;GACH,GAAI,YAAY,SACb,EACA,YAAY,OAAO,YAClB,WAAW,KAAK,QAAQ,CAAC,KAAK,OAAO,CAAC,CACvC,EACD,IACC,CAAC;EACL;CACD;CAEA,MAAM,WAAW,SAAS;CAC1B,IAAI,UAIH,SAAS,QAAQ,CAAC,iBAAiB;CAGpC,MAAM,QAAQ,SAAS;CACvB,IAAI,SAAS,QAAQ,SAAS;EAC7B,MAAM,cAAc;GACnB,GAAG,MAAM;GACT,iBAAiB,QAAQ,QAAQ;GACjC,qBAAqB,QAAQ,QAAQ;EACtC;EAIA,MAAM,QAAQ,CAAC,iBAAiB;CACjC;CAIA,IAAI,SAAA,YAA2B,QAAQ,OACtC,SAASC,cAAAA,iBAAiBC,cAAAA,aAAa,QAAQ,KAAK;CAKrD,IAAI,QAAQ,MAAM,SAAS/B,cAAAA,gBAAgBgC,cAAAA,YAAY,QAAQ,IAAI;CAGnE,IAAI,QAAQ,SACX,SAASC,YAAAA,mBAAmBC,YAAAA,eAC3B,QAAQ,SACR,QAAQ,QACT;CAGD,KAAK,MAAM,OAAO,MACjB,SAAS,IAAI,QAAQ;EACpB,OAAO,IAAI;EACX,GAAI,IAAI,QACL,EACA,OAAO;GACN,GAAGC,cAAAA,kBAAkB;IACpB,YAAY,QAAQ;IACpB,WAAW,QAAQ;IACnB,eAAe,QAAQ;IACvB,YAAY,IAAI,MAAM;GACvB,CAAC;GACD,GAAI,IAAI,MAAM,OAAO,EAAE,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC;EAClD,EACD,IACC,CAAC;EACJ,SAAS;EAGT,GAAI,IAAI,SAAS,aACd;GACA,UAAU,CAAC;IAAE,MAAM,KAAK,IAAI,KAAK;IAAO,QAAQ;GAAe,CAAC;GAChE,GAAI,MAAM,SACP,EACA,YAAY,OAAO,YAClB,MAAM,KAAK,SAAS,CAAC,MAAM,OAAO,CAAC,CACpC,EACD,IACC,CAAC;EACL,IACC,CAAC;EACJ,aAAa,MAAM,IAAI,MAAM,IAAI,SAAS,SAAS,MAAM,SAAS;CACnE;CAID,KAAK,MAAM,UAAU,QAAQ,SAC5B,SAAS,OAAO,QAAQ;EACvB,OAAO,OAAO;EACd,GAAI,OAAO,QACR,EACA,OAAOA,cAAAA,kBAAkB;GACxB,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,eAAe,QAAQ;GACvB,YAAY,OAAO,MAAM;EAC1B,CAAC,EACF,IACC,CAAC;EACJ,SAAS;EACT,UAAU,CAAC;GAAE,MAAM,KAAK,OAAO,KAAK;GAAO,QAAQ;EAAe,CAAC;EACnE,GAAI,MAAM,SACP,EACA,YAAY,OAAO,YAClB,MAAM,KAAK,SAAS,CAAC,MAAM,OAAO,CAAC,CACpC,EACD,IACC,CAAC;EACJ,aAAa,MAAM,OAAO,MAAM,SAAS;CAC1C;CAGD,IAAI,QAAQ,UAAU,SACrB,SAAS,QAAQ;EAChB,OAAOC,cAAAA,eAAe;EACtB,SAAS;EACT,OAAO,CAAC,GAAG,QAAQ,MAAM,OAAO,GAAG,QAAQ,KAAK,IAAI;EAGpD,SAAS,CAAC,oBAAoB,sBAAsB;EACpD,YAAY,OAAO,YAAY,KAAK,KAAK,QAAQ,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC;EACrE,aAAa;GACZ,MAAM;IAAC;IAAO;IAAS;GAAS;GAChC,UAAU;GACV,SAAS;GACT,SAAS;EACV;CACD;CAOD,KAAK,MAAM,CAAC,SAAS,UAAU,QAAQ,MAAM;EAC5C,MAAM,aAAa,SAAS;EAC5B,IAAI,CAAC,YAAY;EACjB,WAAW,WAAW;GACrB,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE;GAC5B,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE;EAC1B;CACD;CAEA,KAAK,MAAM,WAAW,OAAO,OAAO,QAAQ,GAAG;EAC9C,IAAI,CAAC,QAAQ,UAAU,OAAO,QAAQ;EACtC,QAAQ,UAAU;GACjB,QAAQ,aAAa;GACrB,SAAS,EAAE,GAAG,aAAa,QAAQ;EACpC;CACD;CAEA,OAAO;EACN,MAAM;EACN;EACA;EACA,GAAI,QAAQ,KAAK,OAAO,IACrB,EAAE,UAAU,EAAE,MAAM;GAAE,MAAM;GAAc,UAAU;EAAc,EAAE,EAAE,IACtE,CAAC;CACL;AACD;;;;;AAMA,SAAS,cAAc,MAA2B;CACjD,OAAO;EACN,WAAW;EACX,SAAS;EACT,OAAO;GACN,gBAAgB;GAChB,cAAcC,cAAAA;GACd,UAAU;EACX;EACA,UAAU,CAAC,cAAc;CAC1B;AACD;;AAGA,SAAgB,QAAQ,KAA+C;CACtE,OAAO,GAAG,OAAO,QAAQ,GAAG,CAAC,CAC3B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CACtC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,CACxC,KAAK,IAAI,EAAE;AACd;;;;;;;;;;;;;;;;;;;;AC5hDA,SAAgB,QACf,MACA,UAAwD,CAAC,GAC9C;CACX,OAAO;EACN,SAAS;EACT;EACA,MAAA,GAAKC,UAAAA,QAAAA,CAAQ,IAAI;EACjB,GAAG;CACJ;AACD;;AAGA,IAAa,kBAAb,cAAqCC,eAAAA,SAAS;CAEnC;CACA;CAFV,YACC,MACA,QACC;EACD,MACC,mBAAmB,KAAK,uBAAuB,aAAa,KAAK,OAAO,KAAK,KAAK,oBAAoB,sCAChE,aAAa,gDACpD;EANS,KAAA,OAAA;EACA,KAAA,SAAA;EAMT,KAAK,OAAO;CACb;AACD;;;;;;;;;AAUA,IAAa,oBAAb,cAAuCA,eAAAA,SAAS;CAErC;CACA;CACA;CACA;CAJV,YACC,SACA,OACA,MACA,QACC;EACD,MAAM,KAAK,OAAO,UACf,GAAG,OAAO,UAAU,oBAAoB,OAAO,QAAQ,KACvD,OAAO;EACV,MAAM,MACL,UAAU,YACP,OAAO,YAAY,WAAW,OAAO,YAAY,UAChD,6HAA6H,QAAQ,4GACrI,gDAAgD,OAAO,YAAY,OAAO,UAAU,uBAAuB,OAAO,QAAQ,yCAAyC,GAAG,yEACvK,OAAO,YAAA,aACN,iOAAiO,aAAa,WAC9O,QAAQ,OAAO,UAAU;EAC9B,MACC,GAAG,QAAQ,qBAAqB,MAAM,cAAc,KAAK,cAAc,GAAG,IAAI,KAC/E;EAlBS,KAAA,UAAA;EACA,KAAA,QAAA;EACA,KAAA,OAAA;EACA,KAAA,SAAA;EAgBT,KAAK,OAAO;CACb;AACD;;;;;AAMA,eAAsB,gBACrB,QACA,SAMgB;CAChB,MAAM,EAAE,SAAS,OAAO,UAAU;CAClC,KAAK,MAAM,QAAQ,CAAC,MAAM,OAAO,MAAM,IAAI,GAC1C,KAAK,MAAM,UAAU,MAAM,OAAO,WAAW,QAAQ,QAAQ,IAAI,GAKhE,IAAI,EAHH,UAAU,YACP,OAAO,YAAA,aACP,OAAO,YAAY,WAAW,OAAO,YAAY,UAC3C,MAAM,IAAI,kBAAkB,SAAS,OAAO,MAAM,MAAM;AAGrE;;;;;;AAOA,eAAe,IACd,QACA,MACA,MACA,SACA,OAAsB,OACN;CAChB,MAAM,SAAS,MAAM,OAAO,KAC3B,MACA,cACA;EACC;EACA;EACA;EACA;EACA;EACA;CACD,GACA,OACD;CACA,IAAI,OAAO,SAAS,GACnB,MAAM,IAAI,gBAAgB,MAAM,GAAG,OAAO,SAAS,OAAO,QAAQ;AAEpE;;AAGA,eAAe,OACd,QACA,MACA,OACmB;CAQnB,QAAO,MAPc,OAAO,KAAK,MAAM,cAAc;EACpD;EACA;EACA;EACA;EACA,GAAG;CACJ,CAAC,EAAA,CACa,SAAS;AACxB;;;;;;;AAQA,eAAsB,WACrB,QACA,SAQoB;CACpB,MAAM,EAAE,MAAM,UAAU;CAExB,MAAM,UAAU,gBAAgB;EAC/B;EACA,cAHoB,kBAAkB,KAGtC;EACA,SAAS,QAAQ;CAClB,CAAC;CACD,OAAA,GAAMC,iBAAAA,MAAAA,EAAAA,GAAMF,UAAAA,QAAAA,CAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAK,OAAA,GAAMG,iBAAAA,SAAAA,CAAS,MAAM,OAAO,CAAC,CAAC,YAAY,KAAA,CAAS,MAAO,SAC9D,OAAA,GAAMC,iBAAAA,UAAAA,CAAU,MAAM,OAAO;CAG9B,MAAM,MAAM,QAAQ,MAAM;EACzB,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;EAC7C,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACnD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;CACpD,CAAC;CACD,MAAM,OAAO,cAAc,KAAK,YAAY;CAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC;CACnC,OAAO,CAAC,IAAI;AACb;;AAGA,SAAgB,WAAW,SAAyB;CACnD,OAAO,GAAG,iBAAiB,GAAG,QAAQ;AACvC;AAEA,SAAS,iBAAiB,SAAmC;CAC5D,OAAO,CACN,GAAG,eAAe,GAAG,QAAQ,OAC7B,GAAG,eAAe,GAAG,QAAQ,KAC9B;AACD;;;;;;;AAQA,eAAsB,gBACrB,QACA,MACA,SACA,QACA,aACoB;CACpB,MAAM,UAAoB,CAAC;CAC3B,MAAM,CAAC,KAAK,OAAO,iBAAiB,OAAO;CAC3C,IAAI,aAAa;EAChB,MAAM,IAAI,QAAQ,MAAM,KAAK,OAAA,GAAMD,iBAAAA,SAAAA,CAAS,YAAY,UAAU,OAAO,CAAC;EAC1E,MAAM,IACL,QACA,MACA,KACA,OAAA,GAAMA,iBAAAA,SAAAA,CAAS,YAAY,SAAS,OAAO,GAC3C,KACD;EACA,QAAQ,KAAK,KAAK,GAAG;CACtB,OACC,MAAM,OAAO,QAAQ,MAAM,CAAC,KAAK,GAAG,CAAC;CAEtC,MAAM,IAAI,QAAQ,MAAM,WAAW,OAAO,GAAG,MAAM;CACnD,QAAQ,KAAK,WAAW,OAAO,CAAC;CAChC,OAAO;AACR;;AAGA,MAAM,eAAe;;;;;AAMrB,eAAsB,iBACrB,QACA,MACA,SACmB;CACnB,MAAM,OAAO,WAAW,OAAO;CAE/B,KAAI,MADgB,OAAO,KAAK,MAAA,WAAoB;EAAC;EAAQ;EAAM;CAAI,CAAC,EAAA,CAC9D,SAAS,GAAG,OAAO;CAG7B,MAAM,IAAI,QAAQ,MAAM,MAAM,YAAY;CAC1C,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,iBAAiB,OAAO,CAAC,CAAC;CAC/D,OAAO;AACR;;;AC5PA,SAAgB,qBACf,WACA,OACA,QACA,UACmB;CACnB,MAAM,WAAWE,cAAAA,qBAChB,UAAUC,cAAAA,iBAAiB,KAAK,GAChC,QACD;CAcA,MAAM,WAXYC,kBAAAA,sBAAsB;EACvC,GAAI,UAAU,QAAQ,YACnB,EAAE,WAAW,UAAU,OAAO,UAAU,IACxC,CAAC;EACJ;EACA,OAAO;EACP,QAAQ;EACR,SAAS;EACT,YAAY;EACZ,MAAMC,cAAAA,cAAc,QAAQ;CAC7B,CAES,CAAC,EAAE,aAAa,gBACrBC,cAAAA,iBAAiB,SAAS,OAAO,IACjC;EAAE,SAAS,SAAS;EAAS,WAAW,CAAC;CAAE;CAE/C,MAAM,YAAYC,cAAAA,UAAU,UAAU,SAAS,QAAQ,UAAU,CAAC,CAAC,IAChEC,cAAAA,kBAAkB,SAAS,OAAO,IAClC;EAAE,SAAS,SAAS;EAAS,WAAW,CAAC;CAAE;CAC9C,OAAO;EACN,SAAS,UAAU;EACnB,WAAW;GACV,GAAG,SAAS;GACZ,GAAG,SAAS;GACZ,GAAG,UAAU;EACd;CACD;AACD;;;;;;;;;;;;;;AClBA,IAAa,wBAAb,cAA2CC,eAAAA,SAAS;CAEzC;CACA;CAFV,YACC,KACA,WACC;EACD,MACC,GAAG,IAAI,yBAAyB,UAAU,sDAC3C;EALS,KAAA,MAAA;EACA,KAAA,YAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,MAAa,cAA2B,EACvC,KACA,IACA,WACA,aACA,WACA,aACK;CACL,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,OAAA,GAAMC,WAAAA,QAAAA,CACX;GACC,MAAM,aAAa,OAAO;GAC1B,MAAM,gBAAgB,OAAO,QAAQ;GACrC,YAAY,OAAO;GACnB,MAAM,GAAG,OAAO,WAAW,OAAO;GAClC,QAAQ;GACR,SAAS,EAAE,MAAM,OAAO,KAAK;GAC7B,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;GACnB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAC3B,SAAS;EACV,IACC,QAAQ;GAER,IAAI,OAAO;GACX,IAAI,GAAG,aAAa,QAAQ,IAAI,cAAc,CAAC,CAAC;GAChD,IAAI,GAAG,SAAS,MAAM;EACvB,CACD;EACA,IAAI,GAAG,iBACN,IAAI,QAAQ,IAAI,sBAAsB,KAAK,SAAS,CAAC,CACtD;EACA,IAAI,GAAG,SAAS,MAAM;EACtB,IAAI,IAAI;CACT,CAAC;AACF;;AAGA,SAAgB,UAAU,QAAyB;CAClD,OAAO,UAAU,OAAO,SAAS;AAClC;;AAGA,IAAa,uBAAb,cAA0CD,eAAAA,SAAS;CAExC;CAEA;CAEA;CALV,YACC,SAEA,MAEA,QAAsC,SACrC;EACD,MAAM,QAAQ,KAAK,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG;EAC7C,MACC,GAAG,QAAQ,gBAAgB,KAAK,WAAW,IAAI,kBAAkB,gBAAgB,sBAAsB,UAAU,UAAU,UAAU,0BAA0B,OAC9J,KAAK,KAAK,EAAE,KAAK,WAAW,OAAO,IAAI,IAAI,MAAM,CAAC,CAAC,KAAK,IAAI,KAC3D,UAAU,UACR,sCAAsC,QAAQ,cAAc,MAAM,OAClE,sFAAsF,QAAQ,QAAQ,MAAM,KACjH;EAbS,KAAA,UAAA;EAEA,KAAA,OAAA;EAEA,KAAA,QAAA;EAUT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACyIA,IAAa,wBAAb,cAA2CE,eAAAA,SAAS;CACnD,cAAc;EACb,MACC,gJAED;EACA,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyCA,eAAAA,SAAS;CACjD,cAAc;EACb,MACC,sJAGD;EACA,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,kBAAb,cAAqCA,eAAAA,SAAS;CAEnC;CACA;CAFV,YACC,UACA,OACC;EACD,MACC,GAAG,SAAS,GAAG,MAAM,qFACtB;EALS,KAAA,WAAA;EACA,KAAA,QAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,gBAAb,cAAmCA,eAAAA,SAAS;CACtB;CAArB,YAAY,MAAuB;EAClC,MACC,0EACQ,KAAK,8FAEd;EALoB,KAAA,OAAA;EAMpB,KAAK,OAAO;CACb;AACD;;;;;;;AAQA,SAAgB,kBAAkB,MAAc,OAAuB;CACtE,QAAA,GAAOC,UAAAA,KAAAA,CAAK,MAAM,kBAAkB,MAAM,KAAK;AAChD;;AAGA,eAAsB,YAAY,MAA+B;CAChE,IAAI;CACJ,IAAI;EACH,OACC,MAAMC,YAAAA,UAAU,OAAO;GAAC;GAAa;GAAW;EAAM,GAAG,EAAE,KAAK,KAAK,CAAC,EAAA,CACrE,KAAK;CACR,QAAQ;EACP,MAAM,IAAI,cAAc,IAAI;CAC7B;CACA,IAAI,CAAC,KAAK,MAAM,IAAI,cAAc,IAAI;CAOtC,QAAO,MAHcA,YAAAA,UAAU,OAAO,CAAC,UAAU,aAAa,GAAG,EAChE,KAAK,KACN,CAAC,CAAC,CAAC,YAAY,EAAE,EAAA,CACH,KAAK,IAAI,GAAG,IAAI,UAAU;AACzC;;AAGA,SAAgB,UAAU,MAAyB,QAAQ,KAIzD;CACD,MAAM,QAAQ,UAAkB,aAAqB;EACpD,MAAM,QAAQ,IAAI;EAClB,IAAI,UAAU,KAAA,KAAa,UAAU,IAAI,OAAO;EAChD,MAAM,OAAO,OAAO,KAAK;EACzB,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OACjD,MAAM,IAAI,gBAAgB,UAAU,KAAK;EAE1C,OAAO;CACR;CACA,MAAM,OAAO,IAAA,2BAAqB,KAAK,eAAe,CAAC,IAAI,KAAA;CAC3D,OAAO;EACN,OAAO,KAAK,cAAc,OAAO,GAAG;EACpC,MAAM,KAAK,cAAc,MAAM,EAAE;EACjC,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACxB;AACD;;;;;AAMA,MAAa,cAA2B;CACvC,QAAQ;CACR,UAAU;CACV,KAAKC,cAAAA;CACL,SAASC,cAAAA;CACT,QAAQC,cAAAA;CACR,SAASC,kBAAAA;CACT,MAAMC,kBAAAA;CACN,OAAO;CACP,gBAAgB;CAChB,kBAAkB;CAClB,KAAK,QAAQ;CACb,QAAQC,YAAAA;CACR,QAAQ;AACT;;;;;;AAWA,eAAsB,gBACrB,KACA,MACA,UAA6B,CAAC,GACR;CACtB,MAAM,EAAE,WAAW,OAAO,UAAU,QAAQ;CAC5C,MAAM,OAAO,UAAU;CACvB,MAAM,OAAO,QAAQ,SAAS,IAAI,WAAW,SAAS;CACtD,MAAM,OAAO,QAAQ,SAAS;CAC9B,IAAI,QAAQ,SAAS,SAAS,MAAM,IAAI,sBAAsB;CAC9D,IAAI,QAAQ,OAAO,SAAS,QAAQ,MAAM,IAAI,oBAAoB;CAKlE,MAAM,WAAW,UAAU,QAAQ;CACnC,IAAI,CAAC,aAAa,QAAQ,SAAS,SAClC,MAAM,IAAI,iBACT,OAAO,SAAS,QAChBC,iBAAAA,SAAS,UAAU,IAAI,KAAK,MAAM,UAAU,MAAM,KAAA,GAAW,GAAG,CACjE;CAKD,MAAM,YAAsC,CAAC;CAC7C,MAAM,aAAuC,CAAC;CAC9C,MAAM,WAAW,MAAMC,iBAAAA,SAAS;EAC/B,UAAUC,cAAAA,eAAe,SAAS;EAClC,KAAK;EACL;EACA;CACD,CAAC;CAED,MAAM,EAAE,SAAS,cAAc,MAAM,aAAa,KAAK,QAAQ;CAG/D,MAAM,SAAS,SAAS,UAAUC,cAAAA,YAAY,SAAS,IAAI,KAAA;CAE3D,MAAM,WAAW,aAAa;EAC7B;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;GACP;GACA;GACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAChC;EACA;EACA,GAAI,UAAU,UAAU,OAAO,QAC5B,EACA,mBAAmB,MAAMC,cAAAA,qBAAqB,SAAS,EAAA,CAAG,YAC3D,IACC,CAAC;EACJ,kBAAkB,IAAI;EACtB,OAAO,UAAU,KAAK,GAAG;EACzB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACnC,CAAC;CAID,IAAI,SAAS,SACZ,kBAAkB,WAAW,UAAU,UAAU,SAAS;CAM3D,MAAM,QAAQ,QAAQ,MACnB,iBAAiB,UAAU,QAAQ,IAAI,MAAM,QAAQ,IAAI,OAAO,IAChE;CAIH,IAAI,SAAS,UAAU,CAAC,IAAI,QAC3B,MAAM,kBAAkB,KAAK,QAAQ,KAAK,CACzC,GAAG,MAAM,MACT,GAAG,MAAM,OACV,CAAC;CAGF,IAAI,MAAM,SAAS,CAAC,MAAM,OAAO,IAAI,QAAQ,KAAK,MAAM,MAAM,QAAQ;CAItE,IAAI,MAAM,SAAS,CAAC,MAAM,SAAS,MAAM,KAAK,sBAAsB;EACnE,IAAI,QAAQ,KAAK,MAAM,KAAK,QAAQ;EACpC,IAAI,QAAQ,KAAK,MAAM,KAAK,OAAO,0BAA0B;CAC9D;CAMA,IAAI,CAAC,QAAQ,CAAC,MAAM,OACnB,YAAA,sBAAsB,OAAO,UAAU,UAAU,QAAQ,SAAS,MAAM;CAEzE,MAAM,SAAS,OACZ,KAAA,IACA,cAAc;EACd;EACA,OAAO,MAAM;EACb,QAAQ,UAAU,QAAQ,SAAS;EACnC,QAAQ,SAAS;CAClB,CAAC;CAEH,MAAM,OAAA,GAAMZ,UAAAA,KAAAA,CAAK,MAAM,SAAS,KAAK,CAAC;CACtC,MAAM,WAAW,kBAAkB,MAAM,KAAK;CAC9C,MAAM,aAAA,GAAYa,QAAAA,WAAAA,CAAW,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC;CACvD,IAAI,UAAU,SAAS,GACtB,IAAI,OAAO,KACV,6BAA6B,MAAM,8BACpC;CAKD,MAAM,WAAW,OAAO,KAAA,IAAY,MAAM,IAAI,MAAM,KAAK,KAAK;CAC9D,MAAM,WAAW,OAAO,YACvB,OAAO,QAAQ,UAAU,MAAM,YAAY,CAAC,CAAC,CAAC,CAAC,KAC7C,CAAC,MAAM,cAAuC;EAC9C,MAAM,EAAE,KAAK,KAAK,WAAW,SAAS;EACtC,OAAO,CACN,MACA;GAAE;GAAK,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;GAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAG,CAC/D;CACD,CACD,CACD;CAEA,OAAO;EACN;EACA;EACA;EACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B;EACA,KAAK;GACJ,SAAS,eAAe,QAAQ;GAChC,OAAA,GAAMb,UAAAA,KAAAA,CAAK,KAAK,oBAAoB;GACpC,GAAI,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;GAC5C,KAAK;GACL,GAAI,SAAS,EAAE,MAAM,WAAW,MAAM,EAAE,IAAI,CAAC;GAC7C,QAAQ,IAAI;GACZ,QAAQ,IAAI;EACb;EACA;EACA;EACA;EACA,OAAO,CAAC;EACR,QAAQ,CAAC;EACT,SAAS,CAAC;CACX;AACD;;;;;;;;AAaA,eAAsB,aACrB,KACA,KACA,MACgB;CAChB,MAAM,EAAE,UAAU;CAIlB,IAAI,MAAM,KACJ;OAAA,MAAM,QAAQ,CAAC,MAAM,IAAI,UAAU,MAAM,IAAI,OAAO,GACxD,IAAI,EAAA,GAACa,QAAAA,WAAAA,CAAW,IAAI,GAAG,MAAM,IAAIC,kBAAAA,sBAAsB,IAAI,OAAO,IAAI;CAAA;CAIxE,IAAI,MAAM,OAAO;CAGjB,IAAI,IAAI,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,MACrC,MAAM,KAAK,OAAO,MAAM,IAAI,MAAM;CAEnC,MAAM,cACL,KACA,MACAC,YAAAA,WAAW,KAAK,CAAC,CAAC,QAAQ,SAAS,CAACC,YAAAA,YAAY,IAAI,CAAC,GACrD,IAAI,SAAS,MACd;AACD;;AAGA,IAAa,qBAAb,cAAwCjB,eAAAA,SAAS;CAC3B;CAArB,YAAY,MAAkC;EAC7C,MACC,6CAA6C,KAAK,KAAK,IAAI,EAAE,GACzD,KAAK,WAAW,IAAI,SAAS,KAAK,mHAGvC;EANoB,KAAA,OAAA;EAOpB,KAAK,OAAO;CACb;AACD;;;;;;;AAQA,SAAS,kBACR,WACA,OACA,UACA,WACO;CACP,IAAI,CAAC,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,SAAS,OAAO,GAAG;CAE3D,MAAM,YAAY,OAAO,OAAO,QAAQ,CAAC,CACvC,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CACjC,SAAS,MAAM,EAAE,YAAY,CAAC,CAAC;CACjC,MAAM,gBAAgB,SACrB,UAAU,MAAM,QAAQ,MAAM,IAAI,GAAG,CAAC;CAgBvC,MAAM,UAAU,CAAC,mBAAG,IAdF,IAAI,CACrB,GAAG,MAAM,KACP,QACC,QACA,IAAI,SAAS,cACb,aAAakB,cAAAA,WAAW,UAAU,IAAI,MAAM,SAAS,CAAC,CACxD,CAAC,CACA,KAAK,MAAM,EAAE,IAAI,GACnB,GAAG,MAAM,QACP,QAAQ,WACR,aAAaC,cAAAA,cAAc,UAAU,OAAO,IAAI,SAAS,CAAC,CAC3D,CAAC,CACA,KAAK,WAAW,OAAO,IAAI,CAC9B,CACwB,CAAC,CAAC,CACxB,QAAQ,SAAS;EACjB,MAAM,MAAM,UAAU,KAAK;EAC3B,OAAO,OAAO,CAACC,gBAAAA,eAAAA,GAAcnB,UAAAA,KAAAA,CAAK,UAAU,MAAM,IAAI,IAAI,GAAG,SAAS;CACvE,CAAC,CAAC,CACD,KAAK;CACP,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,mBAAmB,OAAO;AAC7D;;;;;;;;;;;;;AAcA,eAAe,cACd,KACA,MACA,OACA,QACgB;CAChB,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,SAASoB,YAAAA,sBACd,OACA,UAAU,UAAU,QACpB,MACD;CACA,IAAI,MAAM,WAAW,GAAG;CACxB,IAAI,IAAI,SAAS;EAChB,IAAI,OAAO,KACV,8DACD;EACA;CACD;CACA,IAAI,CAAC,QAAQ;EACZ,IAAI,OAAO,KACV,sBAAsBC,kBAAAA,gBAAgB,OAAO,MAAM,gBAAgBC,YAAAA,kBAAkB,KAAK,GAC3F;EACA;CACD;CACA,MAAM,OAAO,SAAiB,IAAI,OAAO,KAAK,IAAI;CAClD,IAAI,UAAU,KACb,IACC,eAAe,MAAM,MAAM,OAAO,OAAO,OAAO,OAAO,MAAM,OAAO,SAAS,KAAK,IAAI,SAAS,oCAAoC,IACpI;CAED,IAAI;EACH,MAAM,SAAS,MAAMC,YAAAA,SAAS;GAC7B;GACA;GACA;GACA,KAAK,UAAU;GACf,aAAa,IAAI;GACjB;GACA,QAAQ,KAAK,UAAUhB,YAAAA;GACvB,GAAI,IAAI,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;GACrC,GAAI,KAAK,iBAAiB,EAAE,aAAa,KAAK,eAAe,IAAI,CAAC;EACnE,CAAC;EAED,IAAI,CAAC,IAAI,QAAQ;GAChB,MAAM,UAAU,MAAMiB,cAAAA,cAAc,KAAK,IAAI,OAAO,aACnDC,cAAAA,mBAAmB,KAAK,CACzB;GACA,MAAM,YAAY,IAAI,IACrB,OAAO,KAAK,QAAQ,KAAK,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CACtD;GACA,MAAMC,cAAAA,iBAAiB,SAAS,OAAO,UAAU,WAChD,UAAU,IAAI,MAAM,CACrB;EACD;EACA,MAAM,QAAQ,CACb,OAAO,UAAU,SAAS,IACvB,GAAG,OAAO,UAAU,OAAO,OAAO,OAAO,UAAU,WAAW,IAAI,KAAK,IAAI,kCAC3E,IACH,OAAO,SAAS,SAAS,IACtB,GAAG,OAAO,SAAS,OAAO,OAAO,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,UAAU,OAAO,SAAS,WAAW,IAAI,MAAM,GAAG,MAAM,OAAO,SACxI,EACJ,CAAC,CAAC,OAAO,OAAO;EAChB,IAAI,MAAM,SAAS,GAAG,IAAI,MAAM,MAAM,KAAK,IAAI,GAAG;CACnD,SAAS,OAAO;EACf,IAAI,IAAI,UAAU,iBAAiBC,YAAAA,yBAAyB;GAC3D,IAAI,OAAO,KAAK,KAAK,MAAM,SAAS;GACpC;EACD;EACA,MAAM;CACP;AACD;;;;;;;AAQA,eAAe,aACd,KACA,UACiE;CACjE,MAAM,SAAS,MAAM,IAAI,QAAQ,KAAK;CACtC,IAAI,IAAI,UAAU,IAAI,UAAU,OAAO,OAGtC,OAAO;EAAE,SAAS;EAAQ,WAAW,CAAC;CAAE;CAGzC,MAAM,EAAE,SAAS,cAAc,qBAC9B,IAAI,WACJ,IAAI,OACJ,QACA,QACD;CAEA,IAAI,QAAQ,MAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI;CAC/C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,UAAU,CAAC,CAAC,GAC7D,IAAI,CAACC,kBAAAA,mBAAmB,GAAG,GAAG,IAAI,QAAQ,KAAK,KAAK;CAErD,OAAO;EAAE;EAAS;CAAU;AAC7B;;;;;;AAOA,SAAS,iBACR,OACA,MACA,SACe;CACf,MAAM,OAAO,UAAU,MAAM,SAAS,MAAM,IAAI;CAChD,MAAM,UAAU,UAAU,MAAM,SAAS,MAAM,OAAO;CACtD,MAAM,WAAW,EAAE,GAAG,MAAM,QAAQ,SAAS;CAC7C,KAAK,MAAM,SAAS,CAAC,GAAG,MAAM,GAAG,OAAO,GACvC,SAAS,MAAM,QAAQ;EAAE,GAAG,SAAS,MAAM;EAAQ,OAAO,MAAM;CAAI;CAErE,OAAO;EACN,GAAG;EACH;EACA;EACA,SAAS;GAAE,GAAG,MAAM;GAAS;EAAS;CACvC;AACD;;;;;;AAWA,eAAsB,YACrB,KACA,KACgB;CAChB,IAAI,IAAI,UAAU,SAAS,GAC1B,IAAI,OAAO,KACV,OAAO,IAAI,MAAM,WAAW,IAAI,UAAU,KAAK,IAAI,EAAE,gDACtD;CAED,IAAI,QAAQ,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK;CACxD,UAAU,KAAK,GAAG;CAIlB,IAAI,CAAC,IAAI,QAAQ,IAAI,MAAM,MAAM,SAAS,UAAU,GACnD,cAAA,oBAEE,MAAMC,kBAAAA,aAAa;EAAE,MAAM,IAAI,UAAU;EAAM,UAAU,IAAI;CAAS,CAAC,EAAA,CACtE,KAAK,EAAE,QAAQ,aAAa;EAAE,QAAQ,OAAO;EAAO;CAAM,EAAE,IAC7D,SAAS,IAAI,OAAO,KAAK,IAAI,CAC/B;CAGD,MAAM,WAAW,WAA2B;EAC3C,IAAI,QAAQ,KAAK,MAAM;EACvB,IAAI,KAAK;GAAE,MAAM;GAAoB,GAAG;EAAO,CAAC;CACjD;CACA,KAAK,MAAM,WAAW,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,OAC/C,QAAQ;EACP,KAAK,WAAW;EAChB,cAAc;EACd,QAAQ;CACT,CAAC;CAEF,KAAK,MAAM,OAAO,IAAI,MAAM,MAAM;EACjC,QAAQ;GACP,KAAK,SAAS,IAAI;GAClB,cAAc;GACd,QAAQ,IAAI,SAAS,UAAU,UAAU;GACzC,IAAI,IAAI;EACT,CAAC;EACD,IAAI,IAAI,MAAM;EACd,QAAQ;GACP,KAAK,WAAW,IAAI;GACpB,cAAc;GACd,QAAQ,IAAI,SAAS,IAAI,QAAQ,UAAU;EAC5C,CAAC;CACF;CACA,KAAK,MAAM,UAAU,IAAI,MAAM,SAAS;EACvC,QAAQ;GACP,KAAK,SAAS,OAAO;GACrB,cAAc;GACd,QAAQ,IAAI,SAAS,UAAU,UAAU;GACzC,IAAI,OAAO;EACZ,CAAC;EACD,IAAI,IAAI,MAAM;EACd,QAAQ;GACP,KAAK,WAAW,OAAO;GACvB,cAAc;GACd,QAAQ,IAAI,SAAS,OAAO,QAAQ,UAAU;EAC/C,CAAC;CACF;CACA,IAAI,CAAC,IAAI,MACR,QAAQ;EACP,KACC,IAAI,MAAM,UAAU,UACjB,kBACA,WAAW,aAAa,GAAG;EAC/B,cAAc;EACd,QAAQ;CACT,CAAC;AAEH;;;;;;AAWA,eAAsB,iBACrB,KACA,KACA,MACgB;CAChB,MAAM,EAAE,OAAO,QAAQ;CAEvB,IAAI,IAAI,MAAM;CAEd,IAAI,IAAI,UAAU,SAAS,KAAK,IAAI,SAAS;EAC5C,MAAM,IAAI,QAAQ,MAAM,IAAI,OAAO;EACnC,IAAI,OAAO,KACV,qBAAqB,IAAI,MAAM,KAAK,IAAI,QAAQ,MAAM,KAAK,IAAI,UAAU,KAAK,IAAI,GACnF;CACD;CAIA,MAAM,QAAQ,UAAU,KAAK,GAAG;CAChC,MAAM,gBAAgB,KAAK,QAAQ;EAClC,SAAS,MAAM;EACf,OAAO,MAAM;EACb;EACA,QAAQ;CACT,CAAC;CAED,IAAI,QAAQ,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,KAAK;CACpD,UAAU,KAAK,GAAG;CAIlB,IAAI,MAAM,UAAU,WAAW;EAC9B,IAAI,OAAO,KAAK,kCAAkC,aAAa,GAAG;EAClE,IAAI,MAAM,KACT,GAAI,MAAM,WAAW,KAAK,QAAQ;GACjC,MAAM,SAAS,GAAG;GAClB;GACA,GAAI,IAAI,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;GACrC,SAAS;IACR,QAAQ,aAAa;IACrB,SAAS,EAAE,GAAG,aAAa,QAAQ;GACpC;GACA,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;GAC3C,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC5C,CAAC,CACF;EACA,QAAQ,KAAK,KAAK;GACjB,KAAK,WAAW,aAAa,GAAG;GAChC,cAAc;GACd,QAAQ;GACR,IAAI,GAAG,aAAa,GAAG;GACvB,KAAK;EACN,CAAC;CACF;CAEA,IAAI,MAAM,MAAM,SAAS,GAAG;EAC3B,IAAI,OAAO,KAAK,mBAAmB,MAAM,MAAM,KAAK,IAAI,EAAE,EAAE;EAC5D,MAAM,KAAK,OAAO,GAAG,KAAK,MAAM,KAAK;EACrC,KAAK,MAAM,WAAW,MAAM,OAC3B,QAAQ,KAAK,KAAK;GACjB,KAAK,WAAW;GAChB,cAAc;GACd,QAAQ;GACR,IAAI,GAAG,MAAM,QAAQ,GAAG;GACxB,KAAK,OAAO,KAAK,IAAI,QAAQ,CAAC,CAAC,SAAS,IAAI,aAAa;EAC1D,CAAC;CAEH;CAEA,IAAI,MAAM,MAAM,SAAS,UAAU,GAClC,MAAM,iBAAiB,KAAK,KAAK,IAAI;CAEtC,IAAI,MAAM,WAAW,MAAM,MAAM,SAAS,OAAO,GAChD,MAAM,eAAe,KAAK,KAAK,IAAI;AAErC;;;;;;AAOA,eAAe,eACd,KACA,KACA,MACgB;CAChB,MAAM,UAAU,IAAI,MAAM;CAC1B,IAAI,QAAQ,QAAQ,WAAW,GAAG;CAElC,MAAM,SAAS,MAAM,MAAM,KAAK,MAAM,SAAS,GAAI;CACnD,IAAI;CACJ,IAAI;EACH,MAAM,SAAS,KAAK,QAAQ,OAAO,MAAM,OAAO;EAChD,OAAO,CACN,GAAI,MAAMC,cAAAA,aAAa,QAAQ,QAAQ,OAAO,GAC9C,GAAI,MAAMC,cAAAA,cAAc,QAAQ,QAAQ,QAAQ,CACjD;CACD,UAAU;EACT,MAAM,OAAO,MAAM;CACpB;CACA,MAAM,UAAU,KAAK,QAAQ,UAAU,MAAM,OAAO,CAAC,CAAC;CACtD,IAAI,OAAO,KACV,gBAAgB,QAAQ,QAAQ,KAAK,IAAI,IAAI,UAAU,KAAK,QAAQ,eAAe,IACpF;AACD;;;;;AAMA,eAAe,iBACd,KACA,KACA,MACgB;CAChB,MAAM,SAAS,MAAM,MAAM,KAAK,MAAM,YAAY,IAAI;CACtD,IAAI;EACH,MAAM,eAAe,KAAK,KAAK,MAAM,OAAO,IAAI;CACjD,UAAU;EACT,MAAM,OAAO,MAAM;CACpB;AACD;;;;;;;;;;;AAYA,eAAe,MACd,KACA,MACA,SACA,QACwD;CACxD,MAAM,YAAY,MAAM,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS,MAAM;CACjE,IAAI,CAAC,IAAI,QAAQ,OAAO;EAAE,MAAM;EAAW,OAAO,YAAY,CAAC;CAAE;CACjE,OAAO,KAAK,OAAO,OAAO,IAAI,QAAQ,SAAS;AAChD;AAEA,eAAe,eACd,KACA,KACA,MACA,MACgB;CAChB,MAAM,EAAE,UAAU;CAClB,MAAM,YAAiC,IAAI;CAK3C,MAAM,YAAY,MAAM,WAAW,WAAW;CAC9C,MAAM,QAAQ,MAAM,KAAK,OAAO;EAC/B;EACA,OAAO;EACP,QAAQ,CACP;GAAE,MAAMC,cAAAA,mBAAmB;GAAM,UAAU,UAAU;EAAS,GAC9D,GAAI,MAAM,QAAQ,CAACA,cAAAA,kBAAkB,IAAI,CAAC,CAC3C;CACD,CAAC;CACD,IAAI,MAAM,QAAQ,IAAI,OAAO,KAAK,MAAM,MAAM;CAE9C,MAAM,aAAa,CAClB,GAAGC,cAAAA,mBAAmB,MAAM,MAAM,UAAU,MAAM,MAAM,WAAW,IAAI,GAEvE,GAAI,MAAM,UAAUC,YAAAA,sBAAsB,MAAM,OAAO,IAAI,CAAC,CAC7D;CACA,IAAI,WAAW,SAAS,GAAG;EAC1B,IAAI,OAAO,KAAK,4CAA4C;EAC5D,MAAMC,cAAAA,cAAc,KAAK,IAAI,MAAM,MAAM,KAAK,GAAG,UAAU;CAC5D;CAKA,MAAM,UAA2C,CAAC;CAClD,MAAM,WAAW,MAAM1B,iBAAAA,SAAS;EAC/B,UAAUC,cAAAA,eAAe,SAAS;EAClC,KAAK,UAAU;EACf;CACD,CAAC;CAGD,MAAM,MAAM0B,cAAAA,OAAO,MAAM,MAAM;EAC9B,OAAO,GAAGC,cAAAA,eAAe,UAAU,IAAI,KAAK;EAC5C,SAAS,UAAU;EACnB,aAAa;GACZ,GAAG,MAAM,WAAW;GACpB,UAAU,MAAM;EACjB;EACA,MAAM,MAAM,WAAW;CACxB,CAAC;CACD,MAAM,UAAU;EAAE,MAAM,UAAU;EAAM;EAAU;EAAS;CAAI;CAC/D,MAAM,OAAO,MAAM,KAAK,QAAQ,OAAO;CAIvC,MAAM,QAAQ,MAAM,KAClB,KAAK;EAAE,GAAG;EAAS,OAAO,IAAI;CAAM,CAAC,CAAC,CACtC,OAAO,UAAmB;EAC1B,IAAI,iBAAiBC,kBAAAA,YACpB,MAAM,IAAIC,cAAAA,kBACT,IAAI,OACJ,MAAM,WACN,MAAM,MACN,KACD;EAED,MAAM;CACP,CAAC;CAEF,cAAA,mBACC,KAAK,KAAK,EAAE,QAAQ,eAAe;EAClC,WAAW,OAAO;EAClB,QAAQ,OAAO;EACf;CACD,EAAE,GACF,MAAM,KAAK,EAAE,QAAQ,cAAc;EAClC,WAAW,OAAO;EAClB,QAAQ,OAAO;EACf;CACD,EAAE,IACD,SAAS,IAAI,OAAO,KAAK,IAAI,IAC7B,UAAU,IAAI,KAAK,KAAK,CAC1B;AACD;;;;;;AAWA,eAAsB,aACrB,KACA,KACA,MACgB;CAChB,MAAM,EAAE,OAAO,QAAQ;CACvB,MAAM,SAAS,CAAC,GAAG,MAAM,MAAM,GAAG,MAAM,OAAO;CAC/C,MAAM,OAAO,OAAO,KAAK,UAAU,MAAM,GAAG;CAG5C,IAAI,IAAI,MAAM;EACb,IAAI,QAAQ,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,KAAK;EACpD,UAAU,KAAK,GAAG;CACnB;CAEA,IAAI,IAAI,SAAS,SAAS;EACzB,IAAI,OAAO,KAAK,uBAAuB;EACvC,MAAM,KAAK,OAAO,MAAM,KAAK,IAAI;CAClC,OAAO;EACN,IAAI,OAAO,KAAK,gBAAgB,IAAI,IAAI,EAAE;EAC1C,MAAM,KAAK,OAAO,KAAK,KAAK,IAAI;CACjC;CAEA,IAAI,IAAI,MAAM,IAAI,OAAO,KAAK,sBAAsB;CAIpD,KAAK,MAAM,SAAS,QAAQ;EAC3B,MAAM,SAAS,IAAI,OAChB,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,GAAG,IACrC,MAAM,KAAK,OAAO,OAAO,KAAK,MAAM,GAAG;EAC1C,IAAI,IAAI,MACP,IAAI,OAAO,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,EAAE,GAAG,MAAM,IAAI,GAAG,QAAQ;EAEpE,IAAI,OAAO,MAAM,OAAO;GACvB,KAAK,MAAM;GACX,KAAK,MAAM;GACX,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC5B;EACA,IAAI,KAAK;GACR,MAAM;GACN,KAAK,MAAM;GACX,UAAU,MAAM;GAChB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC5B,CAAC;EACD,IAAI,QAAQ,KAAK;GAChB,KAAK,SAAS,MAAM;GACpB,cAAc;GACd,QAAQ,IAAI,SAAS,UAAU,UAAU;GACzC,IAAI,UAAU,MAAM;EACrB,CAAC;CACF;AACD;;;;;AAUA,eAAsB,eACrB,KACA,KACA,MACgB;CAChB,MAAM,EAAE,OAAO,QAAQ;CAEvB,IAAI,IAAI,MAAM;CAEd,IAAI,OAAO,KAAK,0BAA0B;CAC1C,MAAM,KAAK,OAAO,GAAG,GAAG;CAMxB,MAAM,OAAO,QAAQ,SAAS,GAAG,GAAG;EACnC,GAAI,IAAI,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;EACrC,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;CAC5C,CAAC;CACD,IAAI,MAAM,UAAU,aAAa,MAAM,SAAS;EAC/C,MAAM,UAAU,MAAM,gBACrB,KAAK,QACL,MACA,MAAM,SACN,MAAM,SACN,MAAM,GACP;EACA,IAAI,OAAO,KACV,iBAAiB,MAAM,OAAO,OAAO,iBAAiB,aAAa,IAAI,QAAQ,GAAG,EAAE,GACrF;CACD,OAAO,IAAI,CAAC,MAAM,OACjB,MAAM,iBAAiB,KAAK,QAAQ,MAAM,MAAM,OAAO;CAGxD,IAAI,MAAM,OAGT,MAAM,KAAK,OACT,QACA,KACA,SACA,8CACA,OAAO,GAAG,CACX,CAAC,CACA,YAAY,CAAC,CAAC;CAGjB,MAAM,aAAa,KAAK,GAAG;CAE3B,KAAK,MAAM,OAAO,MAAM,MAAM;EAC7B,MAAM,QAAQ,IAAI,OAAO,IAAI;EAC7B,QAAQ,KAAK,KAAK;GACjB,KAAK,WAAW,IAAI;GACpB,cAAc;GACd,QAAQ;GACR,IAAI,GAAG,MAAM,QAAQ,GAAG,IAAI;GAC5B,KAAK,IAAI,SAAS,IAAI,QAAQ,aAAa;EAC5C,CAAC;EACD,IAAI,KAAK;GACR,MAAM;GACN,KAAK,IAAI;GACT,eAAe,GAAG,MAAM,QAAQ,GAAG,IAAI;GACvC,UAAU,OAAO,OAAO,IAAI;GAC5B,KAAK,IAAI;EACV,CAAC;CACF;CAGA,KAAK,MAAM,UAAU,MAAM,SAC1B,QAAQ,KAAK,KAAK;EACjB,KAAK,WAAW,OAAO;EACvB,cAAc;EACd,QAAQ;EACR,IAAI,GAAG,MAAM,QAAQ,GAAG,OAAO;EAC/B,KAAK,IAAI,SAAS,OAAO,QAAQ,aAAa;CAC/C,CAAC;CAGF,IAAI,OAAO,KAAK,OAAO,MAAM,QAAQ,aAAa;CAClD,KAAK,MAAM,OAAO,MAAM,MACvB,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK,OAAO,EAAE,EAAE,GAAG,IAAI,KAAK;CAEvD,KAAK,MAAM,UAAU,MAAM,SAC1B,IAAI,OAAO,KAAK,MAAM,OAAO,KAAK,OAAO,EAAE,EAAE,UAAU,OAAO,IAAI;CAEnE,IAAI,MAAM,OACT,IAAI,OAAO,KACV,qEAAA,GAAoEvC,UAAAA,KAAAA,CAAK,SAAS,IAAI,KAAK,GAAG,gBAAgB,GAC/G;AAEF;;;;;;AAOA,eAAe,aACd,KACA,KACgB;CAChB,MAAM,UAAU,MAAMwB,cAAAA,cAAc,KAAK,IAAI,OAAO,IAAI,aACvDC,cAAAA,mBAAmB,IAAI,KAAK,CAC7B;CACA,MAAM,KAAKe,cAAAA,aAAa;CACxB,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,OAAO,GAAG;EAC5D,MAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ;GAAE,KAAK,IAAI;GAAK,KAAK,IAAI;EAAI;EAClE,cAAA,cAAc,QAAQ,OAAO,IAAI,KAAK,OAAO,EAAE;CAChD;CACA,QAAQ,MAAM,WAAW,IAAI,SAAS;CACtC,MAAM,QAAQ,KAAK;AACpB;;;;;;;AAYA,eAAsB,cACrB,KACA,KACA,MACgB;CAChB,MAAM,EAAE,UAAU;CAClB,IAAI,IAAI,MAAM;CACd,MAAM,KAAK,MAAM,QACd,OAAA,GAAMC,iBAAAA,SAAAA,CAAS,OAAO,GAAG,GAAG,OAAO,CAAC,CAAC,YAAY,KAAA,CAAS,IAC1D,KAAA;CAEH,IAAI,OAAO,KACV,kCAAkC,MAAM,UAAU,UAAU,UAAU,kBAAkB,EACzF;CAKA,MAAM,OAAO,MAAM,QAChB,EAAE,WAAW,YAAY,IACzB,IAAI,SACH;EAAE,WAAW,IAAI,OAAO;EAAM,aAAa,UAAU,KAAK,GAAG,CAAC,CAAC;CAAM,IACrE,KAAA;CACJ,MAAM,UAAU,MAAM,QAAQ,IAC7B,MAAM,KAAK,KAAK,QAAQ,SAAS,KAAK,KAAK,MAAM;EAAE;EAAI;CAAK,CAAC,CAAC,CAC/D;CAIA,QAAQ,KACP,GAAI,MAAM,QAAQ,IACjB,MAAM,QAAQ,KAAK,WAClB,eAAe,KAAK,KAAK,MAAM,OAAO,IAAI,CAC3C,CACD,CACD;CACA,IAAI,MAAM,MACT,QAAQ,KAAK,MAAM,eAAe,KAAK,KAAK,MAAMC,cAAAA,YAAY,CAAC;CAGhE,MAAM,OAAO,QACX,QAAQ,WAAW,CAAC,OAAO,OAAO,CAAC,CACnC,KAAK,EAAE,KAAK,KAAK,YAAY;EAAE;EAAK;EAAK;CAAK,EAAE;CAClD,IAAI,KAAK,SAAS,GACjB,MAAM,IAAI,qBAAqB,MAAM,SAAS,MAAM,MAAM,KAAK;CAGhE,IAAI,MAAM,MAAM,WAAW,KAAK,MAAM,MAAM,MAAM,OAAO,IAAI,MAAM;AACpE;;;;;;;AAQA,eAAe,eACd,KACA,KACA,MACA,SACwE;CACxE,MAAM,MAAM,UAAU;CACtB,IAAI,OAAO;CAEX,KAAK,IAAI,UAAU,GAAG,WAAW,KAAK,gBAAgB,WAAW;EAChE,IAAI,OAAO,eAAe;EAC1B,MAAM,SAAS,MAAM,KAAK,OACxB,OAAO,IAAI,KAAK,OAAO,CAAC,CACxB,OAAO,UACP,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACtD;EACD,OAAO,UAAU;EACjB,MAAM,UAAU,WAAW;EAC3B,IAAI,KAAK;GACR,MAAM;GACN,KAAK;GACL;GACA;GACA;EACD,CAAC;EACD,IAAI,SAAS;GACZ,IAAI,OAAO,KAAK,QAAQ,QAAQ,OAAO,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;GAC7D,OAAO;IAAE,KAAK;IAAS;IAAK;IAAM;GAAQ;EAC3C;EACA,IAAI,UAAU,KAAK,gBAClB,MAAM,IAAI,SAAS,YAClB,WAAW,SAAS,KAAK,gBAAgB,CAC1C;CAEF;CAEA,IAAI,OAAO,KAAK,QAAQ,QAAQ,OAAO,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;CAC7D,OAAO;EAAE,KAAK;EAAS;EAAK;EAAM,SAAS;CAAM;AAClD;;AAGA,SAAS,WACR,KACA,MACA,OACA,QACO;CACP,MAAM,QAAQC,cAAAA,WAAW,MAAM;EAC9B,OAAO,IAAI;EACX;EACA,MAAM,QAAQ,QAAQ,YAAY;EAClC,UAAU,QAAQ,SAAA,GAAQC,QAAAA,SAAAA,CAAS;EACnC,GAAI,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CACjC,CAAC;CACD,IAAI,OAAO,KAAK,KAAK,MAAM,KAAK,IAAI,GAAG;CACvC,IAAI,KAAK;EACR,MAAM;EACN,SAASF,cAAAA;EACT,QAAQ,KAAK,SAAS,WAAW;EACjC,KAAK,KAAK;EACV,GAAI,KAAK,SAAS,EAAE,OAAO,CAAC,GAAG,KAAK,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,KAAK;EACxE,OAAO,KAAK;CACb,CAAC;AACF;;AAGA,SAAS,cAAsB;CAC9B,IAAI;EACH,QAAA,GAAOG,QAAAA,SAAAA,CAAS,CAAC,CAAC;CACnB,QAAQ;EACP,OAAO,QAAQ,IAAI,QAAQ;CAC5B;AACD;AAEA,eAAe,SACd,KACA,KACA,MACA,SAIwE;CACxE,MAAM,MAAM,GAAG,IAAI,MAAM,IAAI,SAAS,SAAS,MAAM;CACrD,IAAI,OAAO;CAEX,KAAK,IAAI,UAAU,GAAG,WAAW,KAAK,gBAAgB,WAAW;EAChE,IAAI,OAAO,eAAe;EAC1B,IAAI;EACJ,IAAI;GACH,SAAS,MAAM,KAAK,MAAM;IACzB;IACA,GAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;IACvC,GAAG,QAAQ;IACX,WAAW;IACX,QAAQ,IAAI;GACb,CAAC;GACD,OAAO,QAAQ;EAChB,SAAS,OAAO;GACf,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC7D;EAEA,MAAM,UAAU,WAAW,KAAA,KAAa,UAAU,MAAM;EACxD,IAAI,KAAK;GACR,MAAM;GACN,KAAK,IAAI;GACT;GACA;GACA,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;GACzC;EACD,CAAC;EACD,IAAI,SAAS;GACZ,IAAI,OAAO,KAAK,QAAQ,IAAI,KAAK,OAAO,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;GAC9D,OAAO;IAAE,KAAK,IAAI;IAAM;IAAK;IAAM;GAAQ;EAC5C;EACA,IAAI,UAAU,KAAK,gBAClB,MAAM,IAAI,SAAS,YAClB,WAAW,SAAS,KAAK,gBAAgB,CAC1C;CAEF;CAEA,IAAI,OAAO,KAAK,QAAQ,IAAI,KAAK,OAAO,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE;CAC9D,OAAO;EAAE,KAAK,IAAI;EAAM;EAAK;EAAM,SAAS;CAAM;AACnD;AAMA,SAAgB,cACf,KACA,KACe;CACf,MAAM,OAAO,CACZ,GAAG,IAAI,MAAM,KAAK,KAAK,QAAQ;EAC9B,MAAM,QAAQ,IAAI,OAAO,IAAI;EAC7B,OAAO;GACN,SAAS,IAAI;GACb,MAAM,IAAI,SAAS,SAAU,QAAmB;GAChD,SAAS,CAAC,IAAI;GACd,eAAe,GAAG,IAAI,MAAM,QAAQ,GAAG,IAAI;GAC3C,UAAU,OAAO,OAAO,IAAI;GAC5B,GAAI,OAAO,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;GAChD,KAAK,IAAI;EACV;CACD,CAAC,GACD,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;EACpC,MAAM,QAAQ,IAAI,OAAO,OAAO;EAChC,OAAO;GACN,SAAS,OAAO;GAChB,MAAM;GACN,SAAS,CAAC,IAAI;GACd,eAAe,GAAG,IAAI,MAAM,QAAQ,GAAG,OAAO;GAC9C,UAAU,OAAO,OAAO,OAAO;GAC/B,GAAI,OAAO,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EACjD;CACD,CAAC,CACF;CACA,OAAO;EACN;EACA,WAAW,IAAI,MAAM;EACrB,cAAc,IAAI,SAAS,IAAI,KAAK;EACpC,aAAa;EACb,OAAO,IAAI;EACX,UAAU,IAAI,SAAS;EACvB,KAAK,IAAI;EACT,QAAQ,IAAI;EACZ,eAAe;EACf,SAAS,CAAC,GAAG,IAAI,OAAO;EACxB,MAAM,OAAO,YAAY,IAAI,MAAM,KAAK,KAAK,QAAQ,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC;EACzE,SAAS,IAAI;CACd;AACD;AAMA,SAAS,OAAO,KAAyB;CACxC,QAAA,GAAO7C,UAAAA,KAAAA,CAAK,IAAI,KAAK,gBAAgB;AACtC;;AAGA,SAAS,SAAS,KAAyB;CAC1C,QAAA,GAAOA,UAAAA,KAAAA,CAAK,IAAI,KAAK,GAAG,aAAa,KAAK;AAC3C;AAEA,SAAS,QACR,KACA,KACA,QAIO;CACP,MAAM,EAAE,KAAK,GAAG,SAAS;CACzB,IAAI,QAAQ,KAAK,IAAI;CACrB,IAAI,KAAK;EAAE,MAAM;EAAoB,GAAG;EAAM;CAAI,CAAC;AACpD;;AAGA,eAAe,WACd,MACA,KACA,OACoB;CACpB,OAAA,GAAM8C,iBAAAA,MAAAA,CAAM,KAAK;EAAE,WAAW;EAAM,MAAM;CAAM,CAAC;CACjD,OAAA,GAAMC,iBAAAA,MAAAA,CAAM,KAAK,GAAK;CAEtB,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,OAAO,MAAc,SAAiB,OAAO,QAAU;EACpE,OAAA,GAAMD,iBAAAA,MAAAA,EAAAA,GAAME,UAAAA,QAAAA,CAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAC9C,OAAA,GAAMC,iBAAAA,UAAAA,CAAU,MAAM,SAAS,EAAE,KAAK,CAAC;EACvC,OAAA,GAAMF,iBAAAA,MAAAA,CAAM,MAAM,IAAI;EACtB,MAAM,KAAK,IAAI;CAChB;CAKA,MAAM,MACL,MAAM,UAAU,WAAW,MAAM,MAC9B;EACA,MAAM,OAAA,GAAMN,iBAAAA,SAAAA,CAAS,MAAM,IAAI,UAAU,OAAO;EAChD,KAAK,OAAA,GAAMA,iBAAAA,SAAAA,CAAS,MAAM,IAAI,SAAS,OAAO;CAC/C,IACC,KAAA;CACJ,MAAM,UACL,MAAM,cAAc,KAAA,IACjB,iBAAiB,MAAM,SAAS;EAChC,WAAW,MAAM;EACjB,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;CACtB,CAAC,IACA,MAAM;CACV,MAAM,OAAA,GACLzC,UAAAA,KAAAA,CAAK,KAAK,oBAAoB,GAC9B,YAAY,OAAO,OAAO,GAC1B,MAAM,MAAQ,GACf;CAIA,IAAI,MAAM,cAAc,KAAA,GAAW;EAClC,MAAM,OAAA,GAAMA,UAAAA,KAAAA,CAAK,KAAK,WAAW,GAAG,MAAM,SAAS;EACnD,OAAA,GAAMkD,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAK,aAAa,GAAG,EAAE,OAAO,KAAK,CAAC;CACnD,OACC,OAAA,GAAMkD,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAK,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;CAEjD,IAAI,MAAM,YAAY,KAAA,GACrB,MAAM,OAAA,GAAMA,UAAAA,KAAAA,CAAK,KAAK,aAAa,GAAG,MAAM,OAAO;CAGpD,OAAA,GAAMkD,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAK,KAAK,GAAG;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAI3D,KAAK,MAAM,OAAO,CAAC,GAAG,MAAM,MAAM,GAAG,MAAM,OAAO,GACjD,IAAI,IAAI,KACP,MAAM,OAAA,GAAMA,UAAAA,KAAAA,CAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,QAAQ,IAAI,GAAG,GAAG,GAAK;CAGnE,IAAI,MAAM,QAAQ,MAAM,QAAQ,SAAA,cAAsB,EAAE,UACvD,MAAM,OAAA,GACLA,UAAAA,KAAAA,CAAK,KAAK,GAAG0C,cAAAA,aAAa,KAAK,GAC/B,QAAQ,MAAM,KAAK,GAAG,GACtB,GACD;CAED,IAAI,MAAM,SAAS,MAAM,QAAQ,SAAA,QAAuB,EAAE,UACzD,MAAM,OAAA,GACL1C,UAAAA,KAAAA,CAAK,KAAK,GAAGmD,cAAAA,cAAc,KAAK,GAChC,QAAQ,MAAM,MAAM,GAAG,GACvB,GACD;CAID,IAAI,MAAM,SAAS;EAClB,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,MAAM,QAAQ,KAAK,GAC/D,MAAM,OAAA,GAAMnD,UAAAA,KAAAA,CAAK,KAAKoD,YAAAA,iBAAiB,IAAI,GAAG,OAAO;EAEtD,IAAI,MAAM,QAAQ,SAAA,UAAyB,EAAE,UAC5C,MAAM,OAAA,GACLpD,UAAAA,KAAAA,CAAK,KAAK,GAAGoD,YAAAA,gBAAgB,KAAK,GAClC,QAAQ,MAAM,QAAQ,GAAG,GACzB,GACD;CAEF,OAAO;EACN,OAAA,GAAMF,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAKoD,YAAAA,eAAe,GAAG;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACrE,OAAA,GAAMF,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAK,GAAGoD,YAAAA,gBAAgB,KAAK,GAAG,EAAE,OAAO,KAAK,CAAC;CAC9D;CAGA,KAAK,MAAM,SAAS,OAAA,GAAMC,iBAAAA,QAAAA,CAAQ,GAAG,GACpC,IAAI,MAAM,SAAS,cAAc,GAAG,OAAA,GAAMH,iBAAAA,GAAAA,EAAAA,GAAGlD,UAAAA,KAAAA,CAAK,KAAK,KAAK,CAAC;CAE9D,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,MAAM,WAAW,GAC7D,MAAM,OAAA,GAAMA,UAAAA,KAAAA,CAAK,MAAM,IAAI,GAAG,OAAO;CAMtC,MAAMsD,cAAAA,mBAAmBC,cAAAA,cAAc,IAAI,CAAC;CAE5C,OAAO;AACR;AAEA,SAAS,YACR,OACA,SACS;CACT,MAAM,QAAQ,YAAY,MAAM;CAChC,OAAO;QACA,MAAM,MAAM,iCAAiC,MAAM,UAAU,UAAU,cAAc,4BAA4B,aAAa,GAAG;;;;iBAIxH,MAAM;iBACN,MAAM;GACrBC,GAAAA,KAAAA,UAAAA,CAAU,SAAS;EAAE,WAAW;EAAG,uBAAuB;CAAM,CAAC;AACnE;AAEA,SAAS,UAAU,KAAqB,KAAuB;CAC9D,MAAM,EAAE,OAAO,MAAM,UAAU;CAC/B,IAAI,OAAO,KAAK,QAAQ,MAAM,QAAQ,WAAW,MAAM,OAAO;CAC9D,IAAI,IAAI,QACP,IAAI,OAAO,KAAK,QAAQ,UAAU,IAAI,MAAM,EAAE,mBAAmB;CAElE,KAAK,MAAM,OAAO,MAAM,MACvB,IAAI,OAAO,KACV,MAAM,IAAI,KAAK,OAAO,EAAE,EAAE,GAAG,IAAI,IAAI,OAAO,EAAE,EAAE,GAAG,KAAK,GAAG,IAAI,KAChE;CAED,KAAK,MAAM,UAAU,MAAM,SAC1B,IAAI,OAAO,KACV,MAAM,OAAO,KAAK,OAAO,EAAE,EAAE,GAAG,UAAU,OAAO,GAAG,aAAa,OAAO,EAAE,EAAE,GAAG,KAAK,GAAG,OAAO,KAC/F;CAED,IAAI,MAAM,MAAM,SAAS,GACxB,IAAI,OAAO,KAAK,sBAAsB,MAAM,MAAM,KAAK,IAAI,GAAG;CAE/D,IAAI,MAAM,SACT,IAAI,OAAO,KACV,MAAMJ,YAAAA,gBAAgB,OAAO,EAAE,EAAE,GAAG,MAAM,QAAQ,UAAU,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,KAAK,MAAM,QAAQ,QAAQ,SAAS,OAAO,MAAM,QAAQ,OAAO,EAC3J;CAED,IAAI,OAAO,KACV,cAAc,MAAM,OAAO,iBAAiB,SAAS,MAAM,KAAK,EAAE,EACnE;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzlDA,SAAgB,cACf,UAAgC,CAAC,GACK;CACtC,MAAM,EAAE,MAAM,MAAM,KAAK,QAAQ,GAAG,UAAU;CAC9C,MAAM,OAAoB;EAAE,GAAG;EAAa,GAAG;CAAM;CAErD,OAAOK,eAAAA,aAAoC;EAC1C,MAAM;EACN,SAAS;EACT,cAAc;GACb,UAAU;GACV,YAAY;GACZ,QAAQ;GAGR,YAAY;GAEZ,qBAAqB;EACtB;EAGA,aAAa,CAAC;EAEd,MAAM,EAAE,UAAU,KAAK,SAAS,GAAG;EACnC,WAAW,QACV,gBAAgB,KAAK,MAAM;GAC1B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;GACvB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;GACvB,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACtB,CAAC;EACF,QAAQ,KAAK,QAAQ,aAAa,KAAK,KAAK,IAAI;EAChD,OAAO,KAAK,QAAQ,YAAY,KAAK,GAAG;EACxC,YAAY,KAAK,QAAQ,iBAAiB,KAAK,KAAK,IAAI;EACxD,QAAQ,KAAK,QAAQ,aAAa,KAAK,KAAK,IAAI;EAChD,UAAU,KAAK,QAAQ,eAAe,KAAK,KAAK,IAAI;EACpD,SAAS,KAAK,QAAQ,cAAc,KAAK,KAAK,IAAI;EAClD,SAAS,KAAK,QAAQ;GACrB,SAAS,GAAG;GACZ,OAAO,cAAc,KAAK,GAAG;EAC9B;CACD,CAAC;AACF"}
|