@geekmidas/cli 10.0.0-alpha.77 → 10.0.0-alpha.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{LegacyStateStore-dyq07_Ir.mjs → LegacyStateStore-Ceq7A_75.mjs} +2 -2
- package/dist/{LegacyStateStore-dyq07_Ir.mjs.map → LegacyStateStore-Ceq7A_75.mjs.map} +1 -1
- package/dist/{LegacyStateStore-DwngfJxr.cjs → LegacyStateStore-Z-EKUGSX.cjs} +2 -2
- package/dist/{LegacyStateStore-DwngfJxr.cjs.map → LegacyStateStore-Z-EKUGSX.cjs.map} +1 -1
- package/dist/{LocalStateStore-B0NCde8Z.cjs → LocalStateStore-Bocb8dmZ.cjs} +2 -2
- package/dist/{LocalStateStore-B0NCde8Z.cjs.map → LocalStateStore-Bocb8dmZ.cjs.map} +1 -1
- package/dist/{LocalStateStore-DLxCCatI.mjs → LocalStateStore-C72bwpG2.mjs} +2 -2
- package/dist/{LocalStateStore-DLxCCatI.mjs.map → LocalStateStore-C72bwpG2.mjs.map} +1 -1
- package/dist/{S3StateStore-BOenb-3o.cjs → S3StateStore-35YfcdL_.cjs} +2 -2
- package/dist/{S3StateStore-BOenb-3o.cjs.map → S3StateStore-35YfcdL_.cjs.map} +1 -1
- package/dist/{S3StateStore-CGK_4hlo.mjs → S3StateStore-C9upSW5o.mjs} +2 -2
- package/dist/{S3StateStore-CGK_4hlo.mjs.map → S3StateStore-C9upSW5o.mjs.map} +1 -1
- package/dist/{SSMStateStore-DYeD__7p.cjs → SSMStateStore-W-Ps22AQ.cjs} +2 -2
- package/dist/{SSMStateStore-DYeD__7p.cjs.map → SSMStateStore-W-Ps22AQ.cjs.map} +1 -1
- package/dist/{SSMStateStore-B_5_RqY-.mjs → SSMStateStore-dOmFO6g1.mjs} +2 -2
- package/dist/{SSMStateStore-B_5_RqY-.mjs.map → SSMStateStore-dOmFO6g1.mjs.map} +1 -1
- package/dist/{add-DCsgtvDk.cjs → add-BvOICikp.cjs} +3 -3
- package/dist/{add-DCsgtvDk.cjs.map → add-BvOICikp.cjs.map} +1 -1
- package/dist/{add-EPQO-_dt.mjs → add-D2XKszYP.mjs} +3 -3
- package/dist/{add-EPQO-_dt.mjs.map → add-D2XKszYP.mjs.map} +1 -1
- package/dist/{bundler-5spPyduN.cjs → bundler-C6T-1OLT.cjs} +5 -5
- package/dist/{bundler-5spPyduN.cjs.map → bundler-C6T-1OLT.cjs.map} +1 -1
- package/dist/{bundler-DgO_EMVs.mjs → bundler-CtHzKqnZ.mjs} +5 -5
- package/dist/{bundler-DgO_EMVs.mjs.map → bundler-CtHzKqnZ.mjs.map} +1 -1
- package/dist/{cli-B74Ru-V1.mjs → cli-BgPyhx1i.mjs} +3 -3
- package/dist/{cli-B74Ru-V1.mjs.map → cli-BgPyhx1i.mjs.map} +1 -1
- package/dist/{cli-ZpFTMbGw.cjs → cli-K6Vj_pPW.cjs} +3 -3
- package/dist/{cli-ZpFTMbGw.cjs.map → cli-K6Vj_pPW.cjs.map} +1 -1
- package/dist/{compose-CePlrbUw.cjs → compose-B7MC19eC.cjs} +606 -55
- package/dist/compose-B7MC19eC.cjs.map +1 -0
- package/dist/{compose-IUuxRW0J.mjs → compose-DByK353T.mjs} +592 -59
- package/dist/compose-DByK353T.mjs.map +1 -0
- package/dist/{config-Ckmoj56i.d.mts → config-Bql0AmJt.d.mts} +3 -3
- package/dist/{config-Ckmoj56i.d.mts.map → config-Bql0AmJt.d.mts.map} +1 -1
- package/dist/{config-aAeLXH86.d.cts → config-DlNpHK8p.d.cts} +3 -3
- package/dist/{config-aAeLXH86.d.cts.map → config-DlNpHK8p.d.cts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/deploy/public.cjs +6 -6
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-Q6X6RXRG.mjs → deploy-BerP7ppB.mjs} +5 -5
- package/dist/{deploy-Q6X6RXRG.mjs.map → deploy-BerP7ppB.mjs.map} +1 -1
- package/dist/{deploy-XHXi-_tL.cjs → deploy-Dt42xiQA.cjs} +5 -5
- package/dist/{deploy-XHXi-_tL.cjs.map → deploy-Dt42xiQA.cjs.map} +1 -1
- package/dist/{dokploy-MSsPBO-t.cjs → dokploy-NG9UrVrP.cjs} +2 -2
- package/dist/{dokploy-MSsPBO-t.cjs.map → dokploy-NG9UrVrP.cjs.map} +1 -1
- package/dist/{dokploy-BtP5XSrS.mjs → dokploy-ssZQRK2C.mjs} +2 -2
- package/dist/{dokploy-BtP5XSrS.mjs.map → dokploy-ssZQRK2C.mjs.map} +1 -1
- package/dist/{encryption-DY0na43R.cjs → encryption-CbMI24fI.cjs} +3 -3
- package/dist/{encryption-DY0na43R.cjs.map → encryption-CbMI24fI.cjs.map} +1 -1
- package/dist/{encryption-D4Ykywfr.mjs → encryption-De6MN0O5.mjs} +3 -3
- package/dist/{encryption-D4Ykywfr.mjs.map → encryption-De6MN0O5.mjs.map} +1 -1
- package/dist/{engine-y53kE_3H.cjs → engine-CoCsNoW_.cjs} +4 -4
- package/dist/{engine-y53kE_3H.cjs.map → engine-CoCsNoW_.cjs.map} +1 -1
- package/dist/{engine-BI2xjCKt.mjs → engine-DOjGIgl4.mjs} +4 -4
- package/dist/{engine-BI2xjCKt.mjs.map → engine-DOjGIgl4.mjs.map} +1 -1
- package/dist/{github-BBIqk1Jv.mjs → github-CwX9z89E.mjs} +3 -3
- package/dist/{github-BBIqk1Jv.mjs.map → github-CwX9z89E.mjs.map} +1 -1
- package/dist/{github-Bmb45xUQ.cjs → github-D9vGqdLk.cjs} +3 -3
- package/dist/{github-Bmb45xUQ.cjs.map → github-D9vGqdLk.cjs.map} +1 -1
- package/dist/{index-CNdSRwar.d.mts → index-BXO0vlme.d.mts} +2 -2
- package/dist/{index-C7Tma2m1.d.cts.map → index-BXO0vlme.d.mts.map} +1 -1
- package/dist/{index-C7Tma2m1.d.cts → index-Rs0Fua-q.d.cts} +2 -2
- package/dist/{index-CNdSRwar.d.mts.map → index-Rs0Fua-q.d.cts.map} +1 -1
- package/dist/index.cjs +46 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +46 -45
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-31JXUOaG.cjs → migrate-B4GBvCNY.cjs} +3 -3
- package/dist/{migrate-31JXUOaG.cjs.map → migrate-B4GBvCNY.cjs.map} +1 -1
- package/dist/{migrate-DWVl5PQK.mjs → migrate-BQ4wVKq_.mjs} +3 -3
- package/dist/{migrate-DWVl5PQK.mjs.map → migrate-BQ4wVKq_.mjs.map} +1 -1
- package/dist/{migrate-BUBsUiM3.mjs → migrate-CNKaQl3K.mjs} +3 -3
- package/dist/{migrate-BUBsUiM3.mjs.map → migrate-CNKaQl3K.mjs.map} +1 -1
- package/dist/{migrate-sny0NjKe.cjs → migrate-Cgoy58Sh.cjs} +3 -3
- package/dist/{migrate-sny0NjKe.cjs.map → migrate-Cgoy58Sh.cjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-DokLtTUb.cjs → resolve-CEaqRBzY.cjs} +3 -3
- package/dist/{resolve-DokLtTUb.cjs.map → resolve-CEaqRBzY.cjs.map} +1 -1
- package/dist/{resolve-BF1ICosS.mjs → resolve-mvaystiE.mjs} +3 -3
- package/dist/{resolve-BF1ICosS.mjs.map → resolve-mvaystiE.mjs.map} +1 -1
- package/dist/{rollback-CpOWRR9H.cjs → rollback-F3P-rA-r.cjs} +5 -5
- package/dist/{rollback-CpOWRR9H.cjs.map → rollback-F3P-rA-r.cjs.map} +1 -1
- package/dist/{rollback-sg0ZhKGG.mjs → rollback-S2C-Y9pB.mjs} +5 -5
- package/dist/{rollback-sg0ZhKGG.mjs.map → rollback-S2C-Y9pB.mjs.map} +1 -1
- package/dist/{runtime-BozOkPtG.d.cts → runtime-D9AxGzrw.d.cts} +2 -2
- package/dist/{runtime-B5bYom9w.d.mts.map → runtime-D9AxGzrw.d.cts.map} +1 -1
- package/dist/{runtime-B5bYom9w.d.mts → runtime-Dflki3Vs.d.mts} +2 -2
- package/dist/{runtime-BozOkPtG.d.cts.map → runtime-Dflki3Vs.d.mts.map} +1 -1
- package/dist/{sniffer-Y6GQOCXB.cjs → sniffer-BjG-1mlD.cjs} +6 -6
- package/dist/{sniffer-Y6GQOCXB.cjs.map → sniffer-BjG-1mlD.cjs.map} +1 -1
- package/dist/{sniffer-DR8AlRCk.mjs → sniffer-ByWtH28i.mjs} +6 -6
- package/dist/{sniffer-DR8AlRCk.mjs.map → sniffer-ByWtH28i.mjs.map} +1 -1
- package/dist/{stale-yu2FkH3G.cjs → stale-BsiPJI7Y.cjs} +5 -5
- package/dist/stale-BsiPJI7Y.cjs.map +1 -0
- package/dist/{stale-DGzpiN5S.mjs → stale-C5FqIVc8.mjs} +5 -5
- package/dist/stale-C5FqIVc8.mjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-ct7pdQRf.d.cts → types-ByY0zi3n.d.cts} +42 -1
- package/dist/{types-ct7pdQRf.d.cts.map → types-ByY0zi3n.d.cts.map} +1 -1
- package/dist/{types-B9yWJAis.d.mts → types-DKxkXsKC.d.mts} +42 -1
- package/dist/{types-B9yWJAis.d.mts.map → types-DKxkXsKC.d.mts.map} +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-QUTqYmVy.mjs → workspace-BBdqmkch.mjs} +114 -17
- package/dist/workspace-BBdqmkch.mjs.map +1 -0
- package/dist/{workspace-DOm81oUo.cjs → workspace-Bp8FEkF-.cjs} +130 -15
- package/dist/workspace-Bp8FEkF-.cjs.map +1 -0
- package/package.json +15 -15
- package/dist/compose-CePlrbUw.cjs.map +0 -1
- package/dist/compose-IUuxRW0J.mjs.map +0 -1
- package/dist/stale-DGzpiN5S.mjs.map +0 -1
- package/dist/stale-yu2FkH3G.cjs.map +0 -1
- package/dist/workspace-DOm81oUo.cjs.map +0 -1
- package/dist/workspace-QUTqYmVy.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compose-IUuxRW0J.mjs","names":[],"sources":["../src/compose/docker.ts","../src/compose/images.ts","../src/compose/logs.ts","../src/compose/redis.ts","../src/compose/caddyfile.ts","../src/compose/stack.ts","../src/target/compose/health.ts","../src/target/compose/phases.ts","../src/target/compose/index.ts"],"sourcesContent":["/**\n * The Docker operations `gkm compose` needs, behind an interface.\n *\n * Small on purpose, like reconcile's: the rules about *when* each runs — the\n * registry is asked before anything is pulled, nothing is started for a tag\n * that is missing — are asserted against a fake, and this file is only the\n * wiring to the real CLI.\n *\n * Every call is an argument array. Image refs, tags and paths come from the\n * workspace, and none of them reaches a shell.\n */\n\nimport { spawn } from 'node:child_process';\nimport { mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { type RunOptions, run, runOutput } from '../run';\n\n/** Where one stack lives: its compose project and the file that defines it. */\nexport interface StackRef {\n\tproject: string;\n\tfile: string;\n\t/**\n\t * The project's own files merged over `file`, in order — its\n\t * `docker-compose.<stage>.yml`, where it has one.\n\t */\n\toverrides?: readonly string[];\n\t/** Where relative paths in the file resolve — the workspace root. */\n\tcwd: string;\n\t/**\n\t * Where docker's own output goes: the terminal (the default), stderr — so\n\t * a `--json` run's stdout carries only events — or nowhere.\n\t */\n\toutput?: 'inherit' | 'stderr' | 'ignore';\n\t/** Stops whatever docker is doing for the stack. */\n\tsignal?: AbortSignal;\n}\n\n/** `output` as `spawn` reads it. */\nconst STDIO: Record<NonNullable<StackRef['output']>, RunOptions['stdio']> = {\n\tinherit: 'inherit',\n\tstderr: ['ignore', 2, 2],\n\tignore: 'ignore',\n};\n\n/** How a stack's docker commands run: where it is, where output goes. */\nfunction runOptions(stack: StackRef, env?: NodeJS.ProcessEnv): RunOptions {\n\treturn {\n\t\tcwd: stack.cwd,\n\t\tstdio: STDIO[stack.output ?? 'inherit'],\n\t\t...(env ? { env } : {}),\n\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t};\n}\n\n/** What the registry said about one image ref. */\nexport type ImageLookup =\n\t| { ref: string; status: 'found' }\n\t| { ref: string; status: 'missing' }\n\t| { ref: string; status: 'unreachable'; detail: string };\n\nexport interface ComposeDocker {\n\t/** Ask the registry whether `ref` exists, without pulling it. */\n\tlookup(ref: string): Promise<ImageLookup>;\n\t/** Build every service with a `build:` entry. */\n\tbuild(stack: StackRef, services: readonly string[]): Promise<void>;\n\t/** Pull the named services' images. */\n\tpull(stack: StackRef, services: readonly string[]): Promise<void>;\n\t/**\n\t * Start services, detached, and wait for their health checks. With no\n\t * services named, the whole stack — and anything it no longer defines is\n\t * removed.\n\t */\n\tup(stack: StackRef, services?: readonly string[]): Promise<void>;\n\t/** Stop the stack. Its volumes are kept. */\n\tdown(stack: StackRef): Promise<void>;\n\t/** The host port a running service publishes for `inside`. */\n\tport(stack: StackRef, service: string, inside: number): Promise<number>;\n\t/**\n\t * A running service's health, as its own check reports it — `healthy`,\n\t * `starting`, `unhealthy` — or undefined when it is not running.\n\t */\n\thealth(stack: StackRef, service: string): Promise<string | undefined>;\n\t/** Copy a file out of a running service. */\n\tcopyOut(\n\t\tstack: StackRef,\n\t\tservice: string,\n\t\tfrom: string,\n\t\tto: string,\n\t): Promise<void>;\n\t/**\n\t * Push an image built here to its registry, and return the digest the\n\t * registry stored it under (`sha256:…`).\n\t */\n\tpush(stack: StackRef, ref: string): Promise<string>;\n\t/**\n\t * What an image resolved to: the registry digest a pulled image has, or\n\t * the content id of one built here and never pushed.\n\t */\n\tdigest(ref: string): Promise<string | undefined>;\n}\n\n/** How long a stack has to pass its health checks. */\nconst WAIT_TIMEOUT_S = 180;\n\n/** `docker compose port` printed nothing a port can be read from. */\nexport class ServicePortUnknown extends Error {\n\tconstructor(\n\t\treadonly service: string,\n\t\treadonly inside: number,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${service}' publishes no host port for ${inside} (docker said: ${output.trim() || 'nothing'}). Is it running? \\`docker compose ps\\` shows the stack.`,\n\t\t);\n\t\tthis.name = 'ServicePortUnknown';\n\t}\n}\n\n/**\n * Whether `ref` names a registry on this machine's loopback — which the\n * daemon pulls from and pushes to over plain HTTP by default, and `docker\n * manifest inspect` reaches only when told `--insecure` (without it, a local\n * registry's image is reported as no such manifest).\n */\nexport function isLoopbackRegistry(ref: string): boolean {\n\tconst first = ref.split('/')[0]!;\n\tif (!ref.includes('/') || !/[.:]|^localhost$/.test(first)) return false;\n\tconst host = first.replace(/:\\d+$/, '');\n\treturn host === 'localhost' || /^127(?:\\.\\d{1,3}){3}$/.test(host);\n}\n\n/** `docker push` finished without saying what digest the registry stored. */\nexport class PushDigestUnknown extends Error {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly output: string,\n\t) {\n\t\tsuper(\n\t\t\t`Pushed ${ref}, but docker did not say which digest the registry stored ` +\n\t\t\t\t`(it said: ${output.trim().split('\\n').slice(-3).join(' / ') || 'nothing'}). ` +\n\t\t\t\t`Check the push with \\`docker buildx imagetools inspect ${ref}\\`.`,\n\t\t);\n\t\tthis.name = 'PushDigestUnknown';\n\t}\n}\n\n/** The digest `docker push` reports last: `<tag>: digest: sha256:… size: …`. */\nexport function pushedDigest(output: string): string | undefined {\n\tconst matches = [...output.matchAll(/digest: (sha256:[0-9a-f]{64})/g)];\n\treturn matches.at(-1)?.[1];\n}\n\nfunction compose(stack: StackRef, args: readonly string[]): string[] {\n\treturn [\n\t\t'compose',\n\t\t'-p',\n\t\tstack.project,\n\t\t'-f',\n\t\tstack.file,\n\t\t...(stack.overrides ?? []).flatMap((file) => ['-f', file]),\n\t\t...args,\n\t];\n}\n\n/** Run a program and keep everything it said, whatever it exits with. */\nfunction capture(\n\tcommand: string,\n\targs: readonly string[],\n\ttimeoutMs = 60_000,\n): Promise<{ code: number | null; stdout: string; stderr: string }> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(command, [...args], {\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t});\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\t\tchild.stdout.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString();\n\t\t});\n\t\tchild.stderr.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString();\n\t\t});\n\t\tconst timer = setTimeout(() => child.kill('SIGKILL'), timeoutMs);\n\t\ttimer.unref?.();\n\t\tchild.on('error', (error) => {\n\t\t\tclearTimeout(timer);\n\t\t\treject(error);\n\t\t});\n\t\tchild.on('close', (code) => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve({ code, stdout, stderr });\n\t\t});\n\t});\n}\n\n/**\n * Whether a failed `docker manifest inspect` means the tag is not there, as\n * opposed to the registry not answering.\n *\n * Read off the message because that is all the CLI gives. Anything not\n * recognisably \"no such tag\" is treated as the registry being unreachable:\n * a registry that refused credentials must not be reported as a tag that was\n * never pushed, or the fix offered would be the wrong one.\n */\nexport function isMissingManifest(output: string): boolean {\n\treturn /no such manifest|manifest unknown|manifest for .* not found|not found: manifest/i.test(\n\t\toutput,\n\t);\n}\n\nexport const dockerCompose: ComposeDocker = {\n\tasync lookup(ref) {\n\t\tconst { code, stdout, stderr } = await capture('docker', [\n\t\t\t'manifest',\n\t\t\t'inspect',\n\t\t\t...(isLoopbackRegistry(ref) ? ['--insecure'] : []),\n\t\t\tref,\n\t\t]);\n\t\tif (code === 0) return { ref, status: 'found' };\n\n\t\tconst output = `${stderr}\\n${stdout}`.trim();\n\t\treturn isMissingManifest(output)\n\t\t\t? { ref, status: 'missing' }\n\t\t\t: { ref, status: 'unreachable', detail: output };\n\t},\n\n\tasync build(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['build', ...services]),\n\t\t\trunOptions(stack, { ...process.env, DOCKER_BUILDKIT: '1' }),\n\t\t);\n\t},\n\n\tasync pull(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['pull', ...services]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync up(stack, services) {\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, [\n\t\t\t\t'up',\n\t\t\t\t'-d',\n\t\t\t\t'--wait',\n\t\t\t\t`--wait-timeout=${WAIT_TIMEOUT_S}`,\n\t\t\t\t// Only when the whole stack is asked for: starting the databases\n\t\t\t\t// first must not remove the apps an earlier run left running.\n\t\t\t\t...(services ? [] : ['--remove-orphans']),\n\t\t\t\t...(services ?? []),\n\t\t\t]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync down(stack) {\n\t\tawait run('docker', compose(stack, ['down']), runOptions(stack));\n\t},\n\n\tasync port(stack, service, inside) {\n\t\tconst output = await runOutput(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['port', service, String(inside)]),\n\t\t\t{ cwd: stack.cwd, ...(stack.signal ? { signal: stack.signal } : {}) },\n\t\t);\n\t\t// `127.0.0.1:54321` — the part after the last colon is the host port.\n\t\tconst port = Number(output.trim().split(':').pop());\n\t\tif (!Number.isInteger(port) || port <= 0) {\n\t\t\tthrow new ServicePortUnknown(service, inside, output);\n\t\t}\n\t\treturn port;\n\t},\n\n\tasync health(stack, service) {\n\t\tconst { code, stdout } = await capture('docker', [\n\t\t\t...compose(stack, ['ps', '--format', '{{.Health}}', service]),\n\t\t]);\n\t\tif (code !== 0) return undefined;\n\t\treturn stdout.trim().split('\\n')[0] || undefined;\n\t},\n\n\tasync copyOut(stack, service, from, to) {\n\t\tawait mkdir(dirname(to), { recursive: true });\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tcompose(stack, ['cp', `${service}:${from}`, to]),\n\t\t\trunOptions(stack),\n\t\t);\n\t},\n\n\tasync push(stack, ref) {\n\t\t// What it printed is read back for the digest; its errors still reach\n\t\t// the terminal.\n\t\tconst output = await runOutput('docker', ['push', ref], {\n\t\t\tcwd: stack.cwd,\n\t\t\t...(stack.signal ? { signal: stack.signal } : {}),\n\t\t});\n\t\tconst digest = pushedDigest(output);\n\t\tif (!digest) throw new PushDigestUnknown(ref, output);\n\t\treturn digest;\n\t},\n\n\tasync digest(ref) {\n\t\tconst { code, stdout } = await capture('docker', [\n\t\t\t'image',\n\t\t\t'inspect',\n\t\t\t'--format={{json .RepoDigests}} {{.Id}}',\n\t\t\tref,\n\t\t]);\n\t\tif (code !== 0) return undefined;\n\n\t\tconst [json = '[]', id] = stdout.trim().split(' ');\n\t\tconst repository = ref.split('@')[0]!.replace(/:[\\w][\\w.-]*$/, '');\n\t\ttry {\n\t\t\tconst digests = JSON.parse(json) as unknown;\n\t\t\tconst match = Array.isArray(digests)\n\t\t\t\t? digests.find(\n\t\t\t\t\t\t(entry): entry is string =>\n\t\t\t\t\t\t\ttypeof entry === 'string' && entry.startsWith(`${repository}@`),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\t\t\tif (match) return match.slice(repository.length + 1);\n\t\t} catch {\n\t\t\t// Fall through to the content id.\n\t\t}\n\t\treturn id || undefined;\n\t},\n};\n","/**\n * Which image each app runs — and, for a tag, whether every one exists.\n *\n * A tag is a release's identity: `--tag=v1.4.0` means the images CI pushed as\n * v1.4.0, and nothing else. So a stack is never half rolled out: every app's\n * image is asked of the registry before anything is pulled or the running\n * stack is touched, and one missing image stops the whole run naming every\n * one that is missing. Nor is a missing image quietly built instead — a build\n * of whatever is checked out here is not the release the tag names.\n */\n\nimport type { ComposeDocker } from './docker';\n\n/** One app's image, as the stack runs it. */\nexport interface AppImage {\n\tapp: string;\n\tref: string;\n\ttag: string;\n}\n\n/**\n * The tag a site's image carries for a release.\n *\n * A site's public URLs are inlined when it is built, so one bundle serves one\n * stage: `v1.4.0-production` and `v1.4.0-staging` are two images of the same\n * commit. A backend reads its URLs at runtime, so one image serves every stage\n * and its tag is the release's alone.\n */\nexport function siteTag(tag: string, stage: string): string {\n\treturn `${tag}-${stage}`;\n}\n\n/** Images a tag names that the registry does not have. */\nexport class ImageTagNotFound extends Error {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly refs: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The registry has no image for ${refs.length === 1 ? 'this app' : `${refs.length} apps`} at '${tag}':\\n` +\n\t\t\t\trefs.map((ref) => ` - ${ref}`).join('\\n') +\n\t\t\t\t`\\nNothing was pulled or started. Push '${tag}' for every app from CI, ` +\n\t\t\t\t`pick a tag that exists, or run without --tag to build from this checkout.`,\n\t\t);\n\t\tthis.name = 'ImageTagNotFound';\n\t}\n}\n\n/** The registry did not answer, or did not let this machine in. */\nexport class RegistryUnreachable extends Error {\n\tconstructor(\n\t\treadonly ref: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not ask the registry about ${ref}: ${detail || 'no answer'}\\n` +\n\t\t\t\t`Nothing was pulled or started. Check the registry is reachable and ` +\n\t\t\t\t`that this machine is logged in to it (\\`docker login <registry>\\`).`,\n\t\t);\n\t\tthis.name = 'RegistryUnreachable';\n\t}\n}\n\n/**\n * Assert every image exists, before anything else happens.\n *\n * Asked all at once and reported all at once: a release missing two images is\n * one problem with two names, and finding the second only after fixing the\n * first is a slower way to learn the same thing.\n *\n * @throws {RegistryUnreachable} when the registry cannot say\n * @throws {ImageTagNotFound} listing every missing image\n */\nexport async function assertImagesExist(\n\tdocker: Pick<ComposeDocker, 'lookup'>,\n\ttag: string,\n\timages: readonly AppImage[],\n): Promise<void> {\n\tconst lookups = await Promise.all(\n\t\timages.map((image) => docker.lookup(image.ref)),\n\t);\n\n\tconst unreachable = lookups.find((lookup) => lookup.status === 'unreachable');\n\tif (unreachable?.status === 'unreachable') {\n\t\tthrow new RegistryUnreachable(unreachable.ref, unreachable.detail);\n\t}\n\n\tconst missing = lookups\n\t\t.filter((lookup) => lookup.status === 'missing')\n\t\t.map((lookup) => lookup.ref);\n\tif (missing.length > 0) throw new ImageTagNotFound(tag, missing);\n}\n\n/**\n * A push or a pull with no `deploy.registry` to push to or pull from.\n *\n * Without one an image is named `<namespace>/<project>-<app>:<tag>`, which\n * Docker resolves to Docker Hub — so a release would be pushed to, or pulled\n * from, somebody else's account. It is never a fallback.\n */\nexport class RegistryRequired extends Error {\n\tconstructor(\n\t\t/** What needed the registry: `--push`, or a pull (`--tag`/`--pull`). */\n\t\treadonly operation: 'push' | 'pull',\n\t\t/** The ref an image would have had: a Docker Hub name. */\n\t\treadonly ref: string,\n\t) {\n\t\tsuper(\n\t\t\t`${operation === 'push' ? 'Pushing' : 'Pulling'} images needs a registry, and gkm.config.ts sets no deploy.registry: ` +\n\t\t\t\t`'${ref}' would be ${operation === 'push' ? 'pushed to' : 'pulled from'} Docker Hub. ` +\n\t\t\t\t`Set deploy.registry (e.g. registry: 'ghcr.io/acme') in gkm.config.ts.` +\n\t\t\t\t(operation === 'pull'\n\t\t\t\t\t? ' To run images built here instead, pass --build.'\n\t\t\t\t\t: ''),\n\t\t);\n\t\tthis.name = 'RegistryRequired';\n\t}\n}\n\n/**\n * What a push reports, and what a pull can pin to: each app's image as\n * `<ref>@sha256:…` — the tag it was pushed as, and the exact image, whatever\n * that tag is later moved to.\n */\nexport type ImageDigests = Record<string, string>;\n\n/** An image pinned to its digest: `<ref>@sha256:…`. */\nexport function pinnedRef(ref: string, digest: string): string {\n\treturn `${ref.split('@')[0]}@${digest}`;\n}\n\n/** A digests file with no entry for an app the stack runs. */\nexport class ImageDigestMissing extends Error {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly apps: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${file} pins no digest for ${apps.join(', ')}. Use the file the ` +\n\t\t\t\t`same release's \\`gkm compose --build --push --digests-file\\` wrote, ` +\n\t\t\t\t`or run without --digests-file to pull by tag.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMissing';\n\t}\n}\n\n/** A digests file entry that is not this app's image. */\nexport class ImageDigestMismatch extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly expected: string,\n\t\treadonly found: string,\n\t) {\n\t\tsuper(\n\t\t\t`The digests file pins '${app}' to ${found}, but this release runs ` +\n\t\t\t\t`${expected}. It was written for another registry, project, stage ` +\n\t\t\t\t`or tag; use the file this stage's push of this tag wrote.`,\n\t\t);\n\t\tthis.name = 'ImageDigestMismatch';\n\t}\n}\n\n/** A digests file that is not a JSON object of app to pinned ref. */\nexport class ImageDigestsInvalid extends Error {\n\tconstructor(\n\t\treadonly file: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(\n\t\t\t`${file} is not a digests file (${detail}). It should be the JSON ` +\n\t\t\t\t`object \\`gkm compose --build --push --digests-file\\` writes: ` +\n\t\t\t\t`{ \"api\": \"<registry>/<image>:<tag>@sha256:…\" }.`,\n\t\t);\n\t\tthis.name = 'ImageDigestsInvalid';\n\t}\n}\n\n/** Parse a digests file's content, checking its shape. */\nexport function parseDigests(file: string, content: string): ImageDigests {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new ImageDigestsInvalid(\n\t\t\tfile,\n\t\t\terror instanceof Error ? error.message : String(error),\n\t\t);\n\t}\n\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\tthrow new ImageDigestsInvalid(file, 'not a JSON object');\n\t}\n\tfor (const [app, value] of Object.entries(parsed)) {\n\t\tif (typeof value !== 'string' || !/@sha256:[0-9a-f]{64}$/.test(value)) {\n\t\t\tthrow new ImageDigestsInvalid(\n\t\t\t\tfile,\n\t\t\t\t`'${app}' is not an <image>:<tag>@sha256:… ref`,\n\t\t\t);\n\t\t}\n\t}\n\treturn parsed as ImageDigests;\n}\n\n/**\n * Each image pinned to the digest the file names for it.\n *\n * @throws {ImageDigestMissing} naming every app the file has no entry for\n * @throws {ImageDigestMismatch} when an entry is another image or tag\n */\nexport function pinImages<T extends AppImage>(\n\tfile: string,\n\tdigests: ImageDigests,\n\timages: readonly T[],\n): T[] {\n\tconst missing = images\n\t\t.filter((image) => !digests[image.app])\n\t\t.map((image) => image.app);\n\tif (missing.length > 0) throw new ImageDigestMissing(file, missing);\n\n\treturn images.map((image) => {\n\t\tconst pinned = digests[image.app]!;\n\t\tif (pinned.split('@')[0] !== image.ref) {\n\t\t\tthrow new ImageDigestMismatch(image.app, image.ref, pinned);\n\t\t}\n\t\treturn { ...image, ref: pinned };\n\t});\n}\n","/**\n * The stack's log UI: OpenObserve, run beside the apps when\n * `deploy.compose.logs` asks for it, and every backend's OpenTelemetry\n * pointed at it.\n *\n * The production server already exports its traces and pino logs over\n * OTLP/HTTP when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. OpenObserve takes OTLP\n * at `/api/<org>/v1/{logs,traces}` with HTTP basic auth, so wiring an app is\n * two variables: the endpoint, `http://openobserve:5080/api/default`, and\n * the header that signs in as the root user.\n *\n * It is reached, by default, through an SSH tunnel: published on 127.0.0.1\n * only, because a port Docker publishes on every interface is opened in the\n * firewall by Docker itself, past ufw's rules. Served publicly, it is a host\n * on the stack's Caddy that refuses every address not allowed.\n *\n * Pure: the stack decides it, and the phases print and check it.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { isOtlpDestination } from '../deploy/otel.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport { LOGS_PORT, type ResolvedLogs } from './logsConfig.js';\nimport type { StackService } from './stack.js';\n\n/**\n * The image, pinned. A log store's on-disk format is the thing that must not\n * move under a running stack, so a new version is a change to this line.\n */\nexport const OPENOBSERVE_IMAGE = 'public.ecr.aws/zinclabs/openobserve:v1.0.4';\n\n/** Its compose service name — the host the apps send to. */\nexport const LOGS_SERVICE = 'openobserve';\n\n/** The organisation every app's telemetry lands in. */\nexport const LOGS_ORG = 'default';\n\n/** The stage secrets that sign in as OpenObserve's root user. */\nexport const LOGS_EMAIL_KEY = 'ZO_ROOT_USER_EMAIL';\nexport const LOGS_PASSWORD_KEY = 'ZO_ROOT_USER_PASSWORD';\n\n/**\n * The local stage's root login: fixed, as its Postgres password is. It meets\n * OpenObserve's password rules, which a weaker one would not.\n */\nexport const LOCAL_LOGS_EMAIL = 'admin@gkm.localhost';\nexport const LOCAL_LOGS_PASSWORD = 'Geekmidas-1';\n\n/** The stack's OpenObserve, as the stack runs it. */\nexport interface StackLogs extends ResolvedLogs {\n\t/** The root user's email and password. */\n\temail: string;\n\tpassword: string;\n\t/** Whether the stage's secrets set the password, rather than a default. */\n\tpasswordFromSecrets: boolean;\n\t/** Where a browser opens it: the tunnel's end, or its public host. */\n\turl: string;\n\t/** Its public host, when it is served through Caddy. */\n\thost?: string;\n\t/** Its own environment, written to `openobserve.env` (0600). */\n\tenv: Record<string, string>;\n\t/** What every backend is handed to send its telemetry here. */\n\tappEnv: {\n\t\tOTEL_EXPORTER_OTLP_ENDPOINT: string;\n\t\tOTEL_EXPORTER_OTLP_HEADERS: string;\n\t};\n}\n\n/** The stage sends its telemetry somewhere already, and logs are on too. */\nexport class LogsEndpointConflict extends Error {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly keys: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' sets ${keys.join(', ')} in its secrets, and ` +\n\t\t\t\t'deploy.compose.logs also runs OpenObserve for it — each backend can ' +\n\t\t\t\t'send its telemetry to one place. Either keep your own OTLP backend: ' +\n\t\t\t\t'remove logs from deploy.compose in gkm.config.ts; or use the ' +\n\t\t\t\t`bundled OpenObserve: remove ${keys.join(', ')} from the stage's ` +\n\t\t\t\t'secrets, and every backend is pointed at it.',\n\t\t);\n\t\tthis.name = 'LogsEndpointConflict';\n\t}\n}\n\n/** A root password OpenObserve would refuse to start with. */\nexport class LogsPasswordWeak extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' sets ${LOGS_PASSWORD_KEY}, and OpenObserve refuses ` +\n\t\t\t\t'it: a root password must be 8 to 128 characters with a lowercase ' +\n\t\t\t\t'letter, an uppercase letter, a digit and a symbol. Set another with ' +\n\t\t\t\t`gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}, or unset ` +\n\t\t\t\t'it to have one generated.',\n\t\t);\n\t\tthis.name = 'LogsPasswordWeak';\n\t}\n}\n\n/** A deployed stage with logs on and no root password generated yet. */\nexport class LogsPasswordMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' runs OpenObserve and has no ${LOGS_PASSWORD_KEY} ` +\n\t\t\t\t`in its secrets. Run gkm compose --stage ${stage} without --dry-run ` +\n\t\t\t\t'once to generate it, or set one: ' +\n\t\t\t\t`gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'LogsPasswordMissing';\n\t}\n}\n\n/** Whether OpenObserve accepts `password` for its root user. */\nexport function isStrongLogsPassword(password: string): boolean {\n\treturn (\n\t\tpassword.length >= 8 &&\n\t\tpassword.length <= 128 &&\n\t\t/[a-z]/.test(password) &&\n\t\t/[A-Z]/.test(password) &&\n\t\t/\\d/.test(password) &&\n\t\t/[^A-Za-z0-9]/.test(password)\n\t);\n}\n\n/**\n * A root password: 192 random bits, with a fixed tail so every class\n * OpenObserve requires is present whatever the random part drew.\n */\nexport function generateLogsPassword(): string {\n\treturn `${randomBytes(24).toString('base64url')}-Zo1`;\n}\n\n/**\n * The stage's secrets with a generated root password, where it has none.\n * Pure, like `withGeneratedSecrets`: the caller keeps the result once the\n * run goes ahead.\n */\nexport function withLogsPassword(secrets: StageSecrets): {\n\tsecrets: StageSecrets;\n\tgenerated: string[];\n} {\n\tif (secrets.custom?.[LOGS_PASSWORD_KEY]) return { secrets, generated: [] };\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tcustom: {\n\t\t\t\t...secrets.custom,\n\t\t\t\t[LOGS_PASSWORD_KEY]: generateLogsPassword(),\n\t\t\t},\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tgenerated: [LOGS_PASSWORD_KEY],\n\t};\n}\n\n/**\n * `OTEL_EXPORTER_OTLP_HEADERS` signing in as `email`.\n *\n * The variable's values are percent-decoded by the SDK (they follow the W3C\n * baggage format), so the space after `Basic` is written `%20`. Base64's own\n * `+`, `/` and `=` pass through decoding unchanged.\n */\nexport function otlpHeaders(email: string, password: string): string {\n\tconst token = Buffer.from(`${email}:${password}`).toString('base64');\n\treturn `Authorization=Basic%20${token}`;\n}\n\n/** The stack's OpenObserve for one stage. */\nexport function stackLogs(options: {\n\tconfig: ResolvedLogs;\n\tstage: string;\n\tlocal: boolean;\n\t/** The workspace's name: the local stage's public host is under it. */\n\tproject: string;\n\tdomain?: string;\n\tcustom: Readonly<Record<string, string>>;\n\t/** The edge's HTTPS port, which a local public URL carries. */\n\thttps: number;\n}): StackLogs {\n\tconst { config, stage, local, custom } = options;\n\n\tconst conflicting = Object.keys(custom).filter(isOtlpDestination).sort();\n\tif (conflicting.length > 0) {\n\t\tthrow new LogsEndpointConflict(stage, conflicting);\n\t}\n\n\tif (!local && !options.domain) throw new NoDomainForStage(stage);\n\n\tconst email =\n\t\tcustom[LOGS_EMAIL_KEY] ??\n\t\t(local ? LOCAL_LOGS_EMAIL : `admin@${options.domain}`);\n\tconst set = custom[LOGS_PASSWORD_KEY];\n\tif (!set && !local) throw new LogsPasswordMissing(stage);\n\tconst password = set ?? LOCAL_LOGS_PASSWORD;\n\tif (!isStrongLogsPassword(password)) throw new LogsPasswordWeak(stage);\n\n\tconst host = config.public\n\t\t? local\n\t\t\t? `logs.${options.project}.localhost`\n\t\t\t: `logs.${options.domain}`\n\t\t: undefined;\n\tconst url = host\n\t\t? `https://${host}${local && options.https !== 443 ? `:${options.https}` : ''}`\n\t\t: `http://localhost:${config.port}`;\n\n\treturn {\n\t\t...config,\n\t\temail,\n\t\tpassword,\n\t\tpasswordFromSecrets: Boolean(set),\n\t\turl,\n\t\t...(host ? { host } : {}),\n\t\tenv: {\n\t\t\t[LOGS_EMAIL_KEY]: email,\n\t\t\t[LOGS_PASSWORD_KEY]: password,\n\t\t\tZO_DATA_DIR: '/data',\n\t\t\t// Verified against the image: days, and it refuses fewer than 3.\n\t\t\tZO_COMPACT_DATA_RETENTION_DAYS: String(config.retentionDays),\n\t\t\t// A self-hosted log store on a stage's box does not report home.\n\t\t\tZO_TELEMETRY: 'false',\n\t\t},\n\t\tappEnv: {\n\t\t\tOTEL_EXPORTER_OTLP_ENDPOINT: `http://${LOGS_SERVICE}:${LOGS_PORT}/api/${LOGS_ORG}`,\n\t\t\tOTEL_EXPORTER_OTLP_HEADERS: otlpHeaders(email, password),\n\t\t},\n\t};\n}\n\n/**\n * OpenObserve's service. The image has no shell, `wget` or `curl`, so its\n * health check is its own binary asking the running server for its status —\n * which exits non-zero when nothing answers on its port.\n */\nexport function logsService(logs: StackLogs): StackService {\n\treturn {\n\t\timage: OPENOBSERVE_IMAGE,\n\t\trestart: 'unless-stopped',\n\t\tenv_file: [{ path: `./${LOGS_SERVICE}.env`, format: 'raw' }],\n\t\tvolumes: ['openobserve-data:/data'],\n\t\t// Loopback only: Docker opens a port it publishes on every interface in\n\t\t// the firewall itself, past ufw. Served publicly, Caddy is the way in.\n\t\t...(logs.public ? {} : { ports: [`127.0.0.1:${logs.port}:${LOGS_PORT}`] }),\n\t\thealthcheck: {\n\t\t\ttest: ['CMD', '/openobserve', 'node', 'status'],\n\t\t\tinterval: '10s',\n\t\t\ttimeout: '5s',\n\t\t\tretries: 12,\n\t\t\tstart_period: '20s',\n\t\t},\n\t};\n}\n\n/** Where to guess the stack is reached from, for the printed tunnel. */\nexport interface LogsAccessContext {\n\tstage: string;\n\tlocal: boolean;\n\t/** This machine's user and name — the best guess at the SSH target. */\n\tuser: string;\n\thostname: string;\n}\n\n/** What `gkm compose` prints once the stack is up: how to open the logs. */\nexport function logsAccess(logs: StackLogs, ctx: LogsAccessContext): string[] {\n\tconst login = `login: ${logs.email}, password: ${\n\t\tctx.local && !logs.passwordFromSecrets\n\t\t\t? logs.password\n\t\t\t: `gkm secrets:show --stage ${ctx.stage} --reveal → ${LOGS_PASSWORD_KEY}`\n\t}`;\n\n\tif (logs.public) {\n\t\treturn [\n\t\t\t`📜 Logs (OpenObserve): ${logs.url} (${login})`,\n\t\t\t` answered only for ${logs.public.allow.join(', ')}; every other address gets 403`,\n\t\t];\n\t}\n\n\treturn [\n\t\t`📜 Logs (OpenObserve) on 127.0.0.1:${logs.port} — from your computer:`,\n\t\t// The local stage usually runs where you are; it can run on a box too.\n\t\t...(ctx.local\n\t\t\t? [\n\t\t\t\t\t` on this machine, open http://localhost:${logs.port} directly; from another:`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t` ssh -N -L ${logs.port}:localhost:${logs.port} ${ctx.user}@${ctx.hostname} (user and host are guesses: this machine's)`,\n\t\t` then open http://localhost:${logs.port} (${login})`,\n\t\t`⚠️ Docker-published ports bypass ufw, so OpenObserve is bound to 127.0.0.1 only — reach it through the tunnel, not by opening the port.`,\n\t];\n}\n","/**\n * The stack's Redis: what every declared cache lives in when a workspace runs\n * as a `gkm compose` stack, on the local stage and on a deployed one alike.\n *\n * A cache is the one store whose contents can always be rebuilt, so unlike\n * Mailpit and MinIO it is a production service, not a dev stand-in: it runs\n * for every stage, on the compose network only, with nothing published. It\n * is bounded (`maxmemory`, evicting the least recently used key), persisted\n * (an append-only file on a named volume, kept by `--down`) and password\n * protected — the stage's own password, generated once like its seed.\n *\n * A stage that sets a cache's URL in its secrets — a managed Redis — keeps\n * it, and a stack whose every cache is set that way runs no Redis at all.\n *\n * Pure: the stack decides it, and the phases keep the password.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { DEFAULT_IMAGES } from '../reconcile/containers.js';\nimport type { Plan } from '../reconcile/plan.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport type { CacheBackend } from '../types.js';\nimport type { StackService } from './stack.js';\n\n/**\n * Where a stack's caches live: its own Redis, whatever the deploy target's\n * default is. A stack is one machine running containers, and a Redis beside\n * the apps is cheaper for a cache than a table in the database they share.\n */\nexport const STACK_CACHE: CacheBackend = 'redis';\n\n/** Its compose service name — the host every cache URL points at. */\nexport const REDIS_SERVICE = 'redis';\n\n/** The port it answers on, inside the network. */\nexport const REDIS_PORT = 6379;\n\n/** Reconcile's pin, so `gkm dev` and the stack run one Redis. */\nexport const REDIS_IMAGE = DEFAULT_IMAGES.redis!;\n\n/**\n * How much it may hold before it evicts. A cache that grows until the box\n * runs out of memory takes the apps with it; 256 MB is a lot of sessions and\n * little of a small server. A project's `docker-compose.<stage>.yml` can\n * replace the command to change it.\n */\nexport const REDIS_MAXMEMORY = '256mb';\n\n/** The stage secret holding its password. */\nexport const REDIS_PASSWORD_KEY = 'REDIS_PASSWORD';\n\n/** The local stage's password: fixed, as its Postgres password is. */\nexport const LOCAL_REDIS_PASSWORD = 'geekmidas';\n\n/** Redis's own count of logical databases, before `--databases` raises it. */\nconst REDIS_DATABASES = 16;\n\n/** A deployed stage that runs the stack's Redis and has no password yet. */\nexport class RedisPasswordMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' runs the stack's Redis and has no ` +\n\t\t\t\t`${REDIS_PASSWORD_KEY} in its secrets. Run gkm compose --stage ` +\n\t\t\t\t`${stage} without --dry-run once to generate it, or set one: ` +\n\t\t\t\t`gkm secrets:set ${REDIS_PASSWORD_KEY} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'RedisPasswordMissing';\n\t}\n}\n\n/** The stack's Redis, as the stack runs it. */\nexport interface StackRedis {\n\tpassword: string;\n\t/** Whether the stage's secrets set the password, rather than the local one. */\n\tpasswordFromSecrets: boolean;\n\t/** Each cache it holds: its URL key, and the URL. */\n\turls: Record<string, string>;\n\t/** Its own environment, written to `redis.env` (0600). */\n\tenv: Record<string, string>;\n\t/** How many logical databases it keeps — one per cache, at least 16. */\n\tdatabases: number;\n}\n\n/**\n * Whether a stage's stack runs Redis: a cache is declared and the stage's\n * secrets do not set the URL of every one.\n */\nexport function runsRedis(\n\tmanifest: ConstructManifest,\n\tcustom: Readonly<Record<string, string>>,\n): boolean {\n\treturn Object.values(manifest).some(\n\t\t(declaration) =>\n\t\t\tdeclaration?.kind === 'cache' &&\n\t\t\t(declaration.provides ?? []).some((key) => custom[key] === undefined),\n\t);\n}\n\n/** A password: 256 random bits, URL-safe, so it sits in a URL unescaped. */\nexport function generateRedisPassword(): string {\n\treturn randomBytes(32).toString('base64url');\n}\n\n/**\n * The stage's secrets with a generated Redis password, where it has none.\n * Pure, like `withGeneratedSecrets`: the caller keeps the result once the run\n * goes ahead.\n */\nexport function withRedisPassword(secrets: StageSecrets): {\n\tsecrets: StageSecrets;\n\tgenerated: string[];\n} {\n\tif (secrets.custom?.[REDIS_PASSWORD_KEY]) return { secrets, generated: [] };\n\treturn {\n\t\tsecrets: {\n\t\t\t...secrets,\n\t\t\tcustom: {\n\t\t\t\t...secrets.custom,\n\t\t\t\t[REDIS_PASSWORD_KEY]: generateRedisPassword(),\n\t\t\t},\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tgenerated: [REDIS_PASSWORD_KEY],\n\t};\n}\n\n/**\n * The stack's Redis for one stage, or nothing where no cache needs it.\n *\n * Each cache it holds gets a logical database of its own, by the order of\n * their ids, so two caches never read each other's keys.\n */\nexport function stackRedis(options: {\n\tplan: Plan;\n\tstage: string;\n\tlocal: boolean;\n\tcustom: Readonly<Record<string, string>>;\n}): StackRedis | undefined {\n\tconst { plan, stage, local, custom } = options;\n\n\tconst caches = plan.resources\n\t\t.filter((r) => r.kind === 'cache' && custom[r.envKey] === undefined)\n\t\t.sort((a, b) => a.id.localeCompare(b.id));\n\tif (caches.length === 0) return undefined;\n\n\tconst set = custom[REDIS_PASSWORD_KEY];\n\tif (!set && !local) throw new RedisPasswordMissing(stage);\n\tconst password = set ?? LOCAL_REDIS_PASSWORD;\n\tconst auth = encodeURIComponent(password);\n\n\treturn {\n\t\tpassword,\n\t\tpasswordFromSecrets: Boolean(set),\n\t\turls: Object.fromEntries(\n\t\t\tcaches.map((cache, index) => [\n\t\t\t\tcache.envKey,\n\t\t\t\t`redis://:${auth}@${REDIS_SERVICE}:${REDIS_PORT}/${index}`,\n\t\t\t]),\n\t\t),\n\t\tenv: {\n\t\t\t// What the server is started with, by name: the command reads it\n\t\t\t// from the environment, so the value is never in its arguments.\n\t\t\t[REDIS_PASSWORD_KEY]: password,\n\t\t\t// What `redis-cli` signs in with — the health check's, and anyone's\n\t\t\t// who execs into the container — without `-a` on a command line.\n\t\t\tREDISCLI_AUTH: password,\n\t\t},\n\t\tdatabases: Math.max(REDIS_DATABASES, caches.length),\n\t};\n}\n\n/**\n * Redis's service: bounded, persisted and password protected, on the\n * network alone.\n *\n * The command runs the image's own entrypoint with `redis-server` first, so\n * it still drops to the `redis` user and owns `/data`; the password is read\n * from the env file by the shell (`$$` is compose's escape for `$`), so\n * neither the compose file nor the container's command holds it.\n */\nexport function redisService(redis: StackRedis): StackService {\n\tconst flags = [\n\t\t`--requirepass \"$$${REDIS_PASSWORD_KEY}\"`,\n\t\t`--maxmemory ${REDIS_MAXMEMORY}`,\n\t\t'--maxmemory-policy allkeys-lru',\n\t\t'--appendonly yes',\n\t\t...(redis.databases > REDIS_DATABASES\n\t\t\t? [`--databases ${redis.databases}`]\n\t\t\t: []),\n\t];\n\treturn {\n\t\timage: REDIS_IMAGE,\n\t\trestart: 'unless-stopped',\n\t\tcommand: [\n\t\t\t'sh',\n\t\t\t'-c',\n\t\t\t`exec docker-entrypoint.sh redis-server ${flags.join(' ')}`,\n\t\t],\n\t\tenv_file: [{ path: `./${REDIS_SERVICE}.env`, format: 'raw' }],\n\t\tvolumes: ['redis-data:/data'],\n\t\thealthcheck: {\n\t\t\t// `redis-cli` signs in with REDISCLI_AUTH; an unauthenticated ping\n\t\t\t// answers NOAUTH, which is not PONG.\n\t\t\ttest: ['CMD-SHELL', 'redis-cli ping | grep -q PONG'],\n\t\t\tinterval: '5s',\n\t\t\ttimeout: '3s',\n\t\t\tretries: 10,\n\t\t},\n\t};\n}\n","/**\n * The edge in front of a compose stack: one Caddy, one host per app.\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. Locally the hosts\n * are `*.localhost` and the certificates come from Caddy's own CA, as the\n * `gkm dev` edge does, so a local stack is `https://` like a deployed one.\n *\n * Pure: what the edge serves is data, and rendering it is one string.\n */\n\n/** One host on the edge and the app container behind it. */\nexport interface EdgeSite {\n\t/** e.g. `api.example.com` */\n\thost: string;\n\t/** The app on the compose network, e.g. `api:3000`. */\n\tupstream: string;\n\t/**\n\t * A path to rewrite to, where the upstream expects a different one: a\n\t * file server's bucket, as a prefix on MinIO — `/uploads{uri}`.\n\t */\n\trewrite?: string;\n\t/**\n\t * The client addresses (IPs or CIDRs) it answers; every other is\n\t * refused with 403. Absent, it answers everyone.\n\t */\n\tallow?: readonly string[];\n}\n\nexport interface EdgeOptions {\n\t/** Certificates from Caddy's internal CA rather than from ACME. */\n\tlocal: boolean;\n\t/** Where ACME sends expiry notices, when someone wants them. */\n\temail?: string;\n}\n\n/** The Caddyfile for a stack's edge. */\nexport function edgeCaddyfile(\n\tsites: readonly EdgeSite[],\n\toptions: EdgeOptions,\n): string {\n\tconst global = options.local\n\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: options.email\n\t\t\t? `{\n\temail ${options.email}\n}`\n\t\t\t: '';\n\n\tconst blocks = sites.map(\n\t\t({ host, upstream, rewrite, allow }) => `https://${host} {${\n\t\t\toptions.local\n\t\t\t\t? `\n\ttls internal\n`\n\t\t\t\t: ''\n\t\t}${\n\t\t\tallow\n\t\t\t\t? `\n\t# Only these addresses — the peer Caddy sees, never a header a client\n\t# could set. Everything else is refused before it reaches the upstream.\n\t@denied not remote_ip ${allow.join(' ')}\n\trespond @denied 403\n`\n\t\t\t\t: ''\n\t\t}${\n\t\t\trewrite\n\t\t\t\t? `\n\t# A bucket, served at a host of its own: the bucket is a prefix on MinIO,\n\t# which routes and signs on the Host header — so it is sent the upstream's.\n\treverse_proxy ${upstream} {\n\t\trewrite ${rewrite}\n\t\theader_up Host {upstream_hostport}\n\t}`\n\t\t\t\t: `\n\t# Host and X-Forwarded-* are passed through as Caddy does by default, so\n\t# an app builds redirects, cookies and links on the address a caller used.\n\treverse_proxy ${upstream} {\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}\n}`,\n\t);\n\n\t// No blank line under the header: `caddy fmt` wants the first block there.\n\treturn `${HEADER}${global ? `${global}\\n\\n` : ''}${blocks.join('\\n\\n')}\\n`;\n}\n\nconst HEADER = `# Generated by gkm compose from the construct manifest — do not edit.\n#\n# One host per API and site, each in front of its own container, one per\n# file server in front of the stack's MinIO, and — when its logs are served\n# publicly — one for OpenObserve, to the addresses it allows.\n`;\n","/**\n * The stack a workspace runs as for one stage — pure.\n *\n * Everything `gkm compose` writes is decided here, as data: the compose file,\n * the Caddyfile, one env file per backend, and the image each app runs. The\n * command around it reads the workspace, asks the registry, writes the files\n * and starts Docker; none of those decide anything, so all of it can be\n * asserted without a daemon.\n *\n * The values come from the same derivations every other target uses. The\n * plan is reconcile's `planFor`, the keys an app reads are `appEnvKeys`, and\n * every URL is `envFor`'s — asked twice, once with each app at its public\n * address and once on the compose network, because a browser and a sibling\n * service reach the same API by different names.\n */\n\nimport { join } from 'node:path';\nimport {\n\ttype ConstructManifest,\n\tprovideKey,\n\tprovisionOrder,\n\tpublicEnvFor,\n} from '@geekmidas/manifest';\nimport { type WorkerUnit, workerUnits } from '../build/workers.js';\nimport {\n\tassertExternalServices,\n\ttype DevService,\n\ttype DevServiceUse,\n\tdevServicesUsed,\n\ttype ExternalServices,\n\ttype ServiceDeclaration,\n\tsuppliedOnly,\n} from '../deploy/devServices.js';\nimport { isMainFrontendApp, resolveHost } from '../deploy/domain.js';\nimport { type DeployIdentity, imageRef } from '../deploy/identity.js';\nimport { otelEnv } from '../deploy/otel.js';\nimport { validateImageRef } from '../docker/imageRef.js';\nimport { appDockerfile, workerDockerfile } from '../docker/index.js';\nimport { composeBuildPaths, type ImageLayout } from '../docker/layout.js';\nimport { TURBO_VERSION, WORKER_PORT } from '../docker/templates.js';\nimport { appEnvKeys, networkEnv, workerEnvKeys } from '../reconcile/apps.js';\nimport { hostFor } from '../reconcile/caddyfile.js';\nimport { type ComposeService, composeFor } from '../reconcile/compose.js';\nimport { DEFAULT_IMAGES, portKeys } from '../reconcile/containers.js';\nimport { localRolePassword } from '../reconcile/env.js';\nimport { type Plan, type PlannedResource, planFor } from '../reconcile/plan.js';\nimport { bucketPolicies } from '../reconcile/provision.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport { NoDomainForStage } from '../target/dokploy/domain.js';\nimport { DEFAULT_EVENTS } from '../types.js';\nimport { appKey } from '../workspace/derive.js';\nimport type {\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../workspace/types.js';\nimport { type EdgeSite, edgeCaddyfile } from './caddyfile.js';\nimport { type AppImage, siteTag } from './images.js';\nimport {\n\tLOGS_SERVICE,\n\tlogsService,\n\ttype StackLogs,\n\tstackLogs,\n} from './logs.js';\nimport { LOGS_PORT, resolveLogs } from './logsConfig.js';\nimport {\n\tREDIS_SERVICE,\n\tredisService,\n\tSTACK_CACHE,\n\ttype StackRedis,\n\tstackRedis,\n} from './redis.js';\n\n/** Where a stack's files are written, relative to the workspace root. */\nexport function stackDir(stage: string): string {\n\treturn `.gkm/compose/${stage}`;\n}\n\n/**\n * The compose project a stage's stack runs as.\n *\n * The deploy identity's scope, so two workspaces with one name in different\n * namespaces never share containers or volumes — and the stage, so a\n * machine can run two stages side by side.\n */\nexport function composeProject(identity: DeployIdentity): string {\n\treturn `${identity.scope}-${identity.stage}`;\n}\n\n/** The ports the edge is published on, and the variables that move them. */\nexport const EDGE_PORT_ENV = {\n\thttps: 'GKM_COMPOSE_HTTPS_PORT',\n\thttp: 'GKM_COMPOSE_HTTP_PORT',\n} as const;\n\n/**\n * Containers this target does not run.\n *\n * The AWS emulator never applies: a stack is a server target, whose events\n * are pg-boss. Reconcile's Caddy fronts `gkm dev`'s host processes; the stack\n * brings its own edge.\n *\n * MinIO and Mailpit run on the local stage always, and on a deployed stage\n * only where `--allow-dev-services` allowed them and its secrets configure no\n * real bucket or mail server — see `devServices.ts`.\n */\nconst NOT_RUN: Readonly<Record<string, true>> = {\n\tlocalstack: true,\n\tcaddy: true,\n};\n\n/** The kinds a deployed stage takes from its secrets, or a dev service. */\nconst SERVICE_KINDS: Readonly<Record<string, ServiceDeclaration['kind']>> = {\n\temail: 'email',\n\tobjects: 'objects',\n\t'file-server': 'file-server',\n};\n\n/** The region MinIO is addressed with. It has no regions; the SDK wants one. */\nconst MINIO_REGION = 'us-east-1';\n\n/** The S3 client's credentials, read beside a bucket's URL when it has them. */\nconst STORAGE_KEYS = [\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_REGION',\n] as const;\n\n/**\n * Every service's Docker logs, rotated. The json-file driver keeps a\n * container's output in one file that grows until the disk is full — on a\n * small server, in weeks. Three files of 10 MB each per container is enough\n * to see what happened and never fills anything. A project's own override\n * file that sets `logging` wins over it.\n */\nexport const LOG_ROTATION = {\n\tdriver: 'json-file',\n\toptions: { 'max-size': '10m', 'max-file': '3' },\n} as const;\n\n/** Each image's build, where the stack builds rather than pulls. */\nexport interface AppBuild {\n\t/** Where the Dockerfile is written, relative to the workspace root. */\n\tdockerfile: string;\n\t/** A site's public URLs, inlined by its bundler. */\n\targs?: Record<string, string>;\n}\n\n/** One app in the stack. */\nexport interface StackApp extends AppImage {\n\t/** Its compose service name — the app key, `api`. */\n\tname: string;\n\t/** The construct it serves. */\n\tid: string;\n\tkind: 'rest-api' | 'site';\n\t/** Its directory, relative to the workspace root. */\n\tpath: string;\n\tport: number;\n\t/** The host the edge answers it on. */\n\thost: string;\n\t/** `https://<host>` — with the edge's port where it is not 443. */\n\turl: string;\n\tbuild?: AppBuild;\n\t/** A backend's environment, exactly the keys it reads. Absent for a site. */\n\tenv?: Record<string, string>;\n}\n\n/**\n * A Worker in the stack: its crons, queue consumers and subscribers in a\n * container of their own. Nothing routes to it and nothing is published —\n * its one route is the health check Docker asks.\n */\nexport interface StackWorker extends AppImage {\n\t/** Its compose service name — `jobs`. */\n\tname: string;\n\t/** The Worker construct. */\n\tid: string;\n\t/** The app whose build writes its entry, which its image is built from. */\n\thost: string;\n\t/** Where its health check answers, inside the container. */\n\tport: number;\n\tbuild?: AppBuild;\n\t/** Exactly the keys the worker's constructs read. */\n\tenv?: Record<string, string>;\n}\n\n/** A service as the stack's compose file defines it. */\nexport interface StackService {\n\timage: string;\n\tbuild?: {\n\t\tcontext: string;\n\t\tdockerfile: string;\n\t\targs?: Record<string, string>;\n\t};\n\trestart?: string;\n\tcommand?: string | string[];\n\tenv_file?: { path: string; format: 'raw' }[];\n\tenvironment?: Record<string, string>;\n\tports?: string[];\n\tvolumes?: string[];\n\tdepends_on?: Record<string, { condition: 'service_healthy' }>;\n\thealthcheck?: ComposeService['healthcheck'];\n\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}\n\nexport interface ComposeStack {\n\tproject: string;\n\tstage: string;\n\t/** The project's local stage, served with Caddy's internal CA. */\n\tlocal: boolean;\n\tapps: StackApp[];\n\t/** Each Worker with background work, in a container of its own. */\n\tworkers: StackWorker[];\n\t/** The infrastructure containers, by compose service name. */\n\tinfra: string[];\n\tcompose: StackFile;\n\tcaddyfile: string;\n\t/** Generated Dockerfiles, by path relative to the workspace root. */\n\tdockerfiles: Record<string, string>;\n\t/** The plan the stack was derived from — what provisioning creates. */\n\tplan: Plan;\n\t/** The Postgres master's password, and the seed role passwords take. */\n\tcredential: { master: string; seed?: string };\n\t/**\n\t * The stack's MinIO, where it runs one: its root credential — what the\n\t * backends sign with — and the buckets and open paths provisioning\n\t * creates in it.\n\t */\n\tstorage?: StackStorage;\n\t/** The dev services a deployed stage runs (`--allow-dev-services`). */\n\tdevServices: DevServiceUse[];\n\t/**\n\t * The stack's OpenObserve, when `deploy.compose.logs` runs one — every\n\t * backend sends its logs and traces to it.\n\t */\n\tlogs?: StackLogs;\n\t/**\n\t * The stack's Redis, where a declared cache lives in it — every cache\n\t * whose URL the stage's secrets do not set.\n\t */\n\tredis?: StackRedis;\n}\n\n/** The stack's MinIO, and what is created in it. */\nexport interface StackStorage {\n\tuser: string;\n\tpassword: string;\n\t/** Each bucket's stage-scoped name. */\n\tbuckets: string[];\n\t/** The open paths of each served bucket. */\n\tpolicies: { bucket: string; open: string[] }[];\n}\n\nexport interface StackInput {\n\tworkspace: NormalizedWorkspace;\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/**\n\t * Each Worker's crons', queues' and subscribers' files, from discovery —\n\t * which workers run, and which app each is built from.\n\t */\n\tbackground?: Readonly<Record<string, readonly string[]>>;\n\tstage: string;\n\tidentity: DeployIdentity;\n\timages: {\n\t\tmode: 'build' | 'pull';\n\t\t/** A release tag, or — building — the commit. */\n\t\ttag: string;\n\t\tregistry?: string;\n\t};\n\t/** The stage's secrets — set by hand, and what a deployed stage generated. */\n\tsecrets?: StageSecrets | null;\n\t/**\n\t * The dev services a deployed stage may run for mail and buckets its\n\t * secrets do not configure. The local stage runs both regardless.\n\t */\n\tallowDevServices?: readonly DevService[];\n\t/** The edge's published ports. 443 and 80 by default. */\n\tports?: { https?: number; http?: number };\n\t/**\n\t * The stack only builds its images, to push them (`--build --push`): no\n\t * backend's or worker's runtime environment is resolved and no service\n\t * reads an env file, so building needs none of the stage's backend\n\t * secrets. A site's build args — its public URLs — are still resolved.\n\t */\n\tbuildOnly?: boolean;\n\t/**\n\t * For builds: where the images are built from and with what — the build\n\t * root, its package manager and turbo. The workspace's root, with pnpm,\n\t * when not given.\n\t */\n\tlayout?: ImageLayout;\n}\n\n/** A value only the stage's secrets can hold, and they do not. */\nexport class StageSecretMissing extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${app}' reads ${key}, and the stage '${stage}' has none. Nothing in ` +\n\t\t\t\t`the stack can derive it; set it in the stage's secrets: ` +\n\t\t\t\t`gkm secrets:set ${key} '…' --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'StageSecretMissing';\n\t}\n}\n\n/** A deployed stage's secrets with no seed to derive its passwords from. */\nexport class StageSeedMissing extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' has no seed in its secrets, and a deployed stage's ` +\n\t\t\t\t`database passwords are derived from it. Run gkm compose --stage ${stage} ` +\n\t\t\t\t`without --dry-run once, or gkm deploy, to generate it.`,\n\t\t);\n\t\tthis.name = 'StageSeedMissing';\n\t}\n}\n\n/** A workspace with no API and no site to run. */\nexport class NothingToCompose extends Error {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`${root} declares no RestApi, no site and no Worker with work to do, ` +\n\t\t\t\t`so a stack would run nothing. Mobile apps ship through their own ` +\n\t\t\t\t`toolchain.`,\n\t\t);\n\t\tthis.name = 'NothingToCompose';\n\t}\n}\n\n/** A value that cannot be written to an env file a line at a time. */\nexport class EnvValueMultiline extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly key: string,\n\t) {\n\t\tsuper(\n\t\t\t`${key} for '${app}' spans more than one line, and an env file holds ` +\n\t\t\t\t`one value per line. Store it on one line — base64, or JSON — and ` +\n\t\t\t\t`decode it where it is read.`,\n\t\t);\n\t\tthis.name = 'EnvValueMultiline';\n\t}\n}\n\n/** The services a stack's apps wait on and the edge waits on in turn. */\nconst HEALTHY = { condition: 'service_healthy' } as const;\n\n/**\n * An app's health check: its own server, asked on 127.0.0.1 — not\n * `localhost`, which resolves to `::1` first in an Alpine container while a\n * server may listen on IPv4 alone.\n */\nfunction probe(port: number, path: string): StackService['healthcheck'] {\n\treturn {\n\t\ttest: [\n\t\t\t'CMD',\n\t\t\t'wget',\n\t\t\t'-q',\n\t\t\t'-O',\n\t\t\t'/dev/null',\n\t\t\t`http://127.0.0.1:${port}${path}`,\n\t\t],\n\t\tinterval: '5s',\n\t\ttimeout: '3s',\n\t\tretries: 20,\n\t\tstart_period: '10s',\n\t};\n}\n\n/** The stack for one stage. */\nexport function composeStack(input: StackInput): ComposeStack {\n\tconst { workspace, manifest, stage, identity } = input;\n\tconst local = stage === workspace.stages.local;\n\tconst project = composeProject(identity);\n\tconst custom = input.secrets?.custom ?? {};\n\tconst https = input.ports?.https ?? 443;\n\tconst http = input.ports?.http ?? 80;\n\n\t// A server target's backends, whatever `deploy.default` says: the stack is\n\t// one machine running containers, so events are pg-boss beside the\n\t// declared database — and every cache, one declared from that database\n\t// included, is in the stack's own Redis.\n\tconst plan = planFor(manifest, stage, provisionOrder(manifest), {\n\t\tlocalStage: workspace.stages.local,\n\t\tevents: DEFAULT_EVENTS.server,\n\t\tcache: STACK_CACHE,\n\t\t// The stack brings its own edge; reconcile's would front the host.\n\t\tedge: false,\n\t});\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tconst seed = local ? undefined : input.secrets?.seed;\n\tif (!local && !seed) throw new StageSeedMissing(stage);\n\tconst credential = {\n\t\tmaster: local\n\t\t\t? 'geekmidas'\n\t\t\t: localRolePassword(workspace.name, plan, 'master', seed),\n\t\t...(seed ? { seed } : {}),\n\t};\n\n\tconst apps = stackApps(workspace, manifest, plan, {\n\t\tlocal,\n\t\tstage,\n\t\thttps,\n\t\tidentity,\n\t\timages: input.images,\n\t});\n\tconst workers = stackWorkers(\n\t\tworkerUnits(workspace, manifest, input.background ?? {}),\n\t\t{ stage, identity, images: input.images },\n\t);\n\tif (apps.length === 0 && workers.length === 0) {\n\t\tthrow new NothingToCompose(workspace.root);\n\t}\n\n\t// Which construct each key belongs to, so a key is resolved by what it is\n\t// rather than by its spelling.\n\tconst owners = new Map<string, PlannedResource>();\n\tfor (const resource of plan.resources) {\n\t\towners.set(resource.envKey, resource);\n\t\tif (resource.kind === 'email') {\n\t\t\towners.set(provideKey(resource.id, 'from'), resource);\n\t\t\towners.set(provideKey(resource.id, 'inboxUrl'), resource);\n\t\t}\n\t\tif (resource.kind === 'external-api') {\n\t\t\towners.set(provideKey(resource.id, 'credentials'), resource);\n\t\t}\n\t}\n\n\t// The keys each app reads: a backend's environment, and the keys a\n\t// site's build args rename.\n\tconst reads = new Map<string, string[]>();\n\tfor (const app of apps) {\n\t\tconst site = manifest[app.id];\n\t\treads.set(\n\t\t\tapp.name,\n\t\t\tsite?.kind === 'site'\n\t\t\t\t? Object.values(publicEnvFor(site, manifest))\n\t\t\t\t: [...(appEnvKeys(manifest, app.name, input.runnables) ?? [])],\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\treads.set(worker.name, [\n\t\t\t...(workerEnvKeys(manifest, worker.id, input.runnables) ?? []),\n\t\t]);\n\t}\n\tconst domain = workspace.deploy?.domains?.[stage];\n\n\t// The log UI, when the workspace asks for one: its root login, how it is\n\t// reached, and what each backend is handed to send to it.\n\tconst logsConfig = resolveLogs(workspace.deploy?.compose?.logs);\n\tconst logs = logsConfig\n\t\t? stackLogs({\n\t\t\t\tconfig: logsConfig,\n\t\t\t\tstage,\n\t\t\t\tlocal,\n\t\t\t\tproject: workspace.name,\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t\tcustom,\n\t\t\t\thttps,\n\t\t\t})\n\t\t: undefined;\n\n\t// Mail and storage: the local stage runs Mailpit and MinIO for all of it.\n\t// A deployed stage takes each from its secrets — or, where allowed, from a\n\t// dev service — and one missing anything stops here, naming every key.\n\tconst services: ExternalServices = local\n\t\t? {\n\t\t\t\tmissing: [],\n\t\t\t\tminio: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'objects')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t\tmailpit: plan.resources\n\t\t\t\t\t.filter((r) => r.kind === 'email')\n\t\t\t\t\t.map((r) => r.id),\n\t\t\t}\n\t\t: assertExternalServices({\n\t\t\t\tstage,\n\t\t\t\tdeclarations: serviceDeclarations(plan, reads, owners),\n\t\t\t\tsupplied: custom,\n\t\t\t\tallow: input.allowDevServices ?? [],\n\t\t\t\t...(domain ? { domain } : {}),\n\t\t\t});\n\n\t// The caches: in the stack's Redis, unless the stage set a cache's URL —\n\t// a managed Redis — and with every one set, there is no Redis to run.\n\tconst redis = stackRedis({ plan, stage, local, custom });\n\n\tconst infra = [\n\t\t...plan.containers\n\t\t\t.filter((c) => !NOT_RUN[c])\n\t\t\t.filter((c) => c !== 'minio' || services.minio.length > 0)\n\t\t\t.filter((c) => c !== 'mailpit' || services.mailpit.length > 0)\n\t\t\t.filter((c) => c !== REDIS_SERVICE || redis !== undefined),\n\t\t...(logs ? [LOGS_SERVICE] : []),\n\t].sort();\n\n\t// The stack's MinIO signs with the stage's own key pair where it set one,\n\t// and otherwise with a credential derived like every other: the fixed\n\t// local one, or — deployed — from the stage's seed.\n\tconst storage: StackStorage | undefined = infra.includes('minio')\n\t\t? (() => {\n\t\t\t\tconst buckets = services.minio\n\t\t\t\t\t.map((id) => byId.get(id)?.name)\n\t\t\t\t\t.filter((name): name is string => Boolean(name))\n\t\t\t\t\t.sort();\n\t\t\t\treturn {\n\t\t\t\t\tuser:\n\t\t\t\t\t\tcustom.AWS_ACCESS_KEY_ID ??\n\t\t\t\t\t\t(local ? 'geekmidas' : `${workspace.name}-minio`),\n\t\t\t\t\tpassword:\n\t\t\t\t\t\tcustom.AWS_SECRET_ACCESS_KEY ??\n\t\t\t\t\t\t(local\n\t\t\t\t\t\t\t? 'geekmidas'\n\t\t\t\t\t\t\t: localRolePassword(workspace.name, plan, 'minio', seed)),\n\t\t\t\t\tbuckets,\n\t\t\t\t\tpolicies: bucketPolicies(plan).filter((p) =>\n\t\t\t\t\t\tbuckets.includes(p.bucket),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t})()\n\t\t: undefined;\n\n\t// Every key the stage resolves, twice: with each app at its public address\n\t// — what a browser is handed, and what an app says it is — and with each on\n\t// the compose network, which is how one service reaches another.\n\tconst derivation = {\n\t\tproject: workspace.name,\n\t\tmaster: credential.master,\n\t\t...(credential.seed ? { seed: credential.seed } : {}),\n\t\t// Mailpit on a deployed stage sends as the stage's domain.\n\t\t...(!local && domain ? { mailFrom: `noreply@${domain}` } : {}),\n\t};\n\tconst outside = networkEnv(plan, {\n\t\t...derivation,\n\t\taddresses: Object.fromEntries(apps.map((app) => [app.id, app.url])),\n\t});\n\tconst inside = networkEnv(plan, {\n\t\t...derivation,\n\t\taddresses: Object.fromEntries(\n\t\t\tapps.map((app) => [app.id, `http://${app.name}:${app.port}`]),\n\t\t),\n\t});\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; site: EdgeSite }>();\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\tsite: {\n\t\t\t\t\thost,\n\t\t\t\t\tupstream: 'minio:9000',\n\t\t\t\t\trewrite: `/${bucket.name}{uri}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tconst surfaceUrls = new Map(\n\t\tplan.resources\n\t\t\t.filter((r) => r.kind === 'rest-api' || r.kind === 'site')\n\t\t\t.map((r) => [r.envKey, r.id]),\n\t);\n\tconst appById = new Map(apps.map((app) => [app.id, app]));\n\n\t/**\n\t * What a key resolves to for one app, from the stage's secrets where only\n\t * they can hold it, and the derivations otherwise.\n\t */\n\tconst valueFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkey: string,\n\t\towner: PlannedResource | undefined,\n\t): string | undefined => {\n\t\t// Mail and storage: what the stage set — a real server, a real bucket —\n\t\t// and otherwise the dev service it runs, which `services` has already\n\t\t// checked it may.\n\t\tif (owner && SERVICE_KINDS[owner.kind]) {\n\t\t\tif (custom[key] !== undefined) return custom[key];\n\t\t\tif (owner.kind === 'file-server') return fileServers.get(owner.id)?.url;\n\t\t\treturn outside[key];\n\t\t}\n\n\t\t// Supplied by somebody: a third party's credentials, and — deployed —\n\t\t// the secrets the stage generated.\n\t\tif (owner && suppliedOnly(owner.kind, owner.id, key, local)) {\n\t\t\tconst value = custom[key];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new StageSecretMissing(app.name, key, stage);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// Set by hand wins over derived: it is the stage saying what it is.\n\t\tif (custom[key] !== undefined) return custom[key];\n\n\t\t// A cache, in the stack's Redis, by its name on the network.\n\t\tif (owner?.kind === 'cache') return redis?.urls[key];\n\n\t\t// A backend reaches a sibling surface on the compose network; its own\n\t\t// address is the public one, which is what it builds links on. A site\n\t\t// runs in a browser, which has only the public addresses.\n\t\tconst surface = surfaceUrls.get(key);\n\t\tif (app.kind === 'rest-api' && surface && surface !== app.id) {\n\t\t\treturn inside[key];\n\t\t}\n\n\t\treturn outside[key];\n\t};\n\n\t/** Each key one backend process reads, resolved for this stage. */\n\tconst valuesFor = (\n\t\tapp: Pick<StackApp, 'name' | 'id' | 'kind'>,\n\t\tkeys: ReadonlySet<string>,\n\t): Record<string, string> => {\n\t\tconst values: Record<string, string> = {};\n\t\tfor (const key of [...keys].sort()) {\n\t\t\tconst owner = owners.get(key) ?? storageOwner(key, plan);\n\t\t\t// A deployed stage has no inbox: Mailpit runs only locally.\n\t\t\tif (!local && owner?.kind === 'email' && key.endsWith('_INBOX_URL'))\n\t\t\t\tcontinue;\n\t\t\tif ((STORAGE_KEYS as readonly string[]).includes(key)) {\n\t\t\t\t// The stage's own key pair where it set one — an external bucket\n\t\t\t\t// signs with it — and otherwise the stack's MinIO's.\n\t\t\t\tconst value = custom[key] ?? storageValue(key, storage);\n\t\t\t\tif (value !== undefined) values[key] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = valueFor(app, key, owner);\n\t\t\tif (value !== undefined) values[key] = value;\n\t\t}\n\t\treturn values;\n\t};\n\n\tfor (const app of apps) {\n\t\tif (app.kind === 'site') {\n\t\t\tconst site = manifest[app.id];\n\t\t\tif (site?.kind !== 'site') continue;\n\n\t\t\tconst args: Record<string, string> = {};\n\t\t\tfor (const [key, source] of Object.entries(\n\t\t\t\tpublicEnvFor(site, manifest),\n\t\t\t)) {\n\t\t\t\tconst value = valueFor(app, source, owners.get(source));\n\t\t\t\tif (value !== undefined) args[key] = value;\n\t\t\t}\n\t\t\tif (app.build && Object.keys(args).length > 0) app.build.args = args;\n\t\t\tcontinue;\n\t\t}\n\t\t// Built to be pushed, a backend's image is every stage's: what it reads\n\t\t// at runtime is the deploy's business, not the build's.\n\t\tif (input.buildOnly) continue;\n\n\t\tconst keys = appEnvKeys(manifest, app.name, input.runnables) ?? new Set();\n\t\tconst values = valuesFor(app, keys);\n\n\t\t// The origins Better Auth trusts are the browser's and, now, each\n\t\t// service that calls this surface across the compose network: its CSRF\n\t\t// check applies to every caller, and a sibling's request carries its\n\t\t// own origin, not a browser's.\n\t\tconst trusted = provideKey(app.id, 'trustedOrigins');\n\t\tif (keys.has(trusted)) {\n\t\t\tconst internal = (byId.get(app.id)?.callers ?? [])\n\t\t\t\t.map((caller) => appById.get(caller))\n\t\t\t\t.filter((caller): caller is StackApp => caller?.kind === 'rest-api')\n\t\t\t\t.map((caller) => `http://${caller.name}:${caller.port}`);\n\t\t\tconst origins = [\n\t\t\t\t...(values[trusted] ?? '').split(',').filter(Boolean),\n\t\t\t\t...internal,\n\t\t\t];\n\t\t\tvalues[trusted] = [...new Set(origins)].join(',');\n\t\t}\n\n\t\t// Telemetry: the stage's own `OTEL_*`, or the stack's OpenObserve.\n\t\tapp.env = {\n\t\t\t...values,\n\t\t\t...otelEnv({ ...custom, ...logs?.appEnv }, app.name),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(app.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\n\t\tfor (const [key, value] of Object.entries(app.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(app.name, key);\n\t\t}\n\t}\n\n\t// A worker reaches every surface across the compose network: it is never\n\t// one, so no address is its own.\n\tfor (const worker of input.buildOnly ? [] : workers) {\n\t\tconst keys =\n\t\t\tworkerEnvKeys(manifest, worker.id, input.runnables) ?? new Set();\n\t\tworker.env = {\n\t\t\t...valuesFor(\n\t\t\t\t{ name: worker.name, id: worker.id, kind: 'rest-api' },\n\t\t\t\tkeys,\n\t\t\t),\n\t\t\t...otelEnv({ ...custom, ...logs?.appEnv }, worker.name),\n\t\t\tNODE_ENV: 'production',\n\t\t\tPORT: String(worker.port),\n\t\t\tSTAGE: stage,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(worker.env)) {\n\t\t\tif (/[\\r\\n]/.test(value)) throw new EnvValueMultiline(worker.name, key);\n\t\t}\n\t}\n\n\tconst layout = input.layout ?? defaultLayout(workspace.root);\n\tconst compose = stackFile({\n\t\tproject,\n\t\tplan,\n\t\tinfra,\n\t\tapps,\n\t\tworkers,\n\t\tmaster: credential.master,\n\t\t...(storage ? { storage } : {}),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t\thttps,\n\t\thttp,\n\t\tcomposeDir: join(workspace.root, stackDir(stage)),\n\t\tbuildRoot: layout.buildRoot,\n\t\tworkspaceRoot: workspace.root,\n\t\tenvFiles: !input.buildOnly,\n\t});\n\n\tconst caddyfile = edgeCaddyfile(\n\t\t[\n\t\t\t...apps.map((app) => ({\n\t\t\t\thost: app.host,\n\t\t\t\tupstream: `${app.name}:${app.port}`,\n\t\t\t})),\n\t\t\t...[...fileServers.values()].map(({ site }) => site),\n\t\t\t...(logs?.host && logs.public\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thost: logs.host,\n\t\t\t\t\t\t\tupstream: `${LOGS_SERVICE}:${LOGS_PORT}`,\n\t\t\t\t\t\t\tallow: logs.public.allow,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t],\n\t\t{ local },\n\t);\n\n\tconst dockerfiles: Record<string, string> = {};\n\tfor (const app of apps) {\n\t\tif (!app.build) continue;\n\t\t// The same Dockerfile `gkm docker` writes: the image is built inside\n\t\t// Docker from a pruned slice of the build root, and nothing is built\n\t\t// here first.\n\t\tdockerfiles[app.build.dockerfile] = appDockerfile(\n\t\t\tapp.name,\n\t\t\tworkspace.apps[app.name]!,\n\t\t\t{\n\t\t\t\tlayout,\n\t\t\t\tworkspaceRoot: workspace.root,\n\t\t\t\tapps: workspace.apps,\n\t\t\t\tmanifest,\n\t\t\t\tcache: STACK_CACHE,\n\t\t\t},\n\t\t);\n\t}\n\tfor (const worker of workers) {\n\t\tif (!worker.build) continue;\n\t\tdockerfiles[worker.build.dockerfile] = workerDockerfile(\n\t\t\t{ id: worker.id, name: worker.name, app: worker.host },\n\t\t\tworkspace.apps[worker.host]!,\n\t\t\t{ layout, workspaceRoot: workspace.root, cache: STACK_CACHE },\n\t\t);\n\t}\n\n\treturn {\n\t\tproject,\n\t\tstage,\n\t\tlocal,\n\t\tapps,\n\t\tworkers,\n\t\tinfra,\n\t\tcompose,\n\t\tcaddyfile,\n\t\tdockerfiles,\n\t\tplan,\n\t\tcredential,\n\t\t...(storage ? { storage } : {}),\n\t\tdevServices: local ? [] : devServicesUsed(services),\n\t\t...(logs ? { logs } : {}),\n\t\t...(redis ? { redis } : {}),\n\t};\n}\n\n/**\n * The mail and storage constructs a deployed stage's apps read, with who\n * reads each — and every file server's bucket, which serves it whether or\n * not an app reads it directly.\n */\nfunction serviceDeclarations(\n\tplan: Plan,\n\treads: ReadonlyMap<string, readonly string[]>,\n\towners: ReadonlyMap<string, PlannedResource>,\n): ServiceDeclaration[] {\n\tconst byId = new Map(plan.resources.map((r) => [r.id, r]));\n\tconst readers = new Map<string, Set<string>>();\n\tconst add = (id: string, app?: string) => {\n\t\tconst set = readers.get(id) ?? new Set<string>();\n\t\tif (app) set.add(app);\n\t\treaders.set(id, set);\n\t};\n\n\tfor (const [app, keys] of reads) {\n\t\tfor (const key of keys) {\n\t\t\tconst owner = owners.get(key);\n\t\t\tif (!owner || !SERVICE_KINDS[owner.kind]) continue;\n\t\t\t// The inbox is Mailpit's own, never a deployed stage's to set.\n\t\t\tif (owner.kind === 'email' && key.endsWith('_INBOX_URL')) continue;\n\t\t\tadd(owner.id, app);\n\t\t\tif (owner.kind === 'file-server' && owner.of) add(owner.of);\n\t\t}\n\t}\n\n\treturn [...readers].flatMap(([id, apps]) => {\n\t\tconst resource = byId.get(id);\n\t\tconst kind = resource && SERVICE_KINDS[resource.kind];\n\t\tif (!resource || !kind) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tkind,\n\t\t\t\t...(resource.of ? { of: resource.of } : {}),\n\t\t\t\tapps: [...apps].sort(),\n\t\t\t},\n\t\t];\n\t});\n}\n\n/** The stack's MinIO's value for one of the S3 client's keys. */\nfunction storageValue(\n\tkey: string,\n\tstorage: StackStorage | undefined,\n): string | undefined {\n\tif (!storage) return undefined;\n\tif (key === 'AWS_ACCESS_KEY_ID') return storage.user;\n\tif (key === 'AWS_SECRET_ACCESS_KEY') return storage.password;\n\tif (key === 'AWS_REGION') return MINIO_REGION;\n\treturn undefined;\n}\n\n/** Which bucket an S3 credential key belongs to — the first one declared. */\nfunction storageOwner(key: string, plan: Plan): PlannedResource | undefined {\n\tif (!(STORAGE_KEYS as readonly string[]).includes(key)) return undefined;\n\treturn plan.resources.find((r) => r.kind === 'objects');\n}\n\n/** The apps a stack runs: every API and every site, at its stage address. */\nfunction stackApps(\n\tworkspace: NormalizedWorkspace,\n\tmanifest: ConstructManifest,\n\tplan: Plan,\n\toptions: {\n\t\tlocal: boolean;\n\t\tstage: string;\n\t\thttps: number;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackApp[] {\n\tconst apps: StackApp[] = [];\n\tconst resources = new Map(plan.resources.map((r) => [r.id, r]));\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'site')\n\t\t\tcontinue;\n\n\t\tconst name = appKey(id);\n\t\tconst app = workspace.apps[name];\n\t\tconst resource = resources.get(id);\n\t\tif (!app || !resource || !app.port) continue;\n\n\t\tconst host = hostOf(name, app, workspace, resource, options);\n\t\tconst site = declaration.kind === 'site';\n\t\tconst tag = site\n\t\t\t? siteTag(options.images.tag, options.stage)\n\t\t\t: options.images.tag;\n\t\tconst ref = validateImageRef(\n\t\t\timageRef(options.identity, name, options.images.registry, tag),\n\t\t);\n\n\t\tapps.push({\n\t\t\tapp: name,\n\t\t\tname,\n\t\t\tid,\n\t\t\tkind: declaration.kind,\n\t\t\tpath: app.path,\n\t\t\tport: app.port,\n\t\t\thost,\n\t\t\turl: `https://${host}${options.local && options.https !== 443 ? `:${options.https}` : ''}`,\n\t\t\tref,\n\t\t\ttag,\n\t\t\t...(options.images.mode === 'build'\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${name}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\treturn apps.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Each worker's image, and where it is built from. */\nfunction stackWorkers(\n\tunits: readonly WorkerUnit[],\n\toptions: {\n\t\tstage: string;\n\t\tidentity: DeployIdentity;\n\t\timages: StackInput['images'];\n\t},\n): StackWorker[] {\n\treturn units.map((unit) => ({\n\t\tapp: unit.name,\n\t\tname: unit.name,\n\t\tid: unit.id,\n\t\thost: unit.app,\n\t\tport: WORKER_PORT,\n\t\tref: validateImageRef(\n\t\t\timageRef(\n\t\t\t\toptions.identity,\n\t\t\t\tunit.name,\n\t\t\t\toptions.images.registry,\n\t\t\t\toptions.images.tag,\n\t\t\t),\n\t\t),\n\t\ttag: options.images.tag,\n\t\t...(options.images.mode === 'build'\n\t\t\t? {\n\t\t\t\t\tbuild: {\n\t\t\t\t\t\tdockerfile: `${stackDir(options.stage)}/Dockerfile.${unit.name}`,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\n/**\n * The host an app answers on for a stage: the `gkm dev` edge's\n * `*.localhost` names for the local stage, and the stage's domain — by the\n * same rule a deploy follows — for any other.\n */\nfunction hostOf(\n\tname: string,\n\tapp: NormalizedAppConfig,\n\tworkspace: NormalizedWorkspace,\n\tresource: PlannedResource,\n\toptions: { local: boolean; stage: string },\n): string {\n\tif (options.local) return hostFor(resource, workspace.name);\n\n\treturn resolveHost(\n\t\tname,\n\t\tapp,\n\t\toptions.stage,\n\t\tworkspace.deploy?.domains,\n\t\tisMainFrontendApp(name, app, workspace.apps),\n\t);\n}\n\n/** The compose document: the infrastructure, the apps, and the edge. */\nfunction stackFile(options: {\n\tproject: string;\n\tplan: Plan;\n\tinfra: readonly string[];\n\tapps: readonly StackApp[];\n\tworkers: readonly StackWorker[];\n\tmaster: string;\n\tstorage?: StackStorage;\n\tlogs?: StackLogs;\n\tredis?: StackRedis;\n\thttps: number;\n\thttp: number;\n\tcomposeDir: string;\n\tbuildRoot: string;\n\tworkspaceRoot: string;\n\t/** Whether services read env files — not in a stack that only builds. */\n\tenvFiles: boolean;\n}): StackFile {\n\tconst { project, plan, apps } = options;\n\t// What reconcile defines; OpenObserve is the stack's own.\n\tconst infra = options.infra.filter((name) => name !== LOGS_SERVICE);\n\n\t// Reconcile's definitions — images, health checks, volumes — with nothing\n\t// published to the host. Ports are allocation's business there; here the\n\t// edge is the only way in.\n\tconst derived = composeFor(\n\t\t{ ...plan, containers: [...infra] },\n\t\t{\n\t\t\tproject,\n\t\t\tports: Object.fromEntries(\n\t\t\t\tportKeys(infra, plan.fakes).map((key) => [key, 0]),\n\t\t\t),\n\t\t},\n\t);\n\n\tconst services: Record<string, StackService> = {};\n\tconst volumes: Record<string, Record<string, never>> = {\n\t\t...derived.volumes,\n\t\t'caddy-data': {},\n\t\t'caddy-config': {},\n\t\t...(options.logs ? { 'openobserve-data': {} } : {}),\n\t};\n\n\tfor (const name of infra) {\n\t\tconst {\n\t\t\tports: _ports,\n\t\t\tdepends_on,\n\t\t\tprofiles: _profiles,\n\t\t\t...service\n\t\t} = derived.services[name]!;\n\t\tservices[name] = {\n\t\t\t...service,\n\t\t\t...(depends_on?.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tdepends_on.map((dep) => [dep, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tconst postgres = services.postgres;\n\tif (postgres) {\n\t\tpostgres.environment = {\n\t\t\t...postgres.environment,\n\t\t\tPOSTGRES_PASSWORD: options.master,\n\t\t};\n\t\t// Loopback only, on a port Docker picks: gkm creates the databases and\n\t\t// roles and runs the migrations from this machine, and nothing else\n\t\t// should reach the database from outside the stack.\n\t\tpostgres.ports = ['127.0.0.1::5432'];\n\t}\n\n\tconst minio = services.minio;\n\tif (minio && options.storage) {\n\t\tminio.environment = {\n\t\t\t...minio.environment,\n\t\t\tMINIO_ROOT_USER: options.storage.user,\n\t\t\tMINIO_ROOT_PASSWORD: options.storage.password,\n\t\t};\n\t\t// Loopback only, like Postgres: gkm creates the buckets and their\n\t\t// policies from this machine. The apps reach it on the network, and a\n\t\t// browser through a file server's host on the edge.\n\t\tminio.ports = ['127.0.0.1::9000'];\n\t}\n\n\t// Its own definition rather than reconcile's: `gkm dev`'s Redis is an\n\t// open, unbounded scratch store; this one is a production cache.\n\tif (services[REDIS_SERVICE] && options.redis) {\n\t\tservices[REDIS_SERVICE] = redisService(options.redis);\n\t}\n\n\t// Started with the infrastructure, but nothing waits on it: an app whose\n\t// telemetry cannot be delivered still serves.\n\tif (options.logs) services[LOGS_SERVICE] = logsService(options.logs);\n\n\tfor (const app of apps) {\n\t\tservices[app.name] = {\n\t\t\timage: app.ref,\n\t\t\t...(app.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\t...composeBuildPaths({\n\t\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\t\tdockerfile: app.build.dockerfile,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(app.build.args ? { args: app.build.args } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\t// A site is a bundle and reads nothing at runtime; a backend reads\n\t\t\t// exactly the keys in its own file.\n\t\t\t...(app.kind === 'rest-api'\n\t\t\t\t? {\n\t\t\t\t\t\tenv_file: [{ path: `./${app.name}.env`, format: 'raw' as const }],\n\t\t\t\t\t\t...(infra.length\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(app.port, app.kind === 'site' ? '/' : '/health'),\n\t\t};\n\t}\n\n\t// A worker: no route, no published port — its health check is Docker's.\n\tfor (const worker of options.workers) {\n\t\tservices[worker.name] = {\n\t\t\timage: worker.ref,\n\t\t\t...(worker.build\n\t\t\t\t? {\n\t\t\t\t\t\tbuild: composeBuildPaths({\n\t\t\t\t\t\t\tcomposeDir: options.composeDir,\n\t\t\t\t\t\t\tbuildRoot: options.buildRoot,\n\t\t\t\t\t\t\tworkspaceRoot: options.workspaceRoot,\n\t\t\t\t\t\t\tdockerfile: worker.build.dockerfile,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\trestart: 'unless-stopped',\n\t\t\tenv_file: [{ path: `./${worker.name}.env`, format: 'raw' as const }],\n\t\t\t...(infra.length\n\t\t\t\t? {\n\t\t\t\t\t\tdepends_on: Object.fromEntries(\n\t\t\t\t\t\t\tinfra.map((name) => [name, HEALTHY]),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\thealthcheck: probe(worker.port, '/health'),\n\t\t};\n\t}\n\n\tservices.caddy = {\n\t\timage: DEFAULT_IMAGES.caddy!,\n\t\trestart: 'unless-stopped',\n\t\tports: [`${options.https}:443`, `${options.http}:80`],\n\t\tvolumes: [\n\t\t\t'./Caddyfile:/etc/caddy/Caddyfile:ro',\n\t\t\t'caddy-data:/data',\n\t\t\t'caddy-config:/config',\n\t\t],\n\t\tdepends_on: Object.fromEntries(apps.map((app) => [app.name, HEALTHY])),\n\t\thealthcheck: {\n\t\t\ttest: ['CMD', 'caddy', 'version'],\n\t\t\tinterval: '10s',\n\t\t\ttimeout: '5s',\n\t\t\tretries: 5,\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 { name: project, services, volumes };\n}\n\n/**\n * A build without a layout: the workspace is the build root, with pnpm.\n * What a caller that never looked at the filesystem gets.\n */\nfunction defaultLayout(root: string): ImageLayout {\n\treturn {\n\t\tbuildRoot: root,\n\t\tgkmRoot: '.',\n\t\ttools: {\n\t\t\tpackageManager: 'pnpm',\n\t\t\tturboVersion: TURBO_VERSION,\n\t\t\tmonorepo: true,\n\t\t},\n\t\tgkmPaths: ['gkm.config.*'],\n\t};\n}\n\n/** Render an app's env file: one `KEY=value` per line, read raw by compose. */\nexport function envFile(env: Readonly<Record<string, string>>): string {\n\treturn `${Object.entries(env)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join('\\n')}\\n`;\n}\n","/**\n * Asking each app of a stack whether it answers — through Caddy, over HTTPS,\n * the way a browser reaches it.\n *\n * `docker compose up --wait` already knows each container passed its own\n * health check, asked on 127.0.0.1 inside it. What that cannot say is whether\n * the stack is reachable: whether the edge routes the host to the app, and\n * whether the certificate it presents is one a client accepts. So the check\n * goes through the edge, by hostname, and verifies the certificate.\n */\n\nimport { request } from 'node:https';\n\n/** One request to the edge. */\nexport interface HealthRequest {\n\t/** The app's public URL plus its health path. */\n\turl: string;\n\t/**\n\t * The certificate authority to verify against, PEM — Caddy's internal CA\n\t * on the local stage. The system's when absent.\n\t */\n\tca?: string;\n\t/**\n\t * Connect here instead of resolving the URL's host — the local edge, at\n\t * 127.0.0.1. The host is still sent as SNI and `Host`, so nothing depends\n\t * on how this machine resolves `*.localhost`.\n\t */\n\tconnectTo?: string;\n\ttimeoutMs: number;\n\tsignal?: AbortSignal;\n}\n\n/** Asks once, resolving with the HTTP status. Rejects when nothing answers. */\nexport type HealthProbe = (request: HealthRequest) => Promise<number>;\n\n/** A request that got no answer in time. */\nexport class HealthRequestTimedOut extends Error {\n\tconstructor(\n\t\treadonly url: string,\n\t\treadonly timeoutMs: number,\n\t) {\n\t\tsuper(\n\t\t\t`${url} did not answer within ${timeoutMs}ms. Check the stack is up with \\`docker compose ps\\`.`,\n\t\t);\n\t\tthis.name = 'HealthRequestTimedOut';\n\t}\n}\n\n/** The real probe: one HTTPS GET, the certificate verified. */\nexport const httpsProbe: HealthProbe = ({\n\turl,\n\tca,\n\tconnectTo,\n\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: target.port || 443,\n\t\t\t\tservername: target.hostname,\n\t\t\t\tpath: `${target.pathname}${target.search}`,\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: { host: target.host },\n\t\t\t\t...(ca ? { ca } : {}),\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t\ttimeout: timeoutMs,\n\t\t\t},\n\t\t\t(res) => {\n\t\t\t\t// The status is the answer; the body is drained so the socket closes.\n\t\t\t\tres.resume();\n\t\t\t\tres.on('end', () => resolve(res.statusCode ?? 0));\n\t\t\t\tres.on('error', reject);\n\t\t\t},\n\t\t);\n\t\treq.on('timeout', () =>\n\t\t\treq.destroy(new HealthRequestTimedOut(url, timeoutMs)),\n\t\t);\n\t\treq.on('error', reject);\n\t\treq.end();\n\t});\n};\n\n/** Whether a status means the app answered as it should. */\nexport function isHealthy(status: number): boolean {\n\treturn status >= 200 && status < 400;\n}\n\n/** Apps that did not answer through the edge. */\nexport class ComposeAppsUnhealthy extends Error {\n\tconstructor(\n\t\treadonly project: string,\n\t\t/** Each app, and the last thing its check got: a status or an error. */\n\t\treadonly apps: readonly { app: string; url: string; last: string }[],\n\t) {\n\t\tsuper(\n\t\t\t`${project} started, but ${apps.length === 1 ? 'this app does' : 'these apps do'} not answer through Caddy:\\n` +\n\t\t\t\tapps.map(({ url, last }) => ` - ${url}: ${last}`).join('\\n') +\n\t\t\t\t`\\nSee why with \\`docker compose -p ${project} logs caddy ${apps.map((a) => a.app).join(' ')}\\`.`,\n\t\t);\n\t\tthis.name = 'ComposeAppsUnhealthy';\n\t}\n}\n","/**\n * The compose target's phases: a stage as one Docker Compose stack behind\n * Caddy, on the machine the deploy runs on.\n *\n * The order is the point of this file, and the rules it keeps are these:\n *\n * - A tag is checked before anything happens (`validate`). Every app's image\n * is asked of the registry first; one missing image stops the run naming\n * them all, and nothing is written, pulled or started.\n * - The databases exist before the apps do (`provision`). Postgres comes up\n * alone, its databases, roles and grants are created and its migrations\n * applied from this machine, and only then do the apps start — so an app\n * never boots against a schema that is not there yet.\n * - What a stage runs is recorded (`release`). Each app's image, the tag it\n * was released under and the digest it resolved to are written to the\n * stage's state, so \"what is this stage running\" has an exact answer.\n * - What was started answers (`verify`): each app is asked through Caddy,\n * over HTTPS, with the certificate verified.\n *\n * Every image is built inside Docker from a pruned slice of the build root —\n * the same Dockerfiles `gkm docker` writes — so nothing is built on this\n * machine before `docker compose build`.\n *\n * Docker, the registry, Postgres and the health probe are\n * injected, so the rules are asserted without a daemon; the defaults are the\n * real ones.\n */\n\nimport { existsSync } from 'node:fs';\nimport {\n\tchmod,\n\tmkdir,\n\treaddir,\n\treadFile,\n\trm,\n\twriteFile,\n} from 'node:fs/promises';\nimport { hostname, userInfo } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { stringify } from 'yaml';\nimport {\n\ttype ComposeDocker,\n\tdockerCompose,\n\ttype StackRef,\n} from '../../compose/docker';\nimport {\n\tassertImagesExist,\n\ttype ImageDigests,\n\tpinImages,\n\tRegistryRequired,\n} from '../../compose/images';\nimport {\n\tLOGS_SERVICE,\n\tlogsAccess,\n\ttype StackLogs,\n\twithLogsPassword,\n} from '../../compose/logs';\nimport { resolveLogs } from '../../compose/logsConfig';\nimport {\n\tREDIS_SERVICE,\n\trunsRedis,\n\twithRedisPassword,\n} from '../../compose/redis';\nimport {\n\ttype ComposeStack,\n\tcomposeProject,\n\tcomposeStack,\n\tEDGE_PORT_ENV,\n\tenvFile,\n\ttype StackApp,\n\tstackDir,\n} from '../../compose/stack';\nimport { reportDevServices } from '../../deploy/devServices';\nimport type { ResourceChange } from '../../deploy/events';\nimport { withGeneratedSecrets } from '../../deploy/generated.js';\nimport { imageRef } from '../../deploy/identity.js';\nimport { DeployJournal } from '../../deploy/journal';\nimport {\n\tcreateEmptyState,\n\ttype DeployedImage,\n\trecordRelease,\n} from '../../deploy/state.js';\nimport type { DeployResult } from '../../deploy/types';\nimport { ensureDockerignore } from '../../docker/index.js';\nimport { imageLayout } from '../../docker/layout.js';\nimport { findBuildRoot } from '../../docker/templates.js';\nimport { installedFrom } from '../../generators/drivers.js';\nimport { migrateDatabases } from '../../migrate/databases.js';\nimport { bucketClient, pgClient } from '../../reconcile/clients.js';\nimport { primaryPortKey } from '../../reconcile/containers.js';\nimport { type ConstructSource, discover } from '../../reconcile/discover.js';\nimport { envFor } from '../../reconcile/env.js';\nimport {\n\tapplyBuckets,\n\tapplyPolicies,\n\tapplyPostgres,\n\tpostgresStatements,\n} from '../../reconcile/provision.js';\nimport { constructGlobs } from '../../reconcile/workspace.js';\nimport { runOutput } from '../../run';\nimport { assertStageCredentials } from '../../secrets/credentialSchemas.js';\nimport { assertNoStaleSecrets } from '../../secrets/stale.js';\nimport { initStageSecrets } from '../../secrets/storage.js';\nimport type { StageSecrets } from '../../secrets/types.js';\nimport type { NormalizedWorkspace } from '../../workspace/types.js';\nimport type { DeployPhaseContext } from '../types';\nimport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\thttpsProbe,\n\tisHealthy,\n} from './health';\n\n/** Every phase's context: the compose target takes no options. */\nexport type ComposeContext = DeployPhaseContext<undefined>;\n\n/** What the target needs from outside the process, so tests can stand in. */\nexport interface ComposeDeps {\n\tdocker: ComposeDocker;\n\t/** The commit a build is tagged with. */\n\trevision: (root: string) => Promise<string>;\n\t/** The Postgres client provisioning and migrations connect through. */\n\tsql: typeof pgClient;\n\t/** The S3 client the stack's buckets are created through. */\n\tbuckets: typeof bucketClient;\n\t/** Apply the stage's migrations — `migrateDatabases` by default. */\n\tmigrate: typeof migrateDatabases;\n\t/** Ask one app, through the edge, whether it answers. */\n\tprobe: HealthProbe;\n\t/** How many times each app is asked before it counts as down. */\n\thealthAttempts: number;\n\t/** How long to wait between two asks of one app. */\n\thealthIntervalMs: number;\n\t/** Where the edge's ports are read from (`GKM_COMPOSE_HTTPS_PORT`, …). */\n\tenv: NodeJS.ProcessEnv;\n}\n\n/** One app's image, as the stage runs it. */\nexport interface ComposeImage {\n\tref: string;\n\ttag: string;\n\tdigest?: string;\n}\n\n/** A compose deploy in progress: what `validate` found, and what follows. */\nexport interface ComposeRun {\n\t/** Build the images from this checkout, or pull the ones a tag names. */\n\tmode: 'build' | 'pull';\n\t/**\n\t * Build and push the images, and nothing else (`--build --push`): no\n\t * provisioning, no container started, nothing recorded.\n\t */\n\tpush: boolean;\n\tstack: ComposeStack;\n\t/** The stack's directory, absolute: `.gkm/compose/<stage>`. */\n\tdir: string;\n\tref: StackRef;\n\t/** The stage's secrets, with whatever a deployed stage generates once. */\n\tsecrets: StageSecrets | null;\n\t/** The names of what was generated, written back in `provision`. */\n\tgenerated: string[];\n\t/** Each app's image as the stage's state last recorded it. */\n\tprevious: Record<string, DeployedImage>;\n\t/** Every file written, absolute. */\n\tfiles: string[];\n\t/** Each app's image, once built or pulled. */\n\timages: Record<string, ComposeImage>;\n\t/** Every resource the run touched, or for a dry run would. */\n\tchanges: ResourceChange[];\n}\n\n/** How a run gets its images, beyond what the tag implies. */\nexport interface ComposeRunOptions {\n\t/**\n\t * Build or pull whatever the tag says. By default a given tag is pulled\n\t * and no tag builds from the checkout.\n\t */\n\tmode?: 'build' | 'pull';\n\t/** Push what was built, and start nothing (`--build --push`). */\n\tpush?: boolean;\n\t/** Run each pulled image at the digest a push reported for it. */\n\tpin?: { file: string; digests: ImageDigests };\n}\n\n/** `--push` without `--build`: there is nothing built here to push. */\nexport class ComposePushNeedsBuild extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--push pushes the images this checkout builds, so it needs --build ' +\n\t\t\t\t'(and never --pull): gkm compose --stage <stage> --build --push --tag <tag>.',\n\t\t);\n\t\tthis.name = 'ComposePushNeedsBuild';\n\t}\n}\n\n/** Digests to run by, on a run that pulls nothing. */\nexport class ComposePinNeedsPull extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--digests-file pins the images a release pulls, so it needs --tag ' +\n\t\t\t\t'(or --pull) — or, with --build --push, it is where the pushed digests ' +\n\t\t\t\t'are written.',\n\t\t);\n\t\tthis.name = 'ComposePinNeedsPull';\n\t}\n}\n\n/** A port variable that does not hold a port. */\nexport class EdgePortInvalid extends Error {\n\tconstructor(\n\t\treadonly variable: string,\n\t\treadonly value: string,\n\t) {\n\t\tsuper(\n\t\t\t`${variable}=${value} is not a port. Set it to a number between 1 and 65535, or unset it for the default.`,\n\t\t);\n\t\tthis.name = 'EdgePortInvalid';\n\t}\n}\n\n/** A build with no commit to tag its images with. */\nexport class NoGitRevision extends Error {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`Images built here are tagged with the commit they were built from, ` +\n\t\t\t\t`and ${root} is not in a git repository with a commit. Commit, or ` +\n\t\t\t\t`pass --tag to name the images yourself.`,\n\t\t);\n\t\tthis.name = 'NoGitRevision';\n\t}\n}\n\n/**\n * The project's own file merged over a stage's stack: `docker-compose.<stage>.yml`\n * at the workspace root. What the generated file cannot know — a port bound\n * to a tailnet address, another log driver — goes there, and is never\n * overwritten.\n */\nexport function stackOverrideFile(root: string, stage: string): string {\n\treturn join(root, `docker-compose.${stage}.yml`);\n}\n\n/** The commit HEAD is at, short — and `-dirty` when the tree has changes. */\nexport async function gitRevision(root: string): Promise<string> {\n\tlet sha: string;\n\ttry {\n\t\tsha = (\n\t\t\tawait runOutput('git', ['rev-parse', '--short', 'HEAD'], { cwd: root })\n\t\t).trim();\n\t} catch {\n\t\tthrow new NoGitRevision(root);\n\t}\n\tif (!sha) throw new NoGitRevision(root);\n\n\t// An image built from uncommitted changes is not the commit's image, and a\n\t// tag that said it was would be the one thing worse than no tag.\n\tconst status = await runOutput('git', ['status', '--porcelain'], {\n\t\tcwd: root,\n\t}).catch(() => '');\n\treturn status.trim() ? `${sha}-dirty` : sha;\n}\n\n/** The edge's ports, from the environment — 443 and 80 when unset. */\nexport function edgePorts(env: NodeJS.ProcessEnv = process.env): {\n\thttps: number;\n\thttp: number;\n} {\n\tconst read = (variable: string, fallback: number) => {\n\t\tconst value = env[variable];\n\t\tif (value === undefined || value === '') return fallback;\n\t\tconst port = Number(value);\n\t\tif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n\t\t\tthrow new EdgePortInvalid(variable, value);\n\t\t}\n\t\treturn port;\n\t};\n\treturn {\n\t\thttps: read(EDGE_PORT_ENV.https, 443),\n\t\thttp: read(EDGE_PORT_ENV.http, 80),\n\t};\n}\n\n/**\n * The real ones. Each app is asked for three minutes before it counts as\n * down: a deployed stage's first ACME certificate can take that long.\n */\nexport const defaultDeps: ComposeDeps = {\n\tdocker: dockerCompose,\n\trevision: gitRevision,\n\tsql: pgClient,\n\tbuckets: bucketClient,\n\tmigrate: migrateDatabases,\n\tprobe: httpsProbe,\n\thealthAttempts: 90,\n\thealthIntervalMs: 2_000,\n\tenv: process.env,\n};\n\n// ============================================================================\n// validate\n// ============================================================================\n\n/**\n * The stack the stage would run, and — for a tag — the registry's word that\n * every image it names exists. Nothing is written: a missing image stops the\n * run here, before a file, a secret or a container is touched.\n */\nexport async function validateCompose(\n\tctx: ComposeContext,\n\tdeps: ComposeDeps,\n\toptions: ComposeRunOptions = {},\n): Promise<ComposeRun> {\n\tconst { workspace, stage, identity, tag } = ctx;\n\tconst root = workspace.root;\n\tconst mode = options.mode ?? (ctx.tagGiven ? 'pull' : 'build');\n\tconst push = options.push === true;\n\tif (push && mode !== 'build') throw new ComposePushNeedsBuild();\n\tif (options.pin && mode !== 'pull') throw new ComposePinNeedsPull();\n\n\t// An image pushed or pulled with no registry is a Docker Hub name, which\n\t// is somebody else's. Refused before anything is discovered, built or\n\t// asked of a registry.\n\tconst registry = workspace.deploy?.registry;\n\tif (!registry && (push || mode === 'pull')) {\n\t\tthrow new RegistryRequired(\n\t\t\tpush ? 'push' : 'pull',\n\t\t\timageRef(identity, ctx.apps[0] ?? workspace.name, undefined, tag),\n\t\t);\n\t}\n\n\t// The runnables' edges say which surface reaches which; the manifest the\n\t// run discovered has the declarations but not them.\n\tconst runnables: Record<string, string[]> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: root,\n\t\trunnables,\n\t\tbackground,\n\t});\n\n\tconst { secrets, generated } = await stageSecrets(ctx, manifest);\n\n\t// A third party's credentials against their construct's schema, before a\n\t// stack is composed with one every app reading it would refuse. A push\n\t// runs no app, so it reads none of them.\n\tif (!push) {\n\t\t// An address an older gkm stored for what a construct now provides:\n\t\t// set by hand wins, so every app would be handed `localhost`.\n\t\tassertNoStaleSecrets({\n\t\t\tmanifest,\n\t\t\tstage,\n\t\t\tsupplied: secrets?.custom ?? {},\n\t\t});\n\t\tawait assertStageCredentials({\n\t\t\troot,\n\t\t\tpatterns: constructGlobs(workspace),\n\t\t\tmanifest,\n\t\t\tstage,\n\t\t\tsupplied: secrets?.custom ?? {},\n\t\t});\n\t}\n\n\t// Where and with what the images are built — only asked when they are.\n\tconst layout = mode === 'build' ? imageLayout(workspace) : undefined;\n\n\tconst composed = composeStack({\n\t\tworkspace,\n\t\tmanifest,\n\t\trunnables,\n\t\tbackground,\n\t\tstage,\n\t\tidentity,\n\t\timages: {\n\t\t\tmode,\n\t\t\ttag,\n\t\t\t...(registry ? { registry } : {}),\n\t\t},\n\t\tsecrets,\n\t\tallowDevServices: ctx.allowDevServices,\n\t\tports: edgePorts(deps.env),\n\t\t...(layout ? { layout } : {}),\n\t\t...(push ? { buildOnly: true } : {}),\n\t});\n\n\t// Loud, every run — a dry run included: a deployed stage on Mailpit\n\t// delivers no mail, and one on MinIO keeps its files on one disk.\n\treportDevServices(ctx, composed.devServices);\n\n\t// A cache is reached over the Redis wire protocol, and the client is the\n\t// project's own dependency: a build without it fails deep inside Docker.\n\tif (mode === 'build') assertRedisClient(workspace, composed);\n\n\t// No image embeds the stage's secrets: a backend reads them at runtime\n\t// from its env file, so one image built at a commit runs on every stage.\n\t// A pinned release runs each image at the digest its push reported.\n\tconst stack = options.pin\n\t\t? withPinnedImages(composed, options.pin.file, options.pin.digests)\n\t\t: composed;\n\n\t// A release is all of its images or none of them. A dry run asks nothing,\n\t// so it can be run without a registry login.\n\tif (mode === 'pull' && !ctx.dryRun) {\n\t\tawait assertImagesExist(deps.docker, tag, [\n\t\t\t...stack.apps,\n\t\t\t...stack.workers,\n\t\t]);\n\t}\n\n\tif (stack.redis && !stack.local) ctx.secrets.mask(stack.redis.password);\n\n\t// The log UI's root login and the header every backend signs in with:\n\t// secrets, unless they are the local stage's fixed ones.\n\tif (stack.logs && (!stack.local || stack.logs.passwordFromSecrets)) {\n\t\tctx.secrets.mask(stack.logs.password);\n\t\tctx.secrets.mask(stack.logs.appEnv.OTEL_EXPORTER_OTLP_HEADERS);\n\t}\n\n\tconst dir = join(root, stackDir(stage));\n\tconst override = stackOverrideFile(root, stage);\n\tconst overrides = existsSync(override) ? [override] : [];\n\tif (overrides.length > 0) {\n\t\tctx.logger.info(\n\t\t\t`🧩 Merging docker-compose.${stage}.yml over the generated stack`,\n\t\t);\n\t}\n\t// What each app ran before this release: its current release, by the same\n\t// record the Dokploy target keeps, so a rollback reads one shape for both.\n\t// A push changes no stage, so it reads none of its state either.\n\tconst recorded = push ? undefined : await ctx.state.read(stage);\n\tconst previous = Object.fromEntries(\n\t\tObject.entries(recorded?.state.releases ?? {}).map(\n\t\t\t([name, releases]): [string, DeployedImage] => {\n\t\t\t\tconst { ref, tag, digest } = releases.current;\n\t\t\t\treturn [\n\t\t\t\t\tname,\n\t\t\t\t\t{ ref, ...(tag ? { tag } : {}), ...(digest ? { digest } : {}) },\n\t\t\t\t];\n\t\t\t},\n\t\t),\n\t);\n\n\treturn {\n\t\tmode,\n\t\tpush,\n\t\tstack,\n\t\tdir,\n\t\tref: {\n\t\t\tproject: composeProject(identity),\n\t\t\tfile: join(dir, 'docker-compose.yml'),\n\t\t\t...(overrides.length > 0 ? { overrides } : {}),\n\t\t\tcwd: root,\n\t\t\toutput: ctx.childOutput,\n\t\t\tsignal: ctx.signal,\n\t\t},\n\t\tsecrets,\n\t\tgenerated,\n\t\tprevious,\n\t\tfiles: [],\n\t\timages: {},\n\t\tchanges: [],\n\t};\n}\n\n/** A stack whose caches are in Redis, built for an app that has no client. */\nexport class RedisClientMissing extends Error {\n\tconstructor(readonly apps: readonly string[]) {\n\t\tsuper(\n\t\t\t`The stack keeps every cache in Redis, and ${apps.join(', ')} ` +\n\t\t\t\t`${apps.length === 1 ? 'does' : 'do'} not depend on ioredis, the client ` +\n\t\t\t\t'the generated server reaches it with. Add it to the workspace: ' +\n\t\t\t\t'pnpm add ioredis',\n\t\t);\n\t\tthis.name = 'RedisClientMissing';\n\t}\n}\n\n/**\n * Every backend and worker image built for a stack with a cache can resolve\n * `ioredis` — listed by its app or a directory above it, the way Node and\n * the image's install find it.\n */\nfunction assertRedisClient(\n\tworkspace: NormalizedWorkspace,\n\tstack: ComposeStack,\n): void {\n\tif (!stack.plan.resources.some((r) => r.kind === 'cache')) return;\n\n\tconst hosts = new Set([\n\t\t...stack.apps.filter((app) => app.kind === 'rest-api').map((a) => a.name),\n\t\t...stack.workers.map((worker) => worker.host),\n\t]);\n\tconst missing = [...hosts]\n\t\t.filter((name) => {\n\t\t\tconst app = workspace.apps[name];\n\t\t\treturn app && !installedFrom(join(workspace.root, app.path), 'ioredis');\n\t\t})\n\t\t.sort();\n\tif (missing.length > 0) throw new RedisClientMissing(missing);\n}\n\n/**\n * The stage's secrets — and, for a deployed stage, everything it generates\n * once: its seed, and each declared secret and keyring. Kept only once the\n * run goes ahead (`provision`), so a dry run, or a tag that is not there,\n * leaves the stage's secrets as it found them.\n */\nasync function stageSecrets(\n\tctx: ComposeContext,\n\tmanifest: ConstructManifest,\n): Promise<{ secrets: StageSecrets | null; generated: string[] }> {\n\tconst stored = await ctx.secrets.read();\n\tif (ctx.stage === ctx.workspace.stages.local) {\n\t\treturn { secrets: stored, generated: [] };\n\t}\n\n\tconst withSeed = withGeneratedSecrets(\n\t\tstored ?? initStageSecrets(ctx.stage),\n\t\tmanifest,\n\t);\n\t// The log UI's root password, generated once like the seed, where the\n\t// workspace runs one and the stage set none.\n\tconst withLogs = resolveLogs(ctx.workspace.deploy?.compose?.logs)\n\t\t? withLogsPassword(withSeed.secrets)\n\t\t: { secrets: withSeed.secrets, generated: [] };\n\t// The stack's Redis password, the same way, where a cache lives in it.\n\tconst withRedis = runsRedis(manifest, withLogs.secrets.custom ?? {})\n\t\t? withRedisPassword(withLogs.secrets)\n\t\t: { secrets: withLogs.secrets, generated: [] };\n\tconst secrets = withRedis.secrets;\n\tconst generated = [\n\t\t...withSeed.generated,\n\t\t...withLogs.generated,\n\t\t...withRedis.generated,\n\t];\n\t// Read through the store they are masked; made up here, they are not yet.\n\tif (secrets.seed) ctx.secrets.mask(secrets.seed);\n\tfor (const value of Object.values(secrets.custom ?? {})) {\n\t\tctx.secrets.mask(value);\n\t}\n\treturn { secrets, generated };\n}\n\n/**\n * The stack with each app's and worker's image pinned to the digest the file\n * names: the refs it is checked, pulled and recorded by, and the image each\n * compose service runs.\n */\nfunction withPinnedImages(\n\tstack: ComposeStack,\n\tfile: string,\n\tdigests: ImageDigests,\n): ComposeStack {\n\tconst apps = pinImages(file, digests, stack.apps);\n\tconst workers = pinImages(file, digests, stack.workers);\n\tconst services = { ...stack.compose.services };\n\tfor (const image of [...apps, ...workers]) {\n\t\tservices[image.name] = { ...services[image.name]!, image: image.ref };\n\t}\n\treturn {\n\t\t...stack,\n\t\tapps,\n\t\tworkers,\n\t\tcompose: { ...stack.compose, services },\n\t};\n}\n\n// ============================================================================\n// plan (dry run)\n// ============================================================================\n\n/**\n * A dry run: the stack's files, written so they can be read, and what a real\n * run would do — no image is built or pulled, no container touched, nothing\n * recorded and no secret kept.\n */\nexport async function planCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): Promise<void> {\n\tif (run.generated.length > 0) {\n\t\tctx.logger.info(\n\t\t\t`🔑 \"${ctx.stage}\" has no ${run.generated.join(', ')} yet; this dry run used values it did not keep.`,\n\t\t);\n\t}\n\trun.files = await writeStack(ctx.cwd, run.dir, run.stack);\n\tprintPlan(ctx, run);\n\n\tconst planned = (change: ResourceChange) => {\n\t\trun.changes.push(change);\n\t\tctx.emit({ type: 'resource.planned', ...change });\n\t};\n\tfor (const service of run.push ? [] : run.stack.infra) {\n\t\tplanned({\n\t\t\tkey: `service:${service}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t});\n\t}\n\tfor (const app of run.stack.apps) {\n\t\tplanned({\n\t\t\tkey: `image:${app.name}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: app.ref,\n\t\t});\n\t\tif (run.push) continue;\n\t\tplanned({\n\t\t\tkey: `service:${app.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: run.previous[app.name] ? 'reuse' : 'create',\n\t\t});\n\t}\n\tfor (const worker of run.stack.workers) {\n\t\tplanned({\n\t\t\tkey: `image:${worker.name}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: worker.ref,\n\t\t});\n\t\tif (run.push) continue;\n\t\tplanned({\n\t\t\tkey: `service:${worker.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: run.previous[worker.name] ? 'reuse' : 'create',\n\t\t});\n\t}\n\tif (!run.push) {\n\t\tplanned({\n\t\t\tkey: 'service:caddy',\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\trun.files = await writeStack(ctx.cwd, run.dir, stack);\n\tprintPlan(ctx, run);\n\n\tif (stack.infra.length > 0) {\n\t\tctx.logger.info(`\\n🗄️ Starting ${stack.infra.join(', ')}…`);\n\t\tawait deps.docker.up(ref, stack.infra);\n\t\tfor (const service of stack.infra) {\n\t\t\tapplied(ctx, run, {\n\t\t\t\tkey: `service:${service}`,\n\t\t\t\tresourceType: 'service',\n\t\t\t\taction: 'ensure',\n\t\t\t\tid: `${stack.project}/${service}`,\n\t\t\t\tvia: Object.keys(run.previous).length > 0 ? 'recorded' : 'created',\n\t\t\t});\n\t\t}\n\t}\n\n\tif (stack.infra.includes('postgres')) {\n\t\tawait prepareDatabases(ctx, run, deps);\n\t}\n\tif (stack.storage && stack.infra.includes('minio')) {\n\t\tawait prepareBuckets(ctx, run, deps);\n\t}\n}\n\n/**\n * Create each bucket the stack's MinIO serves, and the open paths of each\n * one a file server fronts — from this machine, on MinIO's loopback port,\n * the way `gkm dev` creates them.\n */\nasync function prepareBuckets(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst storage = run.stack.storage!;\n\tif (storage.buckets.length === 0) return;\n\n\tconst port = await deps.docker.port(run.ref, 'minio', 9000);\n\tconst client = deps.buckets(port, storage);\n\tconst done = [\n\t\t...(await applyBuckets(client, storage.buckets)),\n\t\t...(await applyPolicies(client, storage.policies)),\n\t];\n\tconst created = done.filter((entry) => entry.created).length;\n\tctx.logger.info(\n\t\t`🪣 Buckets: ${storage.buckets.join(', ')}${created ? ` (${created} change(s))` : ''}`,\n\t);\n}\n\n/** Create what the plan names in the stack's Postgres, then migrate it. */\nasync function prepareDatabases(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\tconst workspace: NormalizedWorkspace = ctx.workspace;\n\tconst port = await deps.docker.port(run.ref, 'postgres', 5432);\n\n\tconst statements = postgresStatements(\n\t\tstack.plan,\n\t\tworkspace.name,\n\t\tstack.credential.seed,\n\t);\n\tif (statements.length > 0) {\n\t\tctx.logger.info('🗄️ Creating databases, roles and grants…');\n\t\tawait applyPostgres(deps.sql(port, stack.credential.master), statements);\n\t}\n\n\t// Migrations run here, with the project's own Kysely, the way `gkm\n\t// migrate` runs them — so the constructs themselves are needed, which\n\t// only an in-process discovery hands back.\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: workspace.root,\n\t\tsources,\n\t});\n\n\t// The owner URLs, on the port published to this machine.\n\tconst env = envFor(stack.plan, {\n\t\tports: { [primaryPortKey('postgres')]: port },\n\t\tproject: workspace.name,\n\t\tmaster: stack.credential.master,\n\t\t...(stack.credential.seed ? { seed: stack.credential.seed } : {}),\n\t});\n\tconst runs = await deps.migrate({\n\t\troot: workspace.root,\n\t\tmanifest,\n\t\tsources,\n\t\tenv,\n\t});\n\tfor (const { target, applied } of runs) {\n\t\tif (applied.length > 0) {\n\t\t\tctx.logger.info(`🗄️ ${target.migrations}: applied ${applied.length}`);\n\t\t}\n\t}\n}\n\n// ============================================================================\n// build\n// ============================================================================\n\n/**\n * Each app's image: built from this checkout — inside Docker, every one of\n * them, from a pruned slice of the build root — or pulled at the tag. Nothing\n * live changes.\n */\nexport async function buildCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack, ref } = run;\n\tconst images = [...stack.apps, ...stack.workers];\n\tconst apps = images.map((image) => image.app);\n\n\t// Nothing was provisioned, so nothing has written the files it builds from.\n\tif (run.push) {\n\t\trun.files = await writeStack(ctx.cwd, run.dir, stack);\n\t\tprintPlan(ctx, run);\n\t}\n\n\tif (run.mode === 'build') {\n\t\tctx.logger.info('\\n🐳 Building images…');\n\t\tawait deps.docker.build(ref, apps);\n\t} else {\n\t\tctx.logger.info(`\\n🐳 Pulling ${ctx.tag}…`);\n\t\tawait deps.docker.pull(ref, apps);\n\t}\n\n\tif (run.push) ctx.logger.info('\\n📤 Pushing images…');\n\n\t// What each tag resolved to: the registry's digest for a pushed or pulled\n\t// image, or — for one built here and never pushed — its content id.\n\tfor (const image of images) {\n\t\tconst digest = run.push\n\t\t\t? await deps.docker.push(ref, image.ref)\n\t\t\t: await deps.docker.digest(image.ref);\n\t\tif (run.push) {\n\t\t\tctx.logger.info(` ${image.app.padEnd(12)} ${image.ref}@${digest}`);\n\t\t}\n\t\trun.images[image.app] = {\n\t\t\tref: image.ref,\n\t\t\ttag: image.tag,\n\t\t\t...(digest ? { digest } : {}),\n\t\t};\n\t\tctx.emit({\n\t\t\ttype: 'artifact.built',\n\t\t\tapp: image.app,\n\t\t\timageRef: image.ref,\n\t\t\t...(digest ? { digest } : {}),\n\t\t});\n\t\trun.changes.push({\n\t\t\tkey: `image:${image.app}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: run.mode === 'build' ? 'build' : 'reuse',\n\t\t\tid: digest ?? image.ref,\n\t\t});\n\t}\n}\n\n// ============================================================================\n// release\n// ============================================================================\n\n/**\n * The whole stack up — anything it no longer defines removed — and each\n * app's image recorded in the stage's state.\n */\nexport async function releaseCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack, ref } = run;\n\t// A push starts nothing and records nothing: a stage runs what it pulls.\n\tif (run.push) return;\n\n\tctx.logger.info('\\n🚀 Starting the stack…');\n\tawait deps.docker.up(ref);\n\n\tif (stack.local) {\n\t\t// Caddy's CA is generated on its first start. Copied out so a process —\n\t\t// `verify` among them — can trust it without installing anything.\n\t\tawait deps.docker\n\t\t\t.copyOut(\n\t\t\t\tref,\n\t\t\t\t'caddy',\n\t\t\t\t'/data/caddy/pki/authorities/local/root.crt',\n\t\t\t\tcaFile(run),\n\t\t\t)\n\t\t\t.catch(() => {});\n\t}\n\n\tawait recordImages(ctx, run);\n\n\tfor (const app of stack.apps) {\n\t\tconst image = run.images[app.name];\n\t\tapplied(ctx, run, {\n\t\t\tkey: `service:${app.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t\tid: `${stack.project}/${app.name}`,\n\t\t\tvia: run.previous[app.name] ? 'recorded' : 'created',\n\t\t});\n\t\tctx.emit({\n\t\t\ttype: 'app.deployed',\n\t\t\tapp: app.name,\n\t\t\tapplicationId: `${stack.project}/${app.name}`,\n\t\t\timageRef: image?.ref ?? app.ref,\n\t\t\turl: app.url,\n\t\t});\n\t}\n\n\t// A worker has no URL, so no `app.deployed`: its service, applied, is it.\n\tfor (const worker of stack.workers) {\n\t\tapplied(ctx, run, {\n\t\t\tkey: `service:${worker.name}`,\n\t\t\tresourceType: 'service',\n\t\t\taction: 'ensure',\n\t\t\tid: `${stack.project}/${worker.name}`,\n\t\t\tvia: run.previous[worker.name] ? 'recorded' : 'created',\n\t\t});\n\t}\n\n\tctx.logger.info(`\\n✅ ${stack.project} is running:`);\n\tfor (const app of stack.apps) {\n\t\tctx.logger.info(` ${app.name.padEnd(12)} ${app.url}`);\n\t}\n\tfor (const worker of stack.workers) {\n\t\tctx.logger.info(` ${worker.name.padEnd(12)} worker ${worker.id}`);\n\t}\n\tif (stack.local) {\n\t\tctx.logger.info(\n\t\t\t`\\n🔐 Certificates are from Caddy's local CA: NODE_EXTRA_CA_CERTS=${join(stackDir(ctx.stage), 'caddy-root.crt')}`,\n\t\t);\n\t}\n}\n\n/**\n * Each app's image in the stage's state — the same `images` a Dokploy deploy\n * records: the ref it runs, the tag it was released under, and the digest\n * the tag resolved to.\n */\nasync function recordImages(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): Promise<void> {\n\tconst journal = await DeployJournal.open(ctx.state, ctx.stage, () =>\n\t\tcreateEmptyState(ctx.stage, '', ''),\n\t);\n\tfor (const app of [...run.stack.apps, ...run.stack.workers]) {\n\t\tconst image = run.images[app.app] ?? { ref: app.ref, tag: app.tag };\n\t\trecordRelease(journal.state, app.app, image);\n\t}\n\tjournal.state.identity = ctx.identity.key;\n\tawait journal.save();\n}\n\n// ============================================================================\n// verify\n// ============================================================================\n\n/**\n * Each app asked through Caddy, over HTTPS, the certificate verified: an API\n * at `/health`, a site at `/`. On the local stage the edge is this machine and\n * its certificates are Caddy's internal CA's, so the CA `release` copied out\n * is the one trusted and the request goes to 127.0.0.1.\n */\nexport async function verifyCompose(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n): Promise<void> {\n\tconst { stack } = run;\n\tif (run.push) return;\n\tconst ca = stack.local\n\t\t? await readFile(caFile(run), 'utf-8').catch(() => undefined)\n\t\t: undefined;\n\n\tctx.logger.info('\\n🩺 Checking each app through Caddy…');\n\tconst results = await Promise.all(\n\t\tstack.apps.map((app) =>\n\t\t\tcheckApp(ctx, app, deps, { ca, local: stack.local }),\n\t\t),\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) throw new ComposeAppsUnhealthy(stack.project, down);\n\n\tif (stack.logs) reportLogs(ctx, stack.logs, stack.local);\n}\n\n/**\n * A container's own health check, as Docker reports it: a worker's, which\n * has no route through the edge, and OpenObserve's — by default it has no\n * host there, and served publicly it answers only the addresses it allows,\n * which need not include this one.\n */\nasync function checkContainer(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tdeps: ComposeDeps,\n\tservice: string,\n): Promise<{ app: string; url: string; last: string; healthy: boolean }> {\n\tconst url = `docker:${service}`;\n\tlet last = 'not asked';\n\n\tfor (let attempt = 1; attempt <= deps.healthAttempts; attempt++) {\n\t\tctx.signal.throwIfAborted();\n\t\tconst health = await deps.docker\n\t\t\t.health(run.ref, service)\n\t\t\t.catch((error: unknown) =>\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t);\n\t\tlast = health ?? 'not running';\n\t\tconst healthy = health === 'healthy';\n\t\tctx.emit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp: service,\n\t\t\turl,\n\t\t\thealthy,\n\t\t\tattempt,\n\t\t});\n\t\tif (healthy) {\n\t\t\tctx.logger.info(` ✓ ${service.padEnd(12)} ${url} (${last})`);\n\t\t\treturn { app: service, url, last, healthy };\n\t\t}\n\t\tif (attempt < deps.healthAttempts) {\n\t\t\tawait new Promise((resolve) =>\n\t\t\t\tsetTimeout(resolve, deps.healthIntervalMs),\n\t\t\t);\n\t\t}\n\t}\n\n\tctx.logger.warn(` ✗ ${service.padEnd(12)} ${url} (${last})`);\n\treturn { app: service, url, last, healthy: false };\n}\n\n/** How to open the logs, printed — and as an event, for a headless caller. */\nfunction reportLogs(\n\tctx: ComposeContext,\n\tlogs: StackLogs,\n\tlocal: boolean,\n): void {\n\tconst lines = logsAccess(logs, {\n\t\tstage: ctx.stage,\n\t\tlocal,\n\t\tuser: currentUser(),\n\t\thostname: hostname(),\n\t});\n\tctx.logger.info(`\\n${lines.join('\\n')}`);\n\tctx.emit({\n\t\ttype: 'logs.ready',\n\t\tservice: LOGS_SERVICE,\n\t\taccess: logs.public ? 'public' : 'tunnel',\n\t\turl: logs.url,\n\t\t...(logs.public ? { allow: [...logs.public.allow] } : { port: logs.port }),\n\t\temail: logs.email,\n\t});\n}\n\n/** This machine's user — a guess at who would SSH in. */\nfunction currentUser(): string {\n\ttry {\n\t\treturn userInfo().username;\n\t} catch {\n\t\treturn process.env.USER ?? 'user';\n\t}\n}\n\nasync function checkApp(\n\tctx: ComposeContext,\n\tapp: StackApp,\n\tdeps: ComposeDeps,\n\toptions: { ca: string | undefined; local: boolean },\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.local ? { connectTo: '127.0.0.1' } : {}),\n\t\t\t\ttimeoutMs: 10_000,\n\t\t\t\tsignal: ctx.signal,\n\t\t\t});\n\t\t\tlast = `HTTP ${status}`;\n\t\t} catch (error) {\n\t\t\tlast = error instanceof Error ? error.message : String(error);\n\t\t}\n\n\t\tconst healthy = status !== undefined && isHealthy(status);\n\t\tctx.emit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp: app.name,\n\t\t\turl,\n\t\t\thealthy,\n\t\t\t...(status !== undefined ? { status } : {}),\n\t\t\tattempt,\n\t\t});\n\t\tif (healthy) {\n\t\t\tctx.logger.info(` ✓ ${app.name.padEnd(12)} ${url} (${last})`);\n\t\t\treturn { app: app.name, url, last, healthy };\n\t\t}\n\t\tif (attempt < deps.healthAttempts) {\n\t\t\tawait new Promise((resolve) =>\n\t\t\t\tsetTimeout(resolve, deps.healthIntervalMs),\n\t\t\t);\n\t\t}\n\t}\n\n\tctx.logger.warn(` ✗ ${app.name.padEnd(12)} ${url} (${last})`);\n\treturn { app: app.name, url, last, healthy: false };\n}\n\n// ============================================================================\n// result\n// ============================================================================\n\nexport function composeResult(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n): DeployResult {\n\tconst apps = [\n\t\t...run.stack.apps.map((app) => {\n\t\t\tconst image = run.images[app.name];\n\t\t\treturn {\n\t\t\t\tappName: app.name,\n\t\t\t\ttype: app.kind === 'site' ? ('web' as const) : ('backend' as const),\n\t\t\t\tsuccess: !ctx.dryRun,\n\t\t\t\tapplicationId: `${run.stack.project}/${app.name}`,\n\t\t\t\timageRef: image?.ref ?? app.ref,\n\t\t\t\t...(image?.digest ? { digest: image.digest } : {}),\n\t\t\t\turl: app.url,\n\t\t\t};\n\t\t}),\n\t\t...run.stack.workers.map((worker) => {\n\t\t\tconst image = run.images[worker.name];\n\t\t\treturn {\n\t\t\t\tappName: worker.name,\n\t\t\t\ttype: 'backend' as const,\n\t\t\t\tsuccess: !ctx.dryRun,\n\t\t\t\tapplicationId: `${run.stack.project}/${worker.name}`,\n\t\t\t\timageRef: image?.ref ?? worker.ref,\n\t\t\t\t...(image?.digest ? { digest: image.digest } : {}),\n\t\t\t};\n\t\t}),\n\t];\n\treturn {\n\t\tapps,\n\t\tprojectId: run.stack.project,\n\t\tsuccessCount: ctx.dryRun ? 0 : apps.length,\n\t\tfailedCount: 0,\n\t\tstage: ctx.stage,\n\t\tidentity: ctx.identity.key,\n\t\ttag: ctx.tag,\n\t\tdryRun: ctx.dryRun,\n\t\tenvironmentId: '',\n\t\tskipped: [...ctx.skipped],\n\t\turls: Object.fromEntries(run.stack.apps.map((app) => [app.name, app.url])),\n\t\tchanges: run.changes,\n\t};\n}\n\n// ============================================================================\n// Files\n// ============================================================================\n\nfunction caFile(run: ComposeRun): string {\n\treturn join(run.dir, 'caddy-root.crt');\n}\n\nfunction applied(\n\tctx: ComposeContext,\n\trun: ComposeRun,\n\tchange: ResourceChange & {\n\t\tid: string;\n\t\tvia: 'recorded' | 'resumed' | 'found' | 'created';\n\t},\n): void {\n\tconst { via, ...rest } = change;\n\trun.changes.push(rest);\n\tctx.emit({ type: 'resource.applied', ...rest, via });\n}\n\n/** Write the stack's files: owner-only, since the env files hold secrets. */\nasync function writeStack(\n\troot: string,\n\tdir: string,\n\tstack: ComposeStack,\n): Promise<string[]> {\n\tawait mkdir(dir, { recursive: true, mode: 0o700 });\n\tawait chmod(dir, 0o700);\n\n\tconst files: string[] = [];\n\tconst write = async (path: string, content: string, mode = 0o644) => {\n\t\tawait mkdir(dirname(path), { recursive: true });\n\t\tawait writeFile(path, content, { mode });\n\t\tawait chmod(path, mode);\n\t\tfiles.push(path);\n\t};\n\n\tawait write(join(dir, 'docker-compose.yml'), composeYaml(stack));\n\tawait write(join(dir, 'Caddyfile'), stack.caddyfile);\n\tfor (const app of [...stack.apps, ...stack.workers]) {\n\t\tif (app.env)\n\t\t\tawait write(join(dir, `${app.name}.env`), envFile(app.env), 0o600);\n\t}\n\t// A stack that only builds reads no env file, so none is written.\n\tif (stack.logs && stack.compose.services[LOGS_SERVICE]?.env_file) {\n\t\tawait write(\n\t\t\tjoin(dir, `${LOGS_SERVICE}.env`),\n\t\t\tenvFile(stack.logs.env),\n\t\t\t0o600,\n\t\t);\n\t}\n\tif (stack.redis && stack.compose.services[REDIS_SERVICE]?.env_file) {\n\t\tawait write(\n\t\t\tjoin(dir, `${REDIS_SERVICE}.env`),\n\t\t\tenvFile(stack.redis.env),\n\t\t\t0o600,\n\t\t);\n\t}\n\t// Images no longer embed a stage's credentials. The ciphertexts an older\n\t// gkm left beside the compose file for them to embed are removed.\n\tfor (const entry of await readdir(dir)) {\n\t\tif (entry.endsWith('.credentials')) await rm(join(dir, entry));\n\t}\n\tfor (const [path, content] of Object.entries(stack.dockerfiles)) {\n\t\tawait write(join(root, path), content);\n\t}\n\n\t// The build context is the build root, and the env files are under it:\n\t// its ignore file is what keeps a stage's secrets out of every image's\n\t// context.\n\tawait ensureDockerignore(findBuildRoot(root));\n\n\treturn files;\n}\n\nfunction composeYaml(stack: ComposeStack): string {\n\tconst stage = ` --stage ${stack.stage}`;\n\treturn `# Generated by gkm compose from the construct manifest — do not edit.\n# The ${stack.stage} stage's APIs and sites behind one Caddy, and its workers.\n# Each backend and worker reads exactly the keys in its own env file beside\n# this one.\n#\n# gkm compose${stage} start or update it\n# gkm compose${stage} --down stop it\n${stringify(stack.compose, { lineWidth: 0, aliasDuplicateObjects: false })}`;\n}\n\nfunction printPlan(ctx: ComposeContext, run: ComposeRun): void {\n\tconst { stack, mode, files } = run;\n\tctx.logger.info(`\\n🧱 ${stack.project} — stage ${stack.stage}`);\n\tfor (const app of stack.apps) {\n\t\tctx.logger.info(\n\t\t\t` ${app.name.padEnd(12)} ${app.url.padEnd(40)} ${mode} ${app.ref}`,\n\t\t);\n\t}\n\tfor (const worker of stack.workers) {\n\t\tctx.logger.info(\n\t\t\t` ${worker.name.padEnd(12)} ${`worker ${worker.id} (no route)`.padEnd(40)} ${mode} ${worker.ref}`,\n\t\t);\n\t}\n\tif (stack.infra.length > 0) {\n\t\tctx.logger.info(` infrastructure: ${stack.infra.join(', ')}`);\n\t}\n\tctx.logger.info(\n\t\t`\\n📝 Wrote ${files.length} file(s) under ${stackDir(stack.stage)}/`,\n\t);\n}\n","/**\n * The built-in `compose` target: a stage as one Docker Compose stack behind\n * Caddy, on the machine that runs the deploy.\n *\n * ```bash\n * gkm deploy --target compose --stage production --tag v1.4.0 # what CI pushed\n * gkm deploy --target compose --stage production # built from here\n * gkm deploy --target compose --stage development # the local stage\n * ```\n *\n * - `validate`: the stack (`composeStack`, pure) and, for a tag, every image\n * looked up in the registry — `ImageTagNotFound` before anything changes\n * - `plan`: the stack's files and what a run would create or reuse\n * - `provision`: generated secrets kept, files written, infrastructure up,\n * databases, roles, grants and migrations\n * - `build`: each backend bundled on the host and every image built — or, for\n * a tag, pulled\n * - `release`: `up --wait --remove-orphans`, and each app's image, tag and\n * digest in the stage's state\n * - `verify`: each app asked through Caddy over HTTPS\n *\n * With `push` (`gkm compose --build --push`), run with `buildOnly`, it builds\n * every image and pushes it to `deploy.registry`, and does nothing else.\n *\n * `gkm compose` is this target with a few more switches (`--build`, `--pull`,\n * `--down`), run through the same `deploy()`.\n */\n\nimport { defineTarget } from '../define';\nimport type { DeployTarget } from '../types';\nimport {\n\tbuildCompose,\n\ttype ComposeDeps,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tcomposeResult,\n\tdefaultDeps,\n\tplanCompose,\n\tprovisionCompose,\n\treleaseCompose,\n\tvalidateCompose,\n\tverifyCompose,\n} from './phases';\n\nexport {\n\tComposeAppsUnhealthy,\n\ttype HealthProbe,\n\ttype HealthRequest,\n\tHealthRequestTimedOut,\n} from './health';\nexport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\ttype ComposeRunOptions,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n\tstackOverrideFile,\n} from './phases';\n\nexport interface ComposeTargetOptions\n\textends Partial<ComposeDeps>,\n\t\tComposeRunOptions {\n\t/** Handed the finished run — `gkm compose` prints and returns from it. */\n\treport?: (run: ComposeRun) => void;\n}\n\n/** The compose target, with its Docker, bundler and probe as given. */\nexport function composeTarget(\n\toptions: ComposeTargetOptions = {},\n): DeployTarget<undefined, ComposeRun> {\n\tconst { mode, push, pin, report, ...given } = options;\n\tconst deps: ComposeDeps = { ...defaultDeps, ...given };\n\n\treturn defineTarget<undefined, ComposeRun>({\n\t\tname: 'compose',\n\t\truntime: 'server',\n\t\tcapabilities: {\n\t\t\trollback: false,\n\t\t\tmigrations: 'target',\n\t\t\timages: true,\n\t\t\t// The stack runs where the deploy does, so the local stage is one\n\t\t\t// it can run — the `gkm dev` hostnames, behind Caddy's own CA.\n\t\t\tlocalStage: true,\n\t\t},\n\t\t// Images are pulled with this machine's own `docker login`.\n\t\tcredentials: [],\n\t\t// Built from the checkout, an image is named after its commit.\n\t\ttag: ({ cwd }) => deps.revision(cwd),\n\t\tvalidate: (ctx) =>\n\t\t\tvalidateCompose(ctx, deps, {\n\t\t\t\t...(mode ? { mode } : {}),\n\t\t\t\t...(push ? { push } : {}),\n\t\t\t\t...(pin ? { pin } : {}),\n\t\t\t}),\n\t\tplan: (ctx, run) => planCompose(ctx, run),\n\t\tprovision: (ctx, run) => provisionCompose(ctx, run, deps),\n\t\tbuild: (ctx, run) => buildCompose(ctx, run, deps),\n\t\trelease: (ctx, run) => releaseCompose(ctx, run, deps),\n\t\tverify: (ctx, run) => verifyCompose(ctx, run, deps),\n\t\tresult: (ctx, run) => {\n\t\t\treport?.(run);\n\t\t\treturn composeResult(ctx, run);\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAM,QAAsE;CAC3E,SAAS;CACT,QAAQ;EAAC;EAAU;EAAG;CAAC;CACvB,QAAQ;AACT;;AAGA,SAAS,WAAW,OAAiB,KAAqC;CACzE,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;;AAkDA,MAAM,iBAAiB;;AAGvB,IAAa,qBAAb,cAAwC,MAAM;CAEnC;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,cAAuC,MAAM;CAElC;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,YAAY,KACuD;CACnE,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,QAAQ,MAAM,SAAS,CAAC,GAAG,IAAI,GAAG;GACvC,OAAO;IAAC;IAAU;IAAQ;GAAM;GAChC,OAAO;EACR,CAAC;EACD,IAAI,SAAS;EACb,IAAI,SAAS;EACb,MAAM,OAAO,GAAG,SAAS,UAAkB;GAC1C,UAAU,MAAM,SAAS;EAC1B,CAAC;EACD,MAAM,OAAO,GAAG,SAAS,UAAkB;GAC1C,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,MAAM,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,MAAM,IACL,UACA,QAAQ,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,GACpC,WAAW,KAAK,CACjB;CACD;CAEA,MAAM,GAAG,OAAO,UAAU;EACzB,MAAM,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,MAAM,IAAI,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,GAAG,WAAW,KAAK,CAAC;CAChE;CAEA,MAAM,KAAK,OAAO,SAAS,QAAQ;EAClC,MAAM,SAAS,MAAM,UACpB,UACA,QAAQ,OAAO;GAAC;GAAQ;GAAS,OAAO,MAAM;EAAC,CAAC,GAChD;GAAE,KAAK,MAAM;GAAK,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAAG,CACrE;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,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU,CAChD,GAAG,QAAQ,OAAO;GAAC;GAAM;GAAY;GAAe;EAAO,CAAC,CAC7D,CAAC;EACD,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,MAAM,MAAM,QAAQ,EAAE,GAAG,EAAE,WAAW,KAAK,CAAC;EAC5C,MAAM,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,MAAM,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,KAAK;EACjB,MAAM,EAAE,MAAM,WAAW,MAAM,QAAQ,UAAU;GAChD;GACA;GACA;GACA;EACD,CAAC;EACD,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;AACD;;;;;;;;;;;AChTA,SAAgB,QAAQ,KAAa,OAAuB;CAC3D,OAAO,GAAG,IAAI,GAAG;AAClB;;AAGA,IAAa,mBAAb,cAAsC,MAAM;CAEjC;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,cAAyC,MAAM;CAEpC;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,cAAsC,MAAM;CAGjC;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,cAAwC,MAAM;CAEnC;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,cAAyC,MAAM;CAEpC;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,cAAyC,MAAM;CAEpC;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;;;;;;;;;;;;;;;;;;;;;;;;;ACnMA,MAAa,oBAAoB;;AAGjC,MAAa,eAAe;;AAG5B,MAAa,WAAW;;AAGxB,MAAa,iBAAiB;AAC9B,MAAa,oBAAoB;;AA8BjC,IAAa,uBAAb,cAA0C,MAAM;CAErC;CACA;CAFV,YACC,OACA,MACC;EACD,MACC,cAAc,MAAM,SAAS,KAAK,KAAK,IAAI,EAAE,wPAIb,KAAK,KAAK,IAAI,EAAE,+DAEjD;EAVS,KAAA,QAAA;EACA,KAAA,OAAA;EAUT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,mBAAb,cAAsC,MAAM;CACtB;CAArB,YAAY,OAAwB;EACnC,MACC,cAAc,MAAM,SAAS,kBAAkB,iLAG3B,kBAAkB,eAAe,MAAM,qCAE5D;EAPoB,KAAA,QAAA;EAQpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CACzB;CAArB,YAAY,OAAwB;EACnC,MACC,cAAc,MAAM,gCAAgC,kBAAkB,2CAC1B,MAAM,sEAE9B,kBAAkB,eAAe,OACtD;EANoB,KAAA,QAAA;EAOpB,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,qBAAqB,UAA2B;CAC/D,OACC,SAAS,UAAU,KACnB,SAAS,UAAU,OACnB,QAAQ,KAAK,QAAQ,KACrB,QAAQ,KAAK,QAAQ,KACrB,KAAK,KAAK,QAAQ,KAClB,eAAe,KAAK,QAAQ;AAE9B;;;;;AAMA,SAAgB,uBAA+B;CAC9C,OAAO,GAAG,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE;AACjD;;;;;;AAOA,SAAgB,iBAAiB,SAG/B;CACD,IAAI,QAAQ,SAAA,0BAA6B,OAAO;EAAE;EAAS,WAAW,CAAC;CAAE;CACzE,OAAO;EACN,SAAS;GACR,GAAG;GACH,QAAQ;IACP,GAAG,QAAQ;KACV,oBAAoB,qBAAqB;GAC3C;GACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC;EACA,WAAW,CAAC,iBAAiB;CAC9B;AACD;;;;;;;;AASA,SAAgB,YAAY,OAAe,UAA0B;CAEpE,OAAO,yBADO,OAAO,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC,CAAC,SAAS,QACvB;AACrC;;AAGA,SAAgB,UAAU,SAUZ;CACb,MAAM,EAAE,QAAQ,OAAO,OAAO,WAAW;CAEzC,MAAM,cAAc,OAAO,KAAK,MAAM,CAAC,CAAC,OAAO,iBAAiB,CAAC,CAAC,KAAK;CACvE,IAAI,YAAY,SAAS,GACxB,MAAM,IAAI,qBAAqB,OAAO,WAAW;CAGlD,IAAI,CAAC,SAAS,CAAC,QAAQ,QAAQ,MAAM,IAAI,iBAAiB,KAAK;CAE/D,MAAM,QACL,OAAA,0BACC,QAAA,wBAA2B,SAAS,QAAQ;CAC9C,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,OAAO,CAAC,OAAO,MAAM,IAAI,oBAAoB,KAAK;CACvD,MAAM,WAAW,OAAA;CACjB,IAAI,CAAC,qBAAqB,QAAQ,GAAG,MAAM,IAAI,iBAAiB,KAAK;CAErE,MAAM,OAAO,OAAO,SACjB,QACC,QAAQ,QAAQ,QAAQ,cACxB,QAAQ,QAAQ,WACjB,KAAA;CACH,MAAM,MAAM,OACT,WAAW,OAAO,SAAS,QAAQ,UAAU,MAAM,IAAI,QAAQ,UAAU,OACzE,oBAAoB,OAAO;CAE9B,OAAO;EACN,GAAG;EACH;EACA;EACA,qBAAqB,QAAQ,GAAG;EAChC;EACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,KAAK;IACH,iBAAiB;IACjB,oBAAoB;GACrB,aAAa;GAEb,gCAAgC,OAAO,OAAO,aAAa;GAE3D,cAAc;EACf;EACA,QAAQ;GACP,6BAA6B,UAAU,aAAa,GAAG,UAAU,OAAO;GACxE,4BAA4B,YAAY,OAAO,QAAQ;EACxD;CACD;AACD;;;;;;AAOA,SAAgB,YAAY,MAA+B;CAC1D,OAAO;EACN,OAAO;EACP,SAAS;EACT,UAAU,CAAC;GAAE,MAAM,KAAK,aAAa;GAAO,QAAQ;EAAM,CAAC;EAC3D,SAAS,CAAC,wBAAwB;EAGlC,GAAI,KAAK,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,aAAa,KAAK,KAAK,GAAG,WAAW,EAAE;EACxE,aAAa;GACZ,MAAM;IAAC;IAAO;IAAgB;IAAQ;GAAQ;GAC9C,UAAU;GACV,SAAS;GACT,SAAS;GACT,cAAc;EACf;CACD;AACD;;AAYA,SAAgB,WAAW,MAAiB,KAAkC;CAC7E,MAAM,QAAQ,UAAU,KAAK,MAAM,cAClC,IAAI,SAAS,CAAC,KAAK,sBAChB,KAAK,WACL,4BAA4B,IAAI,MAAM,cAAc;CAGxD,IAAI,KAAK,QACR,OAAO,CACN,0BAA0B,KAAK,IAAI,KAAK,MAAM,IAC9C,0BAA0B,KAAK,OAAO,MAAM,KAAK,IAAI,EAAE,+BACxD;CAGD,OAAO;EACN,sCAAsC,KAAK,KAAK;EAEhD,GAAI,IAAI,QACL,CACA,+CAA+C,KAAK,KAAK,yBAC1D,IACC,CAAC;EACJ,kBAAkB,KAAK,KAAK,aAAa,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,SAAS;EAC/E,mCAAmC,KAAK,KAAK,KAAK,MAAM;EACxD;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;ACpQA,MAAa,cAA4B;;AAGzC,MAAa,gBAAgB;;AAG7B,MAAa,aAAa;;AAG1B,MAAa,cAAc,eAAe;;;;;;;AAQ1C,MAAa,kBAAkB;;AAG/B,MAAa,qBAAqB;;AAMlC,MAAM,kBAAkB;;AAGxB,IAAa,uBAAb,cAA0C,MAAM;CAC1B;CAArB,YAAY,OAAwB;EACnC,MACC,cAAc,MAAM,sCAChB,mBAAmB,2CACnB,MAAM,sEACU,mBAAmB,eAAe,OACvD;EANoB,KAAA,QAAA;EAOpB,KAAK,OAAO;CACb;AACD;;;;;AAmBA,SAAgB,UACf,UACA,QACU;CACV,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC,MAC7B,gBACA,aAAa,SAAS,YACrB,YAAY,YAAY,CAAC,EAAA,CAAG,MAAM,QAAQ,OAAO,SAAS,KAAA,CAAS,CACtE;AACD;;AAGA,SAAgB,wBAAgC;CAC/C,OAAO,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW;AAC5C;;;;;;AAOA,SAAgB,kBAAkB,SAGhC;CACD,IAAI,QAAQ,SAAA,mBAA8B,OAAO;EAAE;EAAS,WAAW,CAAC;CAAE;CAC1E,OAAO;EACN,SAAS;GACR,GAAG;GACH,QAAQ;IACP,GAAG,QAAQ;KACV,qBAAqB,sBAAsB;GAC7C;GACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC;EACA,WAAW,CAAC,kBAAkB;CAC/B;AACD;;;;;;;AAQA,SAAgB,WAAW,SAKA;CAC1B,MAAM,EAAE,MAAM,OAAO,OAAO,WAAW;CAEvC,MAAM,SAAS,KAAK,UAClB,QAAQ,MAAM,EAAE,SAAS,WAAW,OAAO,EAAE,YAAY,KAAA,CAAS,CAAC,CACnE,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;CACzC,IAAI,OAAO,WAAW,GAAG,OAAO,KAAA;CAEhC,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,OAAO,CAAC,OAAO,MAAM,IAAI,qBAAqB,KAAK;CACxD,MAAM,WAAW,OAAA;CACjB,MAAM,OAAO,mBAAmB,QAAQ;CAExC,OAAO;EACN;EACA,qBAAqB,QAAQ,GAAG;EAChC,MAAM,OAAO,YACZ,OAAO,KAAK,OAAO,UAAU,CAC5B,MAAM,QACN,YAAY,KAAK,GAAG,cAAc,GAAG,WAAW,GAAG,OACpD,CAAC,CACF;EACA,KAAK;IAGH,qBAAqB;GAGtB,eAAe;EAChB;EACA,WAAW,KAAK,IAAI,iBAAiB,OAAO,MAAM;CACnD;AACD;;;;;;;;;;AAWA,SAAgB,aAAa,OAAiC;CAC7D,MAAM,QAAQ;EACb,oBAAoB,mBAAmB;EACvC,eAAe;EACf;EACA;EACA,GAAI,MAAM,YAAY,kBACnB,CAAC,eAAe,MAAM,WAAW,IACjC,CAAC;CACL;CACA,OAAO;EACN,OAAO;EACP,SAAS;EACT,SAAS;GACR;GACA;GACA,0CAA0C,MAAM,KAAK,GAAG;EACzD;EACA,UAAU,CAAC;GAAE,MAAM,KAAK,cAAc;GAAO,QAAQ;EAAM,CAAC;EAC5D,SAAS,CAAC,kBAAkB;EAC5B,aAAa;GAGZ,MAAM,CAAC,aAAa,+BAA+B;GACnD,UAAU;GACV,SAAS;GACT,SAAS;EACV;CACD;AACD;;;;AC5KA,SAAgB,cACf,OACA,SACS;CACT,MAAM,SAAS,QAAQ,QACpB;;;;;KAMA,QAAQ,QACP;SACI,QAAQ,MAAM;KAElB;CAEJ,MAAM,SAAS,MAAM,KACnB,EAAE,MAAM,UAAU,SAAS,YAAY,WAAW,KAAK,IACvD,QAAQ,QACL;;IAGA,KAEH,QACG;;;yBAGmB,MAAM,KAAK,GAAG,EAAE;;IAGnC,KAEH,UACG;;;iBAGW,SAAS;YACd,QAAQ;;MAGd;;;iBAGW,SAAS;;;;IAKvB;EAEF;CAGA,OAAO,GAAG,SAAS,SAAS,GAAG,OAAO,QAAQ,KAAK,OAAO,KAAK,MAAM,EAAE;AACxE;AAEA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;ACvBf,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;;;;;;;;;;;;AAaA,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;;AAuKA,IAAa,qBAAb,cAAwC,MAAM;CAEnC;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,cAAsC,MAAM;CACtB;CAArB,YAAY,OAAwB;EACnC,MACC,cAAc,MAAM,uHACgD,MAAM,wDAE3E;EALoB,KAAA,QAAA;EAMpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,mBAAb,cAAsC,MAAM;CACtB;CAArB,YAAY,MAAuB;EAClC,MACC,GAAG,KAAK,yIAGT;EALoB,KAAA,OAAA;EAMpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,oBAAb,cAAuC,MAAM;CAElC;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;;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;CAMlC,MAAM,OAAO,QAAQ,UAAU,OAAO,eAAe,QAAQ,GAAG;EAC/D,YAAY,UAAU,OAAO;EAC7B,QAAQ,eAAe;EACvB,OAAO;EAEP,MAAM;CACP,CAAC;CACD,MAAM,OAAO,IAAI,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CAEzD,MAAM,OAAO,QAAQ,KAAA,IAAY,MAAM,SAAS;CAChD,IAAI,CAAC,SAAS,CAAC,MAAM,MAAM,IAAI,iBAAiB,KAAK;CACrD,MAAM,aAAa;EAClB,QAAQ,QACL,cACA,kBAAkB,UAAU,MAAM,MAAM,UAAU,IAAI;EACzD,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACxB;CAEA,MAAM,OAAO,UAAU,WAAW,UAAU,MAAM;EACjD;EACA;EACA;EACA;EACA,QAAQ,MAAM;CACf,CAAC;CACD,MAAM,UAAU,aACf,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,IAAI,WAAW,SAAS,IAAI,MAAM,GAAG,QAAQ;GACpD,OAAO,IAAI,WAAW,SAAS,IAAI,UAAU,GAAG,QAAQ;EACzD;EACA,IAAI,SAAS,SAAS,gBACrB,OAAO,IAAI,WAAW,SAAS,IAAI,aAAa,GAAG,QAAQ;CAE7D;CAIA,MAAM,wBAAQ,IAAI,IAAsB;CACxC,KAAK,MAAM,OAAO,MAAM;EACvB,MAAM,OAAO,SAAS,IAAI;EAC1B,MAAM,IACL,IAAI,MACJ,MAAM,SAAS,SACZ,OAAO,OAAO,aAAa,MAAM,QAAQ,CAAC,IAC1C,CAAC,GAAI,WAAW,UAAU,IAAI,MAAM,MAAM,SAAS,KAAK,CAAC,CAAE,CAC/D;CACD;CACA,KAAK,MAAM,UAAU,SACpB,MAAM,IAAI,OAAO,MAAM,CACtB,GAAI,cAAc,UAAU,OAAO,IAAI,MAAM,SAAS,KAAK,CAAC,CAC7D,CAAC;CAEF,MAAM,SAAS,UAAU,QAAQ,UAAU;CAI3C,MAAM,aAAa,YAAY,UAAU,QAAQ,SAAS,IAAI;CAC9D,MAAM,OAAO,aACV,UAAU;EACV,QAAQ;EACR;EACA;EACA,SAAS,UAAU;EACnB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B;EACA;CACD,CAAC,IACA,KAAA;CAKH,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,IACC,uBAAuB;EACvB;EACA,cAAc,oBAAoB,MAAM,OAAO,MAAM;EACrD,UAAU;EACV,OAAO,MAAM,oBAAoB,CAAC;EAClC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC5B,CAAC;CAIH,MAAM,QAAQ,WAAW;EAAE;EAAM;EAAO;EAAO;CAAO,CAAC;CAEvD,MAAM,QAAQ,CACb,GAAG,KAAK,WACN,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC,CAC1B,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,OAAO,CAAC,YAAY,IAAI,CAAC,CAC9B,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,MACC,OAAO,sBACN,QAAQ,cAAc,GAAG,UAAU,KAAK;GAC1C,UACC,OAAO,0BACN,QACE,cACA,kBAAkB,UAAU,MAAM,MAAM,SAAS,IAAI;GACzD;GACA,UAAU,eAAe,IAAI,CAAC,CAAC,QAAQ,MACtC,QAAQ,SAAS,EAAE,MAAM,CAC1B;EACD;CACD,EAAA,CAAG,IACF,KAAA;CAKH,MAAM,aAAa;EAClB,SAAS,UAAU;EACnB,QAAQ,WAAW;EACnB,GAAI,WAAW,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;EAEnD,GAAI,CAAC,SAAS,SAAS,EAAE,UAAU,WAAW,SAAS,IAAI,CAAC;CAC7D;CACA,MAAM,UAAU,WAAW,MAAM;EAChC,GAAG;EACH,WAAW,OAAO,YAAY,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;CACnE,CAAC;CACD,MAAM,SAAS,WAAW,MAAM;EAC/B,GAAG;EACH,WAAW,OAAO,YACjB,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,UAAU,IAAI,KAAK,GAAG,IAAI,MAAM,CAAC,CAC7D;CACD,CAAC;CAID,MAAM,8BAAc,IAAI,IAA6C;CACrE,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,OAAO,QAAQ,UAAU,UAAU,IAAI;OACjC;GACN,IAAI,CAAC,QAAQ,MAAM,IAAI,iBAAiB,KAAK;GAC7C,OAAO,GAAG,SAAS,aAAa,OAAO,SAAS,EAAE,EAAE,GAAG;EACxD;EACA,YAAY,IAAI,SAAS,IAAI;GAC5B,KAAK,WAAW,OAAO,SAAS,UAAU,MAAM,IAAI,UAAU;GAC9D,MAAM;IACL;IACA,UAAU;IACV,SAAS,IAAI,OAAO,KAAK;GAC1B;EACD,CAAC;CACF;CAGD,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;EAIxB,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,SAAS,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;;CAGA,MAAM,aACL,KACA,SAC4B;EAC5B,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;GACnC,MAAM,QAAQ,OAAO,IAAI,GAAG,KAAK,aAAa,KAAK,IAAI;GAEvD,IAAI,CAAC,SAAS,OAAO,SAAS,WAAW,IAAI,SAAS,YAAY,GACjE;GACD,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,OAA+B,CAAC;GACtC,KAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAClC,aAAa,MAAM,QAAQ,CAC5B,GAAG;IACF,MAAM,QAAQ,SAAS,KAAK,QAAQ,OAAO,IAAI,MAAM,CAAC;IACtD,IAAI,UAAU,KAAA,GAAW,KAAK,OAAO;GACtC;GACA,IAAI,IAAI,SAAS,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,MAAM,OAAO;GAChE;EACD;EAGA,IAAI,MAAM,WAAW;EAErB,MAAM,OAAO,WAAW,UAAU,IAAI,MAAM,MAAM,SAAS,qBAAK,IAAI,IAAI;EACxE,MAAM,SAAS,UAAU,KAAK,IAAI;EAMlC,MAAM,UAAU,WAAW,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,KAAK,GAAG,OAAO,MAAM;GACxD,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,GAAG;GACH,GAAG,QAAQ;IAAE,GAAG;IAAQ,GAAG,MAAM;GAAO,GAAG,IAAI,IAAI;GACnD,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,KAAK,MAAM,UAAU,MAAM,YAAY,CAAC,IAAI,SAAS;EACpD,MAAM,OACL,cAAc,UAAU,OAAO,IAAI,MAAM,SAAS,qBAAK,IAAI,IAAI;EAChE,OAAO,MAAM;GACZ,GAAG,UACF;IAAE,MAAM,OAAO;IAAM,IAAI,OAAO;IAAI,MAAM;GAAW,GACrD,IACD;GACA,GAAG,QAAQ;IAAE,GAAG;IAAQ,GAAG,MAAM;GAAO,GAAG,OAAO,IAAI;GACtD,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;CAEA,MAAM,SAAS,MAAM,UAAU,cAAc,UAAU,IAAI;CAC3D,MAAM,UAAU,UAAU;EACzB;EACA;EACA;EACA;EACA;EACA,QAAQ,WAAW;EACnB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB;EACA;EACA,YAAY,KAAK,UAAU,MAAM,SAAS,KAAK,CAAC;EAChD,WAAW,OAAO;EAClB,eAAe,UAAU;EACzB,UAAU,CAAC,MAAM;CAClB,CAAC;CAED,MAAM,YAAY,cACjB;EACC,GAAG,KAAK,KAAK,SAAS;GACrB,MAAM,IAAI;GACV,UAAU,GAAG,IAAI,KAAK,GAAG,IAAI;EAC9B,EAAE;EACF,GAAG,CAAC,GAAG,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,IAAI;EACnD,GAAI,MAAM,QAAQ,KAAK,SACpB,CACA;GACC,MAAM,KAAK;GACX,UAAU,GAAG,aAAa,GAAG;GAC7B,OAAO,KAAK,OAAO;EACpB,CACD,IACC,CAAC;CACL,GACA,EAAE,MAAM,CACT;CAEA,MAAM,cAAsC,CAAC;CAC7C,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,CAAC,IAAI,OAAO;EAIhB,YAAY,IAAI,MAAM,cAAc,cACnC,IAAI,MACJ,UAAU,KAAK,IAAI,OACnB;GACC;GACA,eAAe,UAAU;GACzB,MAAM,UAAU;GAChB;GACA,OAAO;EACR,CACD;CACD;CACA,KAAK,MAAM,UAAU,SAAS;EAC7B,IAAI,CAAC,OAAO,OAAO;EACnB,YAAY,OAAO,MAAM,cAAc,iBACtC;GAAE,IAAI,OAAO;GAAI,MAAM,OAAO;GAAM,KAAK,OAAO;EAAK,GACrD,UAAU,KAAK,OAAO,OACtB;GAAE;GAAQ,eAAe,UAAU;GAAM,OAAO;EAAY,CAC7D;CACD;CAEA,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,aAAa,QAAQ,CAAC,IAAI,gBAAgB,QAAQ;EAClD,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC1B;AACD;;;;;;AAOA,SAAS,oBACR,MACA,OACA,QACuB;CACvB,MAAM,OAAO,IAAI,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CACzD,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,OAAO,IAAY,QAAiB;EACzC,MAAM,MAAM,QAAQ,IAAI,EAAE,qBAAK,IAAI,IAAY;EAC/C,IAAI,KAAK,IAAI,IAAI,GAAG;EACpB,QAAQ,IAAI,IAAI,GAAG;CACpB;CAEA,KAAK,MAAM,CAAC,KAAK,SAAS,OACzB,KAAK,MAAM,OAAO,MAAM;EACvB,MAAM,QAAQ,OAAO,IAAI,GAAG;EAC5B,IAAI,CAAC,SAAS,CAAC,cAAc,MAAM,OAAO;EAE1C,IAAI,MAAM,SAAS,WAAW,IAAI,SAAS,YAAY,GAAG;EAC1D,IAAI,MAAM,IAAI,GAAG;EACjB,IAAI,MAAM,SAAS,iBAAiB,MAAM,IAAI,IAAI,MAAM,EAAE;CAC3D;CAGD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,UAAU;EAC3C,MAAM,WAAW,KAAK,IAAI,EAAE;EAC5B,MAAM,OAAO,YAAY,cAAc,SAAS;EAChD,IAAI,CAAC,YAAY,CAAC,MAAM,OAAO,CAAC;EAChC,OAAO,CACN;GACC;GACA;GACA,GAAI,SAAS,KAAK,EAAE,IAAI,SAAS,GAAG,IAAI,CAAC;GACzC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK;EACtB,CACD;CACD,CAAC;AACF;;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,OAAO,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,MAAM,iBACX,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,MAAM;EACN,KAAK,iBACJ,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,OAAO,QAAQ,UAAU,UAAU,IAAI;CAE1D,OAAO,YACN,MACA,KACA,QAAQ,OACR,UAAU,QAAQ,SAClB,kBAAkB,MAAM,KAAK,UAAU,IAAI,CAC5C;AACD;;AAGA,SAAS,UAAU,SAiBL;CACb,MAAM,EAAE,SAAS,MAAM,SAAS;CAEhC,MAAM,QAAQ,QAAQ,MAAM,QAAQ,SAAS,SAAS,YAAY;CAKlE,MAAM,UAAU,WACf;EAAE,GAAG;EAAM,YAAY,CAAC,GAAG,KAAK;CAAE,GAClC;EACC;EACA,OAAO,OAAO,YACb,SAAS,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAClD;CACD,CACD;CAEA,MAAM,WAAyC,CAAC;CAChD,MAAM,UAAiD;EACtD,GAAG,QAAQ;EACX,cAAc,CAAC;EACf,gBAAgB,CAAC;EACjB,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,UAAU;EACb,SAAS,cAAc;GACtB,GAAG,SAAS;GACZ,mBAAmB,QAAQ;EAC5B;EAIA,SAAS,QAAQ,CAAC,iBAAiB;CACpC;CAEA,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,SAAS,iBAAiB,aAAa,QAAQ,KAAK;CAKrD,IAAI,QAAQ,MAAM,SAAS,gBAAgB,YAAY,QAAQ,IAAI;CAEnE,KAAK,MAAM,OAAO,MACjB,SAAS,IAAI,QAAQ;EACpB,OAAO,IAAI;EACX,GAAI,IAAI,QACL,EACA,OAAO;GACN,GAAG,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,OAAO,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,SAAS,QAAQ;EAChB,OAAO,eAAe;EACtB,SAAS;EACT,OAAO,CAAC,GAAG,QAAQ,MAAM,OAAO,GAAG,QAAQ,KAAK,IAAI;EACpD,SAAS;GACR;GACA;GACA;EACD;EACA,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;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;EAAE,MAAM;EAAS;EAAU;CAAQ;AAC3C;;;;;AAMA,SAAS,cAAc,MAA2B;CACjD,OAAO;EACN,WAAW;EACX,SAAS;EACT,OAAO;GACN,gBAAgB;GAChB,cAAc;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;;;;;;;;;;;;;;ACvpCA,IAAa,wBAAb,cAA2C,MAAM;CAEtC;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,WACA,aACK;CACL,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,MAAM,QACX;GACC,MAAM,aAAa,OAAO;GAC1B,MAAM,OAAO,QAAQ;GACrB,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,cAA0C,MAAM;CAErC;CAEA;CAHV,YACC,SAEA,MACC;EACD,MACC,GAAG,QAAQ,gBAAgB,KAAK,WAAW,IAAI,kBAAkB,gBAAgB,gCAChF,KAAK,KAAK,EAAE,KAAK,WAAW,OAAO,IAAI,IAAI,MAAM,CAAC,CAAC,KAAK,IAAI,IAC5D,sCAAsC,QAAQ,cAAc,KAAK,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,IAC/F;EARS,KAAA,UAAA;EAEA,KAAA,OAAA;EAOT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACkFA,IAAa,wBAAb,cAA2C,MAAM;CAChD,cAAc;EACb,MACC,gJAED;EACA,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CAC9C,cAAc;EACb,MACC,sJAGD;EACA,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,kBAAb,cAAqC,MAAM;CAEhC;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,cAAmC,MAAM;CACnB;CAArB,YAAY,MAAuB;EAClC,MACC,0EACQ,KAAK,8FAEd;EALoB,KAAA,OAAA;EAMpB,KAAK,OAAO;CACb;AACD;;;;;;;AAQA,SAAgB,kBAAkB,MAAc,OAAuB;CACtE,OAAO,KAAK,MAAM,kBAAkB,MAAM,KAAK;AAChD;;AAGA,eAAsB,YAAY,MAA+B;CAChE,IAAI;CACJ,IAAI;EACH,OACC,MAAM,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,MAHc,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,KAGzD;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,OAAO;EACN,OAAO,KAAK,cAAc,OAAO,GAAG;EACpC,MAAM,KAAK,cAAc,MAAM,EAAE;CAClC;AACD;;;;;AAMA,MAAa,cAA2B;CACvC,QAAQ;CACR,UAAU;CACV,KAAK;CACL,SAAS;CACT,SAAS;CACT,OAAO;CACP,gBAAgB;CAChB,kBAAkB;CAClB,KAAK,QAAQ;AACd;;;;;;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,QAChB,SAAS,UAAU,IAAI,KAAK,MAAM,UAAU,MAAM,KAAA,GAAW,GAAG,CACjE;CAKD,MAAM,YAAsC,CAAC;CAC7C,MAAM,aAAuC,CAAC;CAC9C,MAAM,WAAW,MAAM,SAAS;EAC/B,UAAU,eAAe,SAAS;EAClC,KAAK;EACL;EACA;CACD,CAAC;CAED,MAAM,EAAE,SAAS,cAAc,MAAM,aAAa,KAAK,QAAQ;CAK/D,IAAI,CAAC,MAAM;EAGV,qBAAqB;GACpB;GACA;GACA,UAAU,SAAS,UAAU,CAAC;EAC/B,CAAC;EACD,MAAM,uBAAuB;GAC5B;GACA,UAAU,eAAe,SAAS;GAClC;GACA;GACA,UAAU,SAAS,UAAU,CAAC;EAC/B,CAAC;CACF;CAGA,MAAM,SAAS,SAAS,UAAU,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,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,kBAAkB,KAAK,SAAS,WAAW;CAI3C,IAAI,SAAS,SAAS,kBAAkB,WAAW,QAAQ;CAK3D,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;CAEA,MAAM,MAAM,KAAK,MAAM,SAAS,KAAK,CAAC;CACtC,MAAM,WAAW,kBAAkB,MAAM,KAAK;CAC9C,MAAM,YAAY,WAAW,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;EACA,KAAK;GACJ,SAAS,eAAe,QAAQ;GAChC,MAAM,KAAK,KAAK,oBAAoB;GACpC,GAAI,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;GAC5C,KAAK;GACL,QAAQ,IAAI;GACZ,QAAQ,IAAI;EACb;EACA;EACA;EACA;EACA,OAAO,CAAC;EACR,QAAQ,CAAC;EACT,SAAS,CAAC;CACX;AACD;;AAGA,IAAa,qBAAb,cAAwC,MAAM;CACxB;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;;;;;;AAOA,SAAS,kBACR,WACA,OACO;CACP,IAAI,CAAC,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,SAAS,OAAO,GAAG;CAM3D,MAAM,UAAU,CAAC,mBAAG,IAJF,IAAI,CACrB,GAAG,MAAM,KAAK,QAAQ,QAAQ,IAAI,SAAS,UAAU,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,GACxE,GAAG,MAAM,QAAQ,KAAK,WAAW,OAAO,IAAI,CAC7C,CACwB,CAAC,CAAC,CACxB,QAAQ,SAAS;EACjB,MAAM,MAAM,UAAU,KAAK;EAC3B,OAAO,OAAO,CAAC,cAAc,KAAK,UAAU,MAAM,IAAI,IAAI,GAAG,SAAS;CACvE,CAAC,CAAC,CACD,KAAK;CACP,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,mBAAmB,OAAO;AAC7D;;;;;;;AAQA,eAAe,aACd,KACA,UACiE;CACjE,MAAM,SAAS,MAAM,IAAI,QAAQ,KAAK;CACtC,IAAI,IAAI,UAAU,IAAI,UAAU,OAAO,OACtC,OAAO;EAAE,SAAS;EAAQ,WAAW,CAAC;CAAE;CAGzC,MAAM,WAAW,qBAChB,UAAU,iBAAiB,IAAI,KAAK,GACpC,QACD;CAGA,MAAM,WAAW,YAAY,IAAI,UAAU,QAAQ,SAAS,IAAI,IAC7D,iBAAiB,SAAS,OAAO,IACjC;EAAE,SAAS,SAAS;EAAS,WAAW,CAAC;CAAE;CAE9C,MAAM,YAAY,UAAU,UAAU,SAAS,QAAQ,UAAU,CAAC,CAAC,IAChE,kBAAkB,SAAS,OAAO,IAClC;EAAE,SAAS,SAAS;EAAS,WAAW,CAAC;CAAE;CAC9C,MAAM,UAAU,UAAU;CAC1B,MAAM,YAAY;EACjB,GAAG,SAAS;EACZ,GAAG,SAAS;EACZ,GAAG,UAAU;CACd;CAEA,IAAI,QAAQ,MAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI;CAC/C,KAAK,MAAM,SAAS,OAAO,OAAO,QAAQ,UAAU,CAAC,CAAC,GACrD,IAAI,QAAQ,KAAK,KAAK;CAEvB,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;CAElB,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,KAAK;EACL,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;CAEA,IAAI,QAAQ,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,KAAK;CACpD,UAAU,KAAK,GAAG;CAElB,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,OAAO,MAAM,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS,GAAI;CAC1D,MAAM,SAAS,KAAK,QAAQ,MAAM,OAAO;CAKzC,MAAM,UAAU,CAHf,GAAI,MAAM,aAAa,QAAQ,QAAQ,OAAO,GAC9C,GAAI,MAAM,cAAc,QAAQ,QAAQ,QAAQ,CAE9B,CAAC,CAAC,QAAQ,UAAU,MAAM,OAAO,CAAC,CAAC;CACtD,IAAI,OAAO,KACV,gBAAgB,QAAQ,QAAQ,KAAK,IAAI,IAAI,UAAU,KAAK,QAAQ,eAAe,IACpF;AACD;;AAGA,eAAe,iBACd,KACA,KACA,MACgB;CAChB,MAAM,EAAE,UAAU;CAClB,MAAM,YAAiC,IAAI;CAC3C,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,IAAI,KAAK,YAAY,IAAI;CAE7D,MAAM,aAAa,mBAClB,MAAM,MACN,UAAU,MACV,MAAM,WAAW,IAClB;CACA,IAAI,WAAW,SAAS,GAAG;EAC1B,IAAI,OAAO,KAAK,4CAA4C;EAC5D,MAAM,cAAc,KAAK,IAAI,MAAM,MAAM,WAAW,MAAM,GAAG,UAAU;CACxE;CAKA,MAAM,UAA2C,CAAC;CAClD,MAAM,WAAW,MAAM,SAAS;EAC/B,UAAU,eAAe,SAAS;EAClC,KAAK,UAAU;EACf;CACD,CAAC;CAGD,MAAM,MAAM,OAAO,MAAM,MAAM;EAC9B,OAAO,GAAG,eAAe,UAAU,IAAI,KAAK;EAC5C,SAAS,UAAU;EACnB,QAAQ,MAAM,WAAW;EACzB,GAAI,MAAM,WAAW,OAAO,EAAE,MAAM,MAAM,WAAW,KAAK,IAAI,CAAC;CAChE,CAAC;CACD,MAAM,OAAO,MAAM,KAAK,QAAQ;EAC/B,MAAM,UAAU;EAChB;EACA;EACA;CACD,CAAC;CACD,KAAK,MAAM,EAAE,QAAQ,aAAa,MACjC,IAAI,QAAQ,SAAS,GACpB,IAAI,OAAO,KAAK,QAAQ,OAAO,WAAW,YAAY,QAAQ,QAAQ;AAGzE;;;;;;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,MAAM,GAAG;EACrC,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;CAExB,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,oEAAoE,KAAK,SAAS,IAAI,KAAK,GAAG,gBAAgB,GAC/G;AAEF;;;;;;AAOA,eAAe,aACd,KACA,KACgB;CAChB,MAAM,UAAU,MAAM,cAAc,KAAK,IAAI,OAAO,IAAI,aACvD,iBAAiB,IAAI,OAAO,IAAI,EAAE,CACnC;CACA,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,cAAc,QAAQ,OAAO,IAAI,KAAK,KAAK;CAC5C;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,MAAM,SAAS,OAAO,GAAG,GAAG,OAAO,CAAC,CAAC,YAAY,KAAA,CAAS,IAC1D,KAAA;CAEH,IAAI,OAAO,KAAK,uCAAuC;CACvD,MAAM,UAAU,MAAM,QAAQ,IAC7B,MAAM,KAAK,KAAK,QACf,SAAS,KAAK,KAAK,MAAM;EAAE;EAAI,OAAO,MAAM;CAAM,CAAC,CACpD,CACD;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,MAAM,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,GAAG,MAAM,IAAI,qBAAqB,MAAM,SAAS,IAAI;CAEvE,IAAI,MAAM,MAAM,WAAW,KAAK,MAAM,MAAM,MAAM,KAAK;AACxD;;;;;;;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,OACO;CACP,MAAM,QAAQ,WAAW,MAAM;EAC9B,OAAO,IAAI;EACX;EACA,MAAM,YAAY;EAClB,UAAU,SAAS;CACpB,CAAC;CACD,IAAI,OAAO,KAAK,KAAK,MAAM,KAAK,IAAI,GAAG;CACvC,IAAI,KAAK;EACR,MAAM;EACN,SAAS;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,OAAO,SAAS,CAAC,CAAC;CACnB,QAAQ;EACP,OAAO,QAAQ,IAAI,QAAQ;CAC5B;AACD;AAEA,eAAe,SACd,KACA,KACA,MACA,SACwE;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,GAAI,QAAQ,QAAQ,EAAE,WAAW,YAAY,IAAI,CAAC;IAClD,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,OAAO,KAAK,IAAI,KAAK,gBAAgB;AACtC;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,MAAM,MAAM,KAAK;EAAE,WAAW;EAAM,MAAM;CAAM,CAAC;CACjD,MAAM,MAAM,KAAK,GAAK;CAEtB,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,OAAO,MAAc,SAAiB,OAAO,QAAU;EACpE,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAC9C,MAAM,UAAU,MAAM,SAAS,EAAE,KAAK,CAAC;EACvC,MAAM,MAAM,MAAM,IAAI;EACtB,MAAM,KAAK,IAAI;CAChB;CAEA,MAAM,MAAM,KAAK,KAAK,oBAAoB,GAAG,YAAY,KAAK,CAAC;CAC/D,MAAM,MAAM,KAAK,KAAK,WAAW,GAAG,MAAM,SAAS;CACnD,KAAK,MAAM,OAAO,CAAC,GAAG,MAAM,MAAM,GAAG,MAAM,OAAO,GACjD,IAAI,IAAI,KACP,MAAM,MAAM,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,QAAQ,IAAI,GAAG,GAAG,GAAK;CAGnE,IAAI,MAAM,QAAQ,MAAM,QAAQ,SAAA,cAAsB,EAAE,UACvD,MAAM,MACL,KAAK,KAAK,GAAG,aAAa,KAAK,GAC/B,QAAQ,MAAM,KAAK,GAAG,GACtB,GACD;CAED,IAAI,MAAM,SAAS,MAAM,QAAQ,SAAA,QAAuB,EAAE,UACzD,MAAM,MACL,KAAK,KAAK,GAAG,cAAc,KAAK,GAChC,QAAQ,MAAM,MAAM,GAAG,GACvB,GACD;CAID,KAAK,MAAM,SAAS,MAAM,QAAQ,GAAG,GACpC,IAAI,MAAM,SAAS,cAAc,GAAG,MAAM,GAAG,KAAK,KAAK,KAAK,CAAC;CAE9D,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,MAAM,WAAW,GAC7D,MAAM,MAAM,KAAK,MAAM,IAAI,GAAG,OAAO;CAMtC,MAAM,mBAAmB,cAAc,IAAI,CAAC;CAE5C,OAAO;AACR;AAEA,SAAS,YAAY,OAA6B;CACjD,MAAM,QAAQ,YAAY,MAAM;CAChC,OAAO;QACA,MAAM,MAAM;;;;iBAIH,MAAM;iBACN,MAAM;EACrB,UAAU,MAAM,SAAS;EAAE,WAAW;EAAG,uBAAuB;CAAM,CAAC;AACzE;AAEA,SAAS,UAAU,KAAqB,KAAuB;CAC9D,MAAM,EAAE,OAAO,MAAM,UAAU;CAC/B,IAAI,OAAO,KAAK,QAAQ,MAAM,QAAQ,WAAW,MAAM,OAAO;CAC9D,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,OAAO,KACV,cAAc,MAAM,OAAO,iBAAiB,SAAS,MAAM,KAAK,EAAE,EACnE;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9pCA,SAAgB,cACf,UAAgC,CAAC,GACK;CACtC,MAAM,EAAE,MAAM,MAAM,KAAK,QAAQ,GAAG,UAAU;CAC9C,MAAM,OAAoB;EAAE,GAAG;EAAa,GAAG;CAAM;CAErD,OAAO,aAAoC;EAC1C,MAAM;EACN,SAAS;EACT,cAAc;GACb,UAAU;GACV,YAAY;GACZ,QAAQ;GAGR,YAAY;EACb;EAEA,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,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"}
|