@geekmidas/cli 10.0.0-alpha.78 → 10.0.0-alpha.80
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/{add-D2XKszYP.mjs → add-CIxT-Iq6.mjs} +2 -2
- package/dist/{add-D2XKszYP.mjs.map → add-CIxT-Iq6.mjs.map} +1 -1
- package/dist/{add-BvOICikp.cjs → add-DJ0VE-y-.cjs} +7 -7
- package/dist/{add-BvOICikp.cjs.map → add-DJ0VE-y-.cjs.map} +1 -1
- package/dist/{aws-Bja4zGSs.mjs → aws-B-6uEhgP.mjs} +8 -2
- package/dist/{aws-Bja4zGSs.mjs.map → aws-B-6uEhgP.mjs.map} +1 -1
- package/dist/{aws-CQAuluiu.cjs → aws-BTawF0F-.cjs} +19 -2
- package/dist/{aws-CQAuluiu.cjs.map → aws-BTawF0F-.cjs.map} +1 -1
- package/dist/{bundler-C6T-1OLT.cjs → bundler-BlbSLFLn.cjs} +3 -3
- package/dist/{bundler-C6T-1OLT.cjs.map → bundler-BlbSLFLn.cjs.map} +1 -1
- package/dist/{bundler-CtHzKqnZ.mjs → bundler-D4pl87A5.mjs} +3 -3
- package/dist/{bundler-CtHzKqnZ.mjs.map → bundler-D4pl87A5.mjs.map} +1 -1
- package/dist/{cli-BgPyhx1i.mjs → cli-7aLfgIGt.mjs} +3 -3
- package/dist/{cli-BgPyhx1i.mjs.map → cli-7aLfgIGt.mjs.map} +1 -1
- package/dist/{cli-K6Vj_pPW.cjs → cli-BkNZBe_-.cjs} +4 -4
- package/dist/{cli-K6Vj_pPW.cjs.map → cli-BkNZBe_-.cjs.map} +1 -1
- package/dist/{compose-B7MC19eC.cjs → compose-Bn4OJONR.cjs} +88 -60
- package/dist/{compose-B7MC19eC.cjs.map → compose-Bn4OJONR.cjs.map} +1 -1
- package/dist/{compose-DByK353T.mjs → compose-n7K8H5j8.mjs} +36 -8
- package/dist/{compose-DByK353T.mjs.map → compose-n7K8H5j8.mjs.map} +1 -1
- package/dist/{config-Bql0AmJt.d.mts → config-L_6NivCp.d.mts} +3 -3
- package/dist/{config-Bql0AmJt.d.mts.map → config-L_6NivCp.d.mts.map} +1 -1
- package/dist/{config-DlNpHK8p.d.cts → config-Mr4rcXFC.d.cts} +3 -3
- package/dist/{config-DlNpHK8p.d.cts.map → config-Mr4rcXFC.d.cts.map} +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/{databases-C2p5LGAp.cjs → databases-BY-pEImp.cjs} +185 -7
- package/dist/databases-BY-pEImp.cjs.map +1 -0
- package/dist/{databases-hUHTuwhx.mjs → databases-CzszQV0N.mjs} +153 -5
- package/dist/databases-CzszQV0N.mjs.map +1 -0
- package/dist/deploy/public.cjs +12 -11
- package/dist/deploy/public.d.cts +19 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +19 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-BerP7ppB.mjs → deploy-DK4Y6ev4.mjs} +3 -3
- package/dist/{deploy-BerP7ppB.mjs.map → deploy-DK4Y6ev4.mjs.map} +1 -1
- package/dist/{deploy-Dt42xiQA.cjs → deploy-Ppnh8MHS.cjs} +9 -9
- package/dist/{deploy-Dt42xiQA.cjs.map → deploy-Ppnh8MHS.cjs.map} +1 -1
- package/dist/{dokploy-ssZQRK2C.mjs → dokploy-Bjq05wkw.mjs} +2 -2
- package/dist/{dokploy-ssZQRK2C.mjs.map → dokploy-Bjq05wkw.mjs.map} +1 -1
- package/dist/{dokploy-NG9UrVrP.cjs → dokploy-CJvdoNc3.cjs} +2 -2
- package/dist/{dokploy-NG9UrVrP.cjs.map → dokploy-CJvdoNc3.cjs.map} +1 -1
- package/dist/{encryption-De6MN0O5.mjs → encryption-BrsOJFFz.mjs} +2 -2
- package/dist/{encryption-De6MN0O5.mjs.map → encryption-BrsOJFFz.mjs.map} +1 -1
- package/dist/{encryption-CbMI24fI.cjs → encryption-CAyR6D7B.cjs} +5 -5
- package/dist/{encryption-CbMI24fI.cjs.map → encryption-CAyR6D7B.cjs.map} +1 -1
- package/dist/{engine-CoCsNoW_.cjs → engine-DzBZR5D0.cjs} +118 -82
- package/dist/engine-DzBZR5D0.cjs.map +1 -0
- package/dist/{engine-DOjGIgl4.mjs → engine-ba9CvjTo.mjs} +53 -17
- package/dist/engine-ba9CvjTo.mjs.map +1 -0
- package/dist/github-BLjU59Ye.cjs +669 -0
- package/dist/github-BLjU59Ye.cjs.map +1 -0
- package/dist/github-CVdbVlT5.mjs +669 -0
- package/dist/github-CVdbVlT5.mjs.map +1 -0
- package/dist/{index-BXO0vlme.d.mts → index-C0UmP_lg.d.mts} +2 -2
- package/dist/{index-BXO0vlme.d.mts.map → index-C0UmP_lg.d.mts.map} +1 -1
- package/dist/{index-Rs0Fua-q.d.cts → index-DTEPwLml.d.cts} +2 -2
- package/dist/{index-Rs0Fua-q.d.cts.map → index-DTEPwLml.d.cts.map} +1 -1
- package/dist/index.cjs +114 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +41 -41
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-Cgoy58Sh.cjs → migrate-DkB833Jj.cjs} +8 -9
- package/dist/{migrate-Cgoy58Sh.cjs.map → migrate-DkB833Jj.cjs.map} +1 -1
- package/dist/{migrate-CNKaQl3K.mjs → migrate-DlBgATa-.mjs} +3 -4
- package/dist/{migrate-CNKaQl3K.mjs.map → migrate-DlBgATa-.mjs.map} +1 -1
- package/dist/{migrate-B4GBvCNY.cjs → migrate-iEdyEx4S.cjs} +4 -4
- package/dist/{migrate-B4GBvCNY.cjs.map → migrate-iEdyEx4S.cjs.map} +1 -1
- package/dist/{migrate-BQ4wVKq_.mjs → migrate-pfu4aYzX.mjs} +2 -2
- package/dist/{migrate-BQ4wVKq_.mjs.map → migrate-pfu4aYzX.mjs.map} +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-CEaqRBzY.cjs → resolve-4_5N67Fk.cjs} +3 -3
- package/dist/{resolve-CEaqRBzY.cjs.map → resolve-4_5N67Fk.cjs.map} +1 -1
- package/dist/{resolve-mvaystiE.mjs → resolve-CQPn66jr.mjs} +3 -3
- package/dist/{resolve-mvaystiE.mjs.map → resolve-CQPn66jr.mjs.map} +1 -1
- package/dist/{rollback-S2C-Y9pB.mjs → rollback-C0cbdsM-.mjs} +3 -3
- package/dist/{rollback-S2C-Y9pB.mjs.map → rollback-C0cbdsM-.mjs.map} +1 -1
- package/dist/{rollback-F3P-rA-r.cjs → rollback-CgYUPLbq.cjs} +5 -5
- package/dist/{rollback-F3P-rA-r.cjs.map → rollback-CgYUPLbq.cjs.map} +1 -1
- package/dist/{runtime-D9AxGzrw.d.cts → runtime-D6A-C6zh.d.cts} +2 -2
- package/dist/{runtime-D9AxGzrw.d.cts.map → runtime-D6A-C6zh.d.cts.map} +1 -1
- package/dist/{runtime-Dflki3Vs.d.mts → runtime-ekxfPNM-.d.mts} +2 -2
- package/dist/{runtime-Dflki3Vs.d.mts.map → runtime-ekxfPNM-.d.mts.map} +1 -1
- package/dist/sandbox/migrate-worker.cjs +22 -8
- package/dist/sandbox/migrate-worker.cjs.map +1 -1
- package/dist/sandbox/migrate-worker.mjs +22 -8
- package/dist/sandbox/migrate-worker.mjs.map +1 -1
- package/dist/{secretsManager-Ti0oZwsS.mjs → secretsManager-Chs9VV2r.mjs} +8 -2
- package/dist/{secretsManager-Ti0oZwsS.mjs.map → secretsManager-Chs9VV2r.mjs.map} +1 -1
- package/dist/{secretsManager-DUXW3fQt.cjs → secretsManager-DcMlHnRC.cjs} +19 -2
- package/dist/{secretsManager-DUXW3fQt.cjs.map → secretsManager-DcMlHnRC.cjs.map} +1 -1
- package/dist/{stale-C5FqIVc8.mjs → seeds-BdkFpW0P.mjs} +64 -6
- package/dist/seeds-BdkFpW0P.mjs.map +1 -0
- package/dist/{stale-BsiPJI7Y.cjs → seeds-ZljwYV_p.cjs} +81 -5
- package/dist/seeds-ZljwYV_p.cjs.map +1 -0
- package/dist/sniffer-BjG-1mlD.cjs.map +1 -1
- package/dist/sniffer-ByWtH28i.mjs.map +1 -1
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-DKxkXsKC.d.mts → types-BzCavjGt.d.mts} +29 -2
- package/dist/types-BzCavjGt.d.mts.map +1 -0
- package/dist/{types-ByY0zi3n.d.cts → types-DZtj9jeI.d.cts} +29 -2
- package/dist/types-DZtj9jeI.d.cts.map +1 -0
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/package.json +15 -15
- package/dist/databases-C2p5LGAp.cjs.map +0 -1
- package/dist/databases-hUHTuwhx.mjs.map +0 -1
- package/dist/engine-CoCsNoW_.cjs.map +0 -1
- package/dist/engine-DOjGIgl4.mjs.map +0 -1
- package/dist/github-CwX9z89E.mjs +0 -213
- package/dist/github-CwX9z89E.mjs.map +0 -1
- package/dist/github-D9vGqdLk.cjs +0 -213
- package/dist/github-D9vGqdLk.cjs.map +0 -1
- package/dist/provider-B3Sv_a74.cjs +0 -173
- package/dist/provider-B3Sv_a74.cjs.map +0 -1
- package/dist/provider-D7rQzzzf.mjs +0 -138
- package/dist/provider-D7rQzzzf.mjs.map +0 -1
- package/dist/stale-BsiPJI7Y.cjs.map +0 -1
- package/dist/stale-C5FqIVc8.mjs.map +0 -1
- package/dist/types-ByY0zi3n.d.cts.map +0 -1
- package/dist/types-DKxkXsKC.d.mts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine-CoCsNoW_.cjs","names":["logger","output","createHash","mkdtemp","join","tmpdir","writeFile","chmod","rm","dockerCommand","relative","run","DockerBuildFailed","DockerPushFailed","runOutput","validateImageRef","dockerfileOf","keyFingerprint","DokployApiError","projectName","ownershipMarker","markerOf","isOwnedBy","DokployApiError","toEmbeddableSecrets","encryptSecrets","cloudName","resourceName","ownerRole","readerRole","provideKey","cacheTable","cacheTableStatements","externalApiUrl","dependentsOf","cookieDomain","mobileOrigins","schemeBase","roleStatements","STORAGE_KEY_PAIR","externalServices","ExternalServicesNotConfigured","createHash","discover","constructGlobs","cacheBackendFor","providerOf","eventsBackendFor","storageBackendFor","provisionOrder","applyPostgres","appKey","logger","output","lookup","isDnsVerified","randomBytes","getGeneratedSecret","stripPublicPrefix","migrationTargets","migrationFiles","join","provideKey","activeSandbox","LocalSandbox","runWorker","logger","output","PgClient","createHash","output","getAppBuildOrder","assertExternalServices","manifestServiceDeclarations","devServicesUsed","assertStageCredentials","constructGlobs","workerUnits","withGeneratedSecrets","initStageSecrets","sniffAllApps","DeployJournal","createEmptyState","projectName","MissingCredential","getBackupState","applicationName","imageRef","imageRefFor","imageName","otelEnv","workerEnvKeys","workerDockerfileOf","WORKER_PORT","getPublicEnvPrefix","eventError","StateVersionConflict","StateStoreBusy","DokployApi","resolveHost","isMainFrontendApp"],"sources":["../src/deploy/docker.ts","../src/deploy/ownership.ts","../src/deploy/registry.ts","../src/deploy/secrets.ts","../src/target/dokploy/fromManifest.ts","../src/target/dokploy/declared.ts","../src/target/dokploy/dns/DnsProvider.ts","../src/target/dokploy/dns/index.ts","../src/target/dokploy/env-resolver.ts","../src/target/dokploy/health.ts","../src/target/dokploy/migrations.ts","../src/target/dokploy/postgres.ts","../src/target/dokploy/engine.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join, relative } from 'node:path';\nimport { DockerBuildFailed, DockerPushFailed, dockerCommand } from '../docker';\nimport { validateImageRef } from '../docker/imageRef';\nimport { output } from '../output';\nimport { dockerfileOf } from '../reconcile/apps.js';\nimport { type RunOptions, run, runOutput } from '../run';\nimport { keyFingerprint } from '../secrets/encryption';\nimport type { DockerDeployConfig, DockerDeployResult } from './types';\n\n// Through `output`, so a deploy run hears its own build's progress.\nconst logger = output;\n\n/**\n * The id the Dockerfile templates mount the encrypted credentials under:\n * `RUN --mount=type=secret,id=gkm_credentials`.\n */\nexport const CREDENTIALS_SECRET_ID = 'gkm_credentials';\n\n/** The encrypted payload a backend's image is built with. */\nexport interface BuildCredentials {\n\t/** Base64 ciphertext and auth tag. */\n\tencrypted: string;\n\t/** Hex IV. */\n\tiv: string;\n}\n\nexport interface DockerDeployOptions {\n\t/** Deployment stage */\n\tstage: string;\n\t/** Image tag */\n\ttag: string;\n\t/** Skip pushing to registry */\n\tskipPush?: boolean;\n\t/** Master key from build */\n\tmasterKey?: string;\n\t/** Docker config from gkm.config */\n\tconfig: DockerDeployConfig;\n\t/**\n\t * Build arguments to pass to docker build.\n\t * Format: ['KEY=value', 'KEY2=value2']\n\t *\n\t * Only for values that may be public: a build arg is recorded in the image\n\t * history. Secrets go through `credentials`.\n\t */\n\tbuildArgs?: string[];\n\t/**\n\t * Encrypted credentials, handed to the build as a BuildKit secret — never a\n\t * build arg, which `ps`, shell history and `docker history` all keep.\n\t */\n\tcredentials?: BuildCredentials;\n\t/**\n\t * Public URL argument names for frontend Dockerfile generation.\n\t * Used to ensure the Dockerfile declares these as ARG/ENV.\n\t */\n\tpublicUrlArgs?: string[];\n\t/**\n\t * The project root: where `gkm docker` generates, and the build context.\n\t * Defaults to the process's working directory, which is only the\n\t * project's when the CLI was started in it.\n\t */\n\tcwd?: string;\n\t/**\n\t * The app's path under `cwd`, as gkm.config.ts gives it. The image is\n\t * built from the Dockerfile `gkm docker` writes for it — one per app in a\n\t * workspace (`.gkm/docker/Dockerfile.<app>`), the one for a project\n\t * whose app is the root (`.gkm/docker/Dockerfile`). Defaults to `.`.\n\t */\n\tappPath?: string;\n\t/**\n\t * The Dockerfile, relative to `cwd`, when it is not the app's — a\n\t * worker's, which `gkm docker` writes as `.gkm/docker/Dockerfile.<worker>`.\n\t */\n\tdockerfile?: string;\n\t/** Stops the build or push: the child is killed. */\n\tsignal?: AbortSignal;\n\t/**\n\t * Where docker's own output goes. A deploy writing JSON to stdout sends it\n\t * to stderr instead. Defaults to the terminal.\n\t */\n\tstdio?: RunOptions['stdio'];\n}\n\n/** Where and how docker runs for one image. */\ninterface DockerRun {\n\tcwd: string;\n\t/** The Dockerfile, absolute. */\n\tdockerfile: string;\n\tsignal?: AbortSignal;\n\tstdio?: RunOptions['stdio'];\n}\n\n/**\n * Get the full image reference\n */\nexport function getImageRef(\n\tregistry: string | undefined,\n\timageName: string,\n\ttag: string,\n): string {\n\tif (registry) {\n\t\treturn `${registry}/${imageName}:${tag}`;\n\t}\n\treturn `${imageName}:${tag}`;\n}\n\n/**\n * The `docker build` argv for an image.\n *\n * One element per value, so nothing in a ref or a build arg is read by a\n * shell, and `--opt=value` rather than `--opt value`, so a value that starts\n * with `-` cannot be taken for one of docker's own flags.\n *\n * @internal Exported for testing\n */\nexport function dockerBuildArgs(options: {\n\tdockerfilePath: string;\n\timageRef: string;\n\tbuildArgs?: readonly string[];\n\t/** The file holding the encrypted credentials, if the build gets them. */\n\tcredentialsFile?: string;\n}): string[] {\n\tconst { dockerfilePath, imageRef, buildArgs = [], credentialsFile } = options;\n\treturn [\n\t\t'build',\n\t\t// linux/amd64 is what most cloud servers run.\n\t\t'--platform=linux/amd64',\n\t\t`--file=${dockerfilePath}`,\n\t\t`--tag=${imageRef}`,\n\t\t...buildArgs.map((arg) => `--build-arg=${arg}`),\n\t\t...(credentialsFile\n\t\t\t? [`--secret=id=${CREDENTIALS_SECRET_ID},src=${credentialsFile}`]\n\t\t\t: []),\n\t\t'.',\n\t];\n}\n\n/**\n * The build arg that names which credentials an image embeds: a hash of the\n * ciphertext, which is not a secret. A BuildKit secret is no part of the\n * build cache's key, so without it a rebuild with credentials encrypted under\n * a new key would reuse the layer that embedded the old ones.\n */\nexport function credentialsBuildArg(credentials: BuildCredentials): string {\n\tconst id = createHash('sha256')\n\t\t.update(`${credentials.encrypted}\\n${credentials.iv}`)\n\t\t.digest('hex')\n\t\t.slice(0, 16);\n\treturn `GKM_CIPHERTEXT_HASH=${id}`;\n}\n\n/** The secret file's content: ciphertext, then IV, one per line. */\nexport function credentialsFileContent(credentials: BuildCredentials): string {\n\treturn `${credentials.encrypted}\\n${credentials.iv}\\n`;\n}\n\n/**\n * Write the encrypted credentials where `docker build --secret` reads them.\n *\n * Two lines — ciphertext, then IV — so a template can split them with `sed`\n * in any base image. Owner-only, in a directory of its own, and the returned\n * cleanup removes both whatever the build did.\n *\n * @internal Exported for testing\n */\nexport async function writeCredentialsFile(\n\tcredentials: BuildCredentials,\n): Promise<{ path: string; cleanup: () => Promise<void> }> {\n\tconst dir = await mkdtemp(join(tmpdir(), 'gkm-credentials-'));\n\tconst path = join(dir, CREDENTIALS_SECRET_ID);\n\tawait writeFile(path, credentialsFileContent(credentials), {\n\t\tmode: 0o600,\n\t});\n\t// `mode` above passes through the umask; this does not.\n\tawait chmod(path, 0o600);\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rm(dir, { recursive: true, force: true }),\n\t};\n}\n\n/**\n * Build Docker image\n * @param imageRef - Full image reference (registry/name:tag)\n * @param buildArgs - Build arguments to pass to docker build\n * @param credentials - Encrypted credentials, passed as a build secret\n */\nasync function buildImage(\n\timageRef: string,\n\tbuildArgs: string[] | undefined,\n\tcredentials: BuildCredentials | undefined,\n\t{ cwd, dockerfile, signal, stdio }: DockerRun,\n): Promise<void> {\n\tlogger.log(`\\n🔨 Building Docker image: ${imageRef}`);\n\n\t// Every app's Dockerfile, as `gkm docker` writes it: the image prunes the\n\t// build root to the app's slice, installs it and builds it — workspace\n\t// packages, the bundle, a site's assets — inside Docker. Nothing the host\n\t// built reaches it.\n\tlogger.log(' Generating Dockerfile...');\n\tconst { buildRoot } = await dockerCommand({ cwd });\n\n\t// Relative to the build root, which is the context: absolute paths resolve\n\t// wherever the deploy was started, and the build runs from the root.\n\tconst dockerfilePath = relative(buildRoot, dockerfile);\n\n\tconst secret = credentials\n\t\t? await writeCredentialsFile(credentials)\n\t\t: undefined;\n\n\ttry {\n\t\t// The build root is the context: the package manager's root, which a\n\t\t// workspace's Dockerfiles prune from.\n\t\tawait run(\n\t\t\t'docker',\n\t\t\tdockerBuildArgs({\n\t\t\t\tdockerfilePath,\n\t\t\t\timageRef,\n\t\t\t\tbuildArgs: [\n\t\t\t\t\t...(buildArgs ?? []),\n\t\t\t\t\t...(credentials ? [credentialsBuildArg(credentials)] : []),\n\t\t\t\t],\n\t\t\t\tcredentialsFile: secret?.path,\n\t\t\t}),\n\t\t\t{\n\t\t\t\tcwd: buildRoot,\n\t\t\t\t// BuildKit, for `--secret` and `RUN --mount`.\n\t\t\t\tenv: { ...process.env, DOCKER_BUILDKIT: '1' },\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t\t...(stdio ? { stdio } : {}),\n\t\t\t},\n\t\t);\n\t\tlogger.log(`✅ Image built: ${imageRef}`);\n\t} catch (error) {\n\t\tthrow new DockerBuildFailed(imageRef, error);\n\t} finally {\n\t\tawait secret?.cleanup();\n\t}\n}\n\n/**\n * Push Docker image to registry\n */\nasync function pushImage(\n\timageRef: string,\n\t{ cwd, signal, stdio }: DockerRun,\n): Promise<void> {\n\tlogger.log(`\\n☁️ Pushing image: ${imageRef}`);\n\n\ttry {\n\t\tawait run('docker', ['push', imageRef], {\n\t\t\tcwd,\n\t\t\t...(signal ? { signal } : {}),\n\t\t\t...(stdio ? { stdio } : {}),\n\t\t});\n\t\tlogger.log(`✅ Image pushed: ${imageRef}`);\n\t} catch (error) {\n\t\tthrow new DockerPushFailed(imageRef, error);\n\t}\n}\n\n/**\n * The digest the registry gave a pushed image, `sha256:…`.\n *\n * A tag can be pushed over — by the next deploy, or by anything else that\n * shares the repository — and the digest is what says which image a stage\n * actually ran. `RepoDigests` has one entry per repository the image was\n * pushed to, so the one for this ref's repository is picked by name.\n *\n * @internal Exported for testing\n */\nexport async function pushedDigest(\n\timageRef: string,\n\t{ cwd, signal }: Pick<DockerRun, 'cwd' | 'signal'> = { cwd: process.cwd() },\n): Promise<string | undefined> {\n\tconst repository = imageRef.split('@')[0]!.replace(/:[\\w][\\w.-]*$/, '');\n\tconst output = await runOutput(\n\t\t'docker',\n\t\t['image', 'inspect', '--format={{json .RepoDigests}}', imageRef],\n\t\t{ cwd, ...(signal ? { signal } : {}) },\n\t);\n\n\tlet digests: unknown;\n\ttry {\n\t\tdigests = JSON.parse(output.trim() || '[]');\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!Array.isArray(digests)) return undefined;\n\n\tconst match = digests.find(\n\t\t(entry): entry is string =>\n\t\t\ttypeof entry === 'string' && entry.startsWith(`${repository}@`),\n\t);\n\treturn match?.slice(repository.length + 1);\n}\n\n/**\n * Deploy using Docker (build and optionally push image)\n */\nexport async function deployDocker(\n\toptions: DockerDeployOptions,\n): Promise<DockerDeployResult> {\n\tconst { stage, tag, skipPush, masterKey, config, buildArgs, credentials } =\n\t\toptions;\n\n\t// imageName is always set by the caller\n\tconst imageName = config.imageName!;\n\t// Before anything runs: a ref docker would misread is refused by name.\n\tconst imageRef = validateImageRef(\n\t\tgetImageRef(config.registry, imageName, tag),\n\t);\n\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst docker: DockerRun = {\n\t\tcwd,\n\t\tdockerfile: join(\n\t\t\tcwd,\n\t\t\toptions.dockerfile ??\n\t\t\t\tdockerfileOf(config.appName ?? imageName, options.appPath ?? '.'),\n\t\t),\n\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t...(options.stdio ? { stdio: options.stdio } : {}),\n\t};\n\n\tawait buildImage(imageRef, buildArgs, credentials, docker);\n\n\t// Push to registry if not skipped\n\tlet digest: string | undefined;\n\tif (!skipPush) {\n\t\tif (!config.registry) {\n\t\t\tlogger.warn(\n\t\t\t\t'\\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts',\n\t\t\t);\n\t\t} else {\n\t\t\tawait pushImage(imageRef, docker);\n\t\t\tdigest = await pushedDigest(imageRef, docker);\n\t\t}\n\t}\n\n\t// Output deployment info\n\tlogger.log('\\n✅ Docker deployment ready!');\n\tlogger.log(`\\n📋 Deployment details:`);\n\tlogger.log(` Image: ${imageRef}`);\n\tlogger.log(` Stage: ${stage}`);\n\n\t// Named by its fingerprint, never printed: the key decrypts every secret of\n\t// the stage, and CI logs and scrollback outlive the deploy.\n\tif (masterKey) {\n\t\tlogger.log(\n\t\t\t`\\n🔐 Run the container with GKM_MASTER_KEY set to the key with fingerprint ${keyFingerprint(masterKey)}.`,\n\t\t);\n\t}\n\n\treturn {\n\t\timageRef,\n\t\t...(digest ? { digest } : {}),\n\t\tmasterKey,\n\t};\n}\n","/**\n * Which Dokploy project a deploy is allowed to deploy into.\n *\n * Deploy used to take any project whose name matched the workspace's, in any\n * case — so a second workspace called `shop` (or `Shop`) on the same server\n * deployed into the first one's project, over its images and applications. A\n * project is now claimed by an ownership marker in its description, and a\n * project with the right name and no marker is somebody else's.\n */\n\nimport {\n\ttype DokployApi,\n\tDokployApiError,\n\ttype DokployEnvironment,\n\ttype DokployProjectDetails,\n} from '../target/dokploy/dokploy-api';\nimport {\n\ttype DeployIdentity,\n\tisOwnedBy,\n\tmarkerOf,\n\townershipMarker,\n\tprojectName,\n} from './identity';\n\n/**\n * A Dokploy project with the name this deploy would use exists, and nothing\n * says this workspace created it.\n */\nexport class ProjectNotOwned extends Error {\n\tconstructor(\n\t\treadonly projectName: string,\n\t\treadonly projectId: string,\n\t\treadonly identity: string,\n\t\t/** The marker the project carries instead, if it carries one. */\n\t\treadonly ownedBy: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\t`The Dokploy project '${projectName}' (${projectId}) was not created by this workspace (${identity})${ownedBy ? ` — it is marked '${ownedBy}'` : ''}, so deploy will not use it. ` +\n\t\t\t\t`Set deploy.namespace in gkm.config.ts to deploy under a name of your own, or, if this project really is this workspace's, add 'gkm:${identity}' to its description in Dokploy.`,\n\t\t);\n\t\tthis.name = 'ProjectNotOwned';\n\t}\n}\n\nexport interface ResolvedProject {\n\tprojectId: string;\n\tname: string;\n\tenvironments: DokployEnvironment[];\n\t/** How it was found, for the log. */\n\tvia: 'state' | 'marker' | 'created';\n}\n\n/** A description with the marker added, keeping what was there. */\nfunction withMarker(description: string | null, marker: string): string {\n\tconst existing = (description ?? '').trim();\n\treturn existing ? `${existing}\\n${marker}` : marker;\n}\n\n/** `project.one`, or `null` when Dokploy no longer has the project. */\nasync function projectById(\n\tapi: DokployApi,\n\tprojectId: string,\n): Promise<DokployProjectDetails | null> {\n\ttry {\n\t\t// Dokploy answers an unknown id with an error on some versions and an\n\t\t// empty body on others.\n\t\treturn (await api.getProject(projectId)) ?? null;\n\t} catch (error) {\n\t\tif (error instanceof DokployApiError) return null;\n\t\tthrow error;\n\t}\n}\n\n/** A project this identity may deploy into, as found without changing it. */\nexport interface FoundProject {\n\tprojectId: string;\n\tname: string;\n\tdescription: string | null;\n\tenvironments: DokployEnvironment[];\n\t/** By the id the stage's state recorded, or by name and marker. */\n\tvia: 'state' | 'marker';\n\t/**\n\t * Found through state but carrying no marker yet: a deploy writes the\n\t * marker; a dry run says it would.\n\t */\n\tneedsClaim: boolean;\n}\n\n/**\n * The project this identity owns, if there is one — read only, so a dry run\n * asks the same question a deploy does:\n *\n * 1. The one the stage's state names, if Dokploy still has it. State written\n * before markers existed is trusted — it holds an id this workspace was\n * given when it created the project.\n * 2. One with this name *and* this identity's marker.\n *\n * A project that matches by name (in any case) but carries no marker, or\n * another identity's, raises `ProjectNotOwned` — it is never adopted.\n */\nexport async function findProject(\n\tapi: DokployApi,\n\tidentity: DeployIdentity,\n\tstateProjectId: string | undefined,\n): Promise<FoundProject | null> {\n\tconst name = projectName(identity);\n\tconst marker = ownershipMarker(identity);\n\n\tif (stateProjectId) {\n\t\tconst known = await projectById(api, stateProjectId);\n\t\tif (known) {\n\t\t\tconst claimed = markerOf(known.description);\n\t\t\tif (claimed && claimed !== marker) {\n\t\t\t\tthrow new ProjectNotOwned(\n\t\t\t\t\tknown.name,\n\t\t\t\t\tknown.projectId,\n\t\t\t\t\tidentity.key,\n\t\t\t\t\tclaimed,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tprojectId: known.projectId,\n\t\t\t\tname: known.name,\n\t\t\t\tdescription: known.description ?? null,\n\t\t\t\tenvironments: known.environments ?? [],\n\t\t\t\tvia: 'state',\n\t\t\t\tneedsClaim: !claimed,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst projects = await api.listProjects();\n\n\t// The marker is the proof; the name only narrows the search. Compared in\n\t// any case so a project created as `Shop` before identities, and claimed\n\t// through its state since, is still found once that state is gone.\n\tconst owned = projects.find(\n\t\t(p) =>\n\t\t\tp.name.toLowerCase() === name.toLowerCase() &&\n\t\t\tisOwnedBy(p.description, identity),\n\t);\n\tif (owned) {\n\t\tconst details = await api.getProject(owned.projectId);\n\t\treturn {\n\t\t\tprojectId: owned.projectId,\n\t\t\tname: owned.name,\n\t\t\tdescription: owned.description ?? null,\n\t\t\tenvironments: details.environments ?? [],\n\t\t\tvia: 'marker',\n\t\t\tneedsClaim: false,\n\t\t};\n\t}\n\n\t// Case-insensitively, because the clash the marker exists to stop is\n\t// exactly `Shop` and `shop` landing on one server.\n\tconst clash = projects.find(\n\t\t(p) => p.name.toLowerCase() === name.toLowerCase(),\n\t);\n\tif (clash) {\n\t\tthrow new ProjectNotOwned(\n\t\t\tclash.name,\n\t\t\tclash.projectId,\n\t\t\tidentity.key,\n\t\t\tmarkerOf(clash.description),\n\t\t);\n\t}\n\n\treturn null;\n}\n\n/**\n * The project this deploy deploys into: the one {@link findProject} finds —\n * claimed with this identity's marker if it carries none yet, so the next\n * deploy without state still finds it — or a new one, marked.\n */\nexport async function resolveProject(\n\tapi: DokployApi,\n\tidentity: DeployIdentity,\n\tstateProjectId: string | undefined,\n\tlog: (message: string) => void = () => {},\n\thooks: {\n\t\t/** Runs just before a project is created — where a journal says so. */\n\t\tbeforeCreate?: () => Promise<void>;\n\t} = {},\n): Promise<ResolvedProject> {\n\tconst marker = ownershipMarker(identity);\n\tconst found = await findProject(api, identity, stateProjectId);\n\n\tif (found) {\n\t\tif (found.needsClaim) {\n\t\t\tawait api.updateProject(found.projectId, {\n\t\t\t\tname: found.name,\n\t\t\t\tdescription: withMarker(found.description, marker),\n\t\t\t});\n\t\t\tlog(` Claimed project ${found.name} for ${identity.key}`);\n\t\t}\n\t\treturn {\n\t\t\tprojectId: found.projectId,\n\t\t\tname: found.name,\n\t\t\tenvironments: found.environments,\n\t\t\tvia: found.via,\n\t\t};\n\t}\n\n\tawait hooks.beforeCreate?.();\n\tconst created = await api.createProject(\n\t\tprojectName(identity),\n\t\twithMarker('Deployed by gkm.', marker),\n\t);\n\treturn {\n\t\tprojectId: created.project.projectId,\n\t\tname: created.project.name,\n\t\tenvironments: [created.environment],\n\t\tvia: 'created',\n\t};\n}\n","/**\n * Which Dokploy registry a stage's images are pulled through.\n *\n * It used to be one id stored per machine (`~/.gkm/credentials.json`), and\n * when that was empty, the first registry Dokploy listed — so an image could be\n * deployed with credentials for a registry nobody chose, and two workspaces\n * deployed from one machine shared whichever was stored last. The id is now\n * kept in the stage's state, and found only from what the workspace\n * configured.\n */\n\nimport {\n\ttype DokployApi,\n\tDokployApiError,\n\ttype DokployRegistry,\n} from './dokploy-api';\n\n/** There is nowhere to push images to, so Dokploy has nothing to pull. */\nexport class RegistryNotConfigured extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`Deploying '${stage}' needs a container registry: Dokploy pulls each app's image from one. ` +\n\t\t\t\t`Set deploy.registry in gkm.config.ts (e.g. 'ghcr.io/acme'), and deploy.dokploy.registryId if Dokploy already holds that registry's credentials.`,\n\t\t);\n\t\tthis.name = 'RegistryNotConfigured';\n\t}\n}\n\n/** `deploy.dokploy.registryId` names a registry Dokploy does not have. */\nexport class RegistryNotFound extends Error {\n\tconstructor(readonly registryId: string) {\n\t\tsuper(\n\t\t\t`deploy.dokploy.registryId '${registryId}' is not a registry on this Dokploy server. ` +\n\t\t\t\t`Find the right id under Settings → Docker Registry in Dokploy and set it in gkm.config.ts, or remove it to have deploy find the registry by its URL.`,\n\t\t);\n\t\tthis.name = 'RegistryNotFound';\n\t}\n}\n\n/** More than one Dokploy registry serves the configured registry. */\nexport class RegistryAmbiguous extends Error {\n\tconstructor(\n\t\treadonly registry: string,\n\t\treadonly registryIds: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Dokploy has ${registryIds.length} registries for '${registry}' (${registryIds.join(', ')}). ` +\n\t\t\t\t`Set deploy.dokploy.registryId in gkm.config.ts to the one this workspace pushes with.`,\n\t\t);\n\t\tthis.name = 'RegistryAmbiguous';\n\t}\n}\n\n/** `https://ghcr.io/acme/` → `{ host: 'ghcr.io', path: 'acme' }`. */\nfunction parts(url: string): { host: string; path: string } {\n\tconst [host = '', ...path] = url\n\t\t.replace(/^[a-z]+:\\/\\//i, '')\n\t\t.replace(/\\/+$/, '')\n\t\t.toLowerCase()\n\t\t.split('/');\n\treturn { host, path: path.join('/') };\n}\n\n/**\n * The Dokploy registries that serve `registry`: the same host, and — where\n * Dokploy's own entry names one — the same path.\n */\nfunction serving(\n\tregistries: readonly DokployRegistry[],\n\tregistry: string,\n): DokployRegistry[] {\n\tconst wanted = parts(registry);\n\tconst sameHost = registries.filter(\n\t\t(r) => parts(r.registryUrl ?? '').host === wanted.host,\n\t);\n\tif (sameHost.length <= 1) return sameHost;\n\n\t// Several on one host (two organisations on ghcr.io): the one whose URL or\n\t// image prefix is the configured path is the one meant.\n\treturn sameHost.filter((r) => {\n\t\tconst own = parts(r.registryUrl ?? '');\n\t\tconst path = own.path || (r.imagePrefix ?? '').toLowerCase();\n\t\treturn path === wanted.path;\n\t});\n}\n\n/** `registry.one`, or `null` when Dokploy says it has no such registry. */\nasync function registryById(\n\tapi: DokployApi,\n\tregistryId: string,\n): Promise<DokployRegistry | null> {\n\ttry {\n\t\treturn (await api.getRegistry(registryId)) ?? null;\n\t} catch (error) {\n\t\t// Only Dokploy's own answer means \"not there\"; a timeout or a refused\n\t\t// connection is not a reason to pick another registry.\n\t\tif (error instanceof DokployApiError) return null;\n\t\tthrow error;\n\t}\n}\n\nexport interface ResolveRegistryOptions {\n\tstage: string;\n\t/** `deploy.registry`: where images are pushed. */\n\tregistry: string | undefined;\n\t/** `deploy.dokploy.registryId`: a registry chosen by id. */\n\tconfiguredId: string | undefined;\n\t/** The id the stage's state recorded on its last deploy. */\n\tstateId: string | undefined;\n\t/** Creates the registry in Dokploy when it has none for `registry`. */\n\tcreate: (registry: string) => Promise<DokployRegistry>;\n\tlog?: (message: string) => void;\n}\n\n/**\n * The registry id for a stage, in order: the configured id, the one in the\n * stage's state, the one Dokploy has for the configured registry URL, and\n * otherwise a new one. Never a registry the workspace did not point at.\n */\nexport async function resolveRegistry(\n\tapi: DokployApi,\n\toptions: ResolveRegistryOptions,\n): Promise<DokployRegistry> {\n\tconst { stage, registry, configuredId, stateId, log = () => {} } = options;\n\n\tif (!registry) throw new RegistryNotConfigured(stage);\n\n\tif (configuredId) {\n\t\tconst configured = await registryById(api, configuredId);\n\t\tif (!configured) throw new RegistryNotFound(configuredId);\n\t\treturn configured;\n\t}\n\n\tif (stateId) {\n\t\tconst known = await registryById(api, stateId);\n\t\tif (known) return known;\n\t\tlog(` ⚠ The stage's registry ${stateId} no longer exists in Dokploy`);\n\t}\n\n\tconst matches = serving(await api.listRegistries(), registry);\n\tif (matches.length > 1) {\n\t\tthrow new RegistryAmbiguous(\n\t\t\tregistry,\n\t\t\tmatches.map((r) => r.registryId),\n\t\t);\n\t}\n\tif (matches[0]) return matches[0];\n\n\treturn options.create(registry);\n}\n","import { encryptSecrets } from '../secrets/encryption.js';\nimport { toEmbeddableSecrets } from '../secrets/storage.js';\nimport type {\n\tEmbeddableSecrets,\n\tEncryptedPayload,\n\tStageSecrets,\n} from '../secrets/types.js';\nimport type { SniffedEnvironment } from './sniffer.js';\n\n/**\n * Result of filtering secrets for an app.\n */\nexport interface FilteredAppSecrets {\n\tappName: string;\n\t/** Secrets filtered to only include what the app needs */\n\tsecrets: EmbeddableSecrets;\n\t/** List of required env vars that were found in secrets */\n\tfound: string[];\n\t/** List of required env vars that were NOT found in secrets */\n\tmissing: string[];\n}\n\n/**\n * Filter secrets to only include the env vars that an app requires.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedEnv - The sniffed environment requirements for the app\n * @returns Filtered secrets with found/missing tracking\n */\nexport function filterSecretsForApp(\n\tstageSecrets: StageSecrets,\n\tsniffedEnv: SniffedEnvironment,\n): FilteredAppSecrets {\n\t// Convert stage secrets to flat embeddable format\n\tconst allSecrets = toEmbeddableSecrets(stageSecrets);\n\tconst filtered: EmbeddableSecrets = {};\n\tconst found: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Filter to only required env vars\n\tfor (const key of sniffedEnv.requiredEnvVars) {\n\t\tif (key in allSecrets) {\n\t\t\tfiltered[key] = allSecrets[key]!;\n\t\t\tfound.push(key);\n\t\t} else {\n\t\t\tmissing.push(key);\n\t\t}\n\t}\n\n\treturn {\n\t\tappName: sniffedEnv.appName,\n\t\tsecrets: filtered,\n\t\tfound: found.sort(),\n\t\tmissing: missing.sort(),\n\t};\n}\n\n/**\n * Result of encrypting secrets for an app.\n */\nexport interface EncryptedAppSecrets {\n\tappName: string;\n\t/** Encrypted payload with credentials and IV */\n\tpayload: EncryptedPayload;\n\t/** Master key for runtime decryption (hex encoded) */\n\tmasterKey: string;\n\t/** Number of secrets encrypted */\n\tsecretCount: number;\n\t/** List of required env vars that were NOT found in secrets */\n\tmissingSecrets: string[];\n}\n\n/**\n * Encrypt filtered secrets for an app.\n * Generates an ephemeral master key that should be injected into Dokploy.\n *\n * @param filteredSecrets - The filtered secrets for the app\n * @returns Encrypted payload with master key\n */\nexport function encryptSecretsForApp(\n\tfilteredSecrets: FilteredAppSecrets,\n): EncryptedAppSecrets {\n\tconst payload = encryptSecrets(filteredSecrets.secrets);\n\n\treturn {\n\t\tappName: filteredSecrets.appName,\n\t\tpayload,\n\t\tmasterKey: payload.masterKey,\n\t\tsecretCount: Object.keys(filteredSecrets.secrets).length,\n\t\tmissingSecrets: filteredSecrets.missing,\n\t};\n}\n\n/**\n * Filter and encrypt secrets for an app in one step.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedEnv - The sniffed environment requirements for the app\n * @returns Encrypted secrets with master key\n */\nexport function prepareSecretsForApp(\n\tstageSecrets: StageSecrets,\n\tsniffedEnv: SniffedEnvironment,\n): EncryptedAppSecrets {\n\tconst filtered = filterSecretsForApp(stageSecrets, sniffedEnv);\n\treturn encryptSecretsForApp(filtered);\n}\n\n/**\n * Prepare secrets for multiple apps.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedApps - Map of app name to sniffed environment\n * @returns Map of app name to encrypted secrets\n */\nexport function prepareSecretsForAllApps(\n\tstageSecrets: StageSecrets,\n\tsniffedApps: Map<string, SniffedEnvironment>,\n): Map<string, EncryptedAppSecrets> {\n\tconst results = new Map<string, EncryptedAppSecrets>();\n\n\tfor (const [appName, sniffedEnv] of sniffedApps) {\n\t\t// Only prepare secrets for apps that have required env vars\n\t\tif (sniffedEnv.requiredEnvVars.length > 0) {\n\t\t\tconst encrypted = prepareSecretsForApp(stageSecrets, sniffedEnv);\n\t\t\tresults.set(appName, encrypted);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Report on secrets preparation status for all apps.\n */\nexport interface SecretsReport {\n\t/** Total number of apps processed */\n\ttotalApps: number;\n\t/** Apps with encrypted secrets */\n\tappsWithSecrets: string[];\n\t/** Apps without secrets (frontends or no env requirements) */\n\tappsWithoutSecrets: string[];\n\t/** Apps with missing secrets (warnings) */\n\tappsWithMissingSecrets: Array<{\n\t\tappName: string;\n\t\tmissing: string[];\n\t}>;\n}\n\n/**\n * Generate a report on secrets preparation.\n */\nexport function generateSecretsReport(\n\tencryptedApps: Map<string, EncryptedAppSecrets>,\n\tsniffedApps: Map<string, SniffedEnvironment>,\n): SecretsReport {\n\tconst appsWithSecrets: string[] = [];\n\tconst appsWithoutSecrets: string[] = [];\n\tconst appsWithMissingSecrets: Array<{ appName: string; missing: string[] }> =\n\t\t[];\n\n\tfor (const [appName, sniffedEnv] of sniffedApps) {\n\t\tif (sniffedEnv.requiredEnvVars.length === 0) {\n\t\t\tappsWithoutSecrets.push(appName);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst encrypted = encryptedApps.get(appName);\n\t\tif (encrypted) {\n\t\t\tappsWithSecrets.push(appName);\n\n\t\t\tif (encrypted.missingSecrets.length > 0) {\n\t\t\t\tappsWithMissingSecrets.push({\n\t\t\t\t\tappName,\n\t\t\t\t\tmissing: encrypted.missingSecrets,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttotalApps: sniffedApps.size,\n\t\tappsWithSecrets: appsWithSecrets.sort(),\n\t\tappsWithoutSecrets: appsWithoutSecrets.sort(),\n\t\tappsWithMissingSecrets,\n\t};\n}\n","/**\n * The Dokploy target, read off the construct manifest.\n *\n * The AWS target has done this since `fromManifest` landed: a table keyed by\n * declaration kind, each entry turning one declaration into infrastructure and\n * the env keys it resolves. Dokploy had no such thing — it resolved environment\n * from the *sniffer*, which walks application code for `get('X')` calls, and a\n * construct reads its own key inside `@geekmidas/constructs` where there is\n * nothing to find. So a declared app deployed here got none of the model, and\n * nothing reported the absence: the deploy succeeded and the first request that\n * needed a URL failed at runtime.\n *\n * This is the same table, over the REST wrapper instead of over Pulumi.\n *\n * **Two phases, and the split is not incidental.** Creating a Postgres and\n * creating a role inside it are different kinds of act: the first is an API\n * call, the second needs a connection to a database that does not exist yet\n * when the call is made. So provisioners *accumulate* DDL rather than running\n * it, and it is applied once against a cluster that is up — which is exactly\n * what `DatabaseBootstrap` does on AWS, for exactly the same reason.\n *\n * **The DDL itself is shared.** `roleStatements` and `cacheTableStatements` are\n * the same generators the local target and the AWS target use. Dokploy used to\n * write its own `DO $$` block, which meant three targets applying three\n * different definitions of \"the role split\" and no way to notice they had\n * drifted.\n *\n * Entries are deliberately small and free of I/O ordering: each takes what it\n * needs and returns what it resolved. That is what would let a Pulumi dynamic\n * provider wrap one later without the table itself changing — see §6b.\n */\n\nimport { createHash } from 'node:crypto';\nimport { cacheTableStatements } from '@geekmidas/cache/postgres';\nimport {\n\townerRole,\n\ttype RoleStatement,\n\treaderRole,\n\troleStatements,\n} from '@geekmidas/db/pg/roles';\nimport {\n\ttype ConstructManifest,\n\tcacheTable,\n\tcloudName,\n\tcookieDomain,\n\ttype Declaration,\n\ttype DeclarationKind,\n\tdependentsOf,\n\texternalApiUrl,\n\tmobileOrigins,\n\tprovideKey,\n\tschemeBase,\n} from '@geekmidas/manifest';\nimport {\n\ttype DevService,\n\tExternalServicesNotConfigured,\n\texternalServices,\n\tSTORAGE_KEY_PAIR,\n} from '../../deploy/devServices.js';\nimport { resourceName } from '../../reconcile/plan.js';\nimport type { DokployApi } from './dokploy-api';\n\n/** What one provisioned construct resolves for anything that depends on it. */\nexport interface Provisioned {\n\t/** The env keys this construct publishes, and their values. */\n\tprovides: Record<string, string>;\n}\n\n/** A statement to run once the cluster it operates on is reachable. */\nexport interface DeferredStatement extends RoleStatement {\n\t/** The construct that asked for it, so a failure can name one. */\n\tid: string;\n\t/** The database to connect to, where it is not the cluster's default. */\n\tdatabase?: string;\n}\n\nexport interface DokployProvisionContext {\n\tmanifest: ConstructManifest;\n\t/** Everything already provisioned. Parents are present; siblings may not be. */\n\tprovisioned: Record<string, Provisioned>;\n\tapi: DokployApi;\n\tprojectId: string;\n\tenvironmentId: string;\n\t/** The stage, which scopes every name exactly as it does locally. */\n\tstage: string;\n\t/**\n\t * Seeds every derived password.\n\t *\n\t * Derived rather than random so a second deploy does not lock the running\n\t * app out of its own database, and seeded per project so two projects do not\n\t * share a credential.\n\t */\n\tproject: string;\n\t/**\n\t * The prefix every Dokploy name carries: the deploy identity's scope, so two\n\t * workspaces with one name in different namespaces never share a service.\n\t * Separate from `project` because that one salts passwords, and a change to\n\t * it would lock a running app out of its database. Defaults to `project`.\n\t */\n\tscope?: string;\n\t/** Where a declared cache lives — the same config the other targets read. */\n\tcache?: 'upstash' | 'elasticache' | 'db';\n\t/** Where a declared bucket lives. Only `minio` has a Dokploy primitive. */\n\tstorage?: 'minio' | 's3' | 'r2';\n\t/**\n\t * The dev services the stage may run (`--allow-dev-services`): MinIO for\n\t * a bucket whose URL the stage's secrets do not hold, Mailpit for mail.\n\t * Without them a bucket and mail are the stage's own, from `supplied`.\n\t */\n\tdevServices?: readonly DevService[];\n\t/** The stage's base domain, which Mailpit's sending address is on. */\n\tdomain?: string;\n\t/**\n\t * What carries a declared queue or topic — the same config the local target\n\t * reads, and for the same reason it is config rather than a declaration: the\n\t * handlers are written once and the transport is a deployment choice.\n\t */\n\tevents?: 'pgboss' | 'sns' | 'rabbitmq';\n\t/**\n\t * Where each surface answers, keyed by construct id.\n\t *\n\t * Assigned by whatever created the domain, which is the existing engine —\n\t * so it arrives here rather than being composed, the same way the local\n\t * target receives addresses it did not choose.\n\t */\n\taddresses?: Readonly<Record<string, string>>;\n\t/**\n\t * The stage's random seed, from its store: what every derived password is\n\t * salted with, so none can be computed from the project and stage names.\n\t */\n\tseed: string;\n\t/**\n\t * The stage's values by key, from its store: what it was given by hand\n\t * (`gkm secrets:set`, a third party's credentials) and what it generated\n\t * once (a `secret` construct's value — see `withGeneratedSecrets`).\n\t */\n\tsupplied?: Readonly<Record<string, string>>;\n\t/** DDL accumulated by the provisioners, applied once at the end. */\n\tdeferred: DeferredStatement[];\n\t/**\n\t * The Postgres each declared database resolved to, keyed by database name.\n\t *\n\t * Recorded because the deferred DDL has to run against *the cluster the\n\t * manifest created*, and nothing else knows which that is: a project may\n\t * also have a legacy `services.postgres`, and applying a construct's roles\n\t * to that one would create them where nothing connects.\n\t */\n\tclusters: Record<string, DokployCluster>;\n}\n\n/** The half of a Dokploy Postgres a caller outside this module needs. */\nexport interface DokployCluster {\n\tpostgresId: string;\n\tappName: string;\n\tdatabaseName: string;\n\tdatabaseUser: string;\n\tdatabasePassword: string;\n}\n\ntype Provisioner = (\n\tdeclaration: Declaration,\n\tcontext: DokployProvisionContext,\n) => Promise<Provisioned>;\n\n/**\n * The internal hostname a Dokploy Postgres answers on.\n *\n * Its own service name on the Docker network — not the server's public address.\n * An app reaching its database over the public internet would be a credential\n * crossing a network that did not need to see it.\n */\nfunction clusterHost(postgres: { appName: string }): string {\n\treturn postgres.appName;\n}\n\n/**\n * What a resource is called in the provider.\n *\n * `cloudName` and nothing else — the same scoped kebab rule the AWS target\n * uses, so a name reads identically on both: `production-shop-orders`.\n *\n * It briefly carried a `-postgres` suffix on the theory that a Dokploy project\n * is one flat list where an application and its database would collide. It is\n * not: `project.one` returns typed collections — `applications`, `postgres`,\n * `redis`, `compose`, `mariadb`, `mongo`, `mysql` — so the kind is already in\n * the shape of the response and an application and a Postgres of the same name\n * are different objects with different ids. The suffix was answering a question\n * nobody had asked.\n */\nexport function serviceName(\n\tscope: { stage: string; app: string },\n\tid: string,\n): string {\n\treturn cloudName(scope, id);\n}\n\nconst PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {\n\t/**\n\t * A Postgres service, plus the roles that reach it.\n\t *\n\t * The service is `findOrCreate`, because a deploy that recreated the\n\t * database would be a deploy that lost the data. The roles are deferred:\n\t * they need a connection to a cluster this call has only just asked for.\n\t */\n\tdatabase: async (declaration, context) => {\n\t\tif (declaration.kind !== 'database') throw new WrongKind(declaration.kind);\n\n\t\t// Two names, deliberately: what Postgres calls the database, and what the\n\t\t// Dokploy service list calls the service.\n\t\tconst name = resourceName(declaration.id, declaration.kind, context.stage);\n\t\tconst { postgres } = await context.api.findOrCreatePostgres(\n\t\t\tserviceName(\n\t\t\t\t{ stage: context.stage, app: context.scope ?? context.project },\n\t\t\t\tdeclaration.id,\n\t\t\t),\n\t\t\tcontext.projectId,\n\t\t\tcontext.environmentId,\n\t\t\t{\n\t\t\t\tdatabaseName: name,\n\t\t\t\t// The cluster master, which nothing in the application ever holds:\n\t\t\t\t// every handler connects as a role created *by* this one.\n\t\t\t\tdatabasePassword: derivedPassword(context, `${name}:master`),\n\t\t\t},\n\t\t);\n\n\t\tconst host = clusterHost(postgres);\n\t\tcontext.clusters[postgres.databaseName] = postgres;\n\t\tconst schema = declaration.schema ?? 'app';\n\t\tconst runtime = name;\n\t\tconst owner = ownerRole(runtime);\n\t\tconst reads = readsFrom(context.manifest, declaration.id);\n\n\t\tcontext.deferred.push(\n\t\t\t...statementsFor({\n\t\t\t\tid: declaration.id,\n\t\t\t\tdatabase: postgres.databaseName,\n\t\t\t\townsDatabase: true,\n\t\t\t\truntime,\n\t\t\t\towner,\n\t\t\t\t...(reads ? { reader: readerRole(runtime) } : {}),\n\t\t\t\tschema,\n\t\t\t\tcontext,\n\t\t\t}),\n\t\t);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[provideKey(declaration.id, 'url')]: postgresUrl(\n\t\t\t\t\truntime,\n\t\t\t\t\tderivedPassword(context, runtime),\n\t\t\t\t\thost,\n\t\t\t\t\tpostgres.databaseName,\n\t\t\t\t),\n\t\t\t\t// Deliberately not in `provides` on any manifest edge — the migrator\n\t\t\t\t// reads it from the injected environment and nothing can depend on\n\t\t\t\t// it, so DDL rights are never granted by an edge.\n\t\t\t\t[provideKey(declaration.id, 'ownerUrl')]: postgresUrl(\n\t\t\t\t\towner,\n\t\t\t\t\tderivedPassword(context, owner),\n\t\t\t\t\thost,\n\t\t\t\t\tpostgres.databaseName,\n\t\t\t\t),\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * A schema in the parent's database, with its own role and its own URL — so\n\t * the parent's role holds no grant on these tables at all.\n\t */\n\t'database-schema': async (declaration, context) => {\n\t\tif (declaration.kind !== 'database-schema')\n\t\t\tthrow new WrongKind(declaration.kind);\n\n\t\tconst parent = context.provisioned[declaration.of];\n\t\tif (!parent) throw new UnresolvedParent(declaration.id, declaration.of);\n\n\t\tconst runtime = resourceName(\n\t\t\tdeclaration.id,\n\t\t\tdeclaration.kind,\n\t\t\tcontext.stage,\n\t\t);\n\t\tconst owner = ownerRole(runtime);\n\t\tconst reads = readsFrom(context.manifest, declaration.id);\n\t\tconst parentUrl = new URL(\n\t\t\tparent.provides[provideKey(declaration.of, 'url')] ?? '',\n\t\t);\n\n\t\tcontext.deferred.push(\n\t\t\t...statementsFor({\n\t\t\t\tid: declaration.id,\n\t\t\t\tdatabase: parentUrl.pathname.slice(1),\n\t\t\t\truntime,\n\t\t\t\towner,\n\t\t\t\t...(reads ? { reader: readerRole(runtime) } : {}),\n\t\t\t\tschema: declaration.schema,\n\t\t\t\tcontext,\n\t\t\t}),\n\t\t);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[provideKey(declaration.id, 'url')]: postgresUrl(\n\t\t\t\t\truntime,\n\t\t\t\t\tderivedPassword(context, runtime),\n\t\t\t\t\tparentUrl.hostname,\n\t\t\t\t\tparentUrl.pathname.slice(1),\n\t\t\t\t),\n\t\t\t\t[provideKey(declaration.id, 'ownerUrl')]: postgresUrl(\n\t\t\t\t\towner,\n\t\t\t\t\tderivedPassword(context, owner),\n\t\t\t\t\tparentUrl.hostname,\n\t\t\t\t\tparentUrl.pathname.slice(1),\n\t\t\t\t),\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * A read-only endpoint on the same cluster.\n\t *\n\t * Nothing is provisioned: a Dokploy Postgres has one endpoint, so this\n\t * resolves to the writer's address — and that is safe rather than a\n\t * loophole, because read-only is enforced by the reader role's grants and\n\t * not by which host the URL names. The role itself was created with its\n\t * parent.\n\t */\n\t'database-reader': async (declaration, context) => {\n\t\tif (declaration.kind !== 'database-reader')\n\t\t\tthrow new WrongKind(declaration.kind);\n\n\t\tconst parent = context.provisioned[declaration.of];\n\t\tif (!parent) throw new UnresolvedParent(declaration.id, declaration.of);\n\n\t\tconst parentUrl = new URL(\n\t\t\tparent.provides[provideKey(declaration.of, 'url')] ?? '',\n\t\t);\n\t\tconst reader = readerRole(parentUrl.username);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[provideKey(declaration.id, 'url')]: postgresUrl(\n\t\t\t\t\treader,\n\t\t\t\t\tderivedPassword(context, reader),\n\t\t\t\t\tparentUrl.hostname,\n\t\t\t\t\tparentUrl.pathname.slice(1),\n\t\t\t\t),\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * A cache, wherever the project said it lives.\n\t *\n\t * `db` is a table in a database the manifest already declares, so it\n\t * provisions no service and costs nothing to run — the same relationship\n\t * pg-boss has. The table's DDL is deferred with the roles, and the table\n\t * name travels in the URL because two caches in one database resolve the\n\t * same connection string.\n\t */\n\tcache: async (declaration, context) => {\n\t\tif (declaration.kind !== 'cache') throw new WrongKind(declaration.kind);\n\n\t\tconst parentId =\n\t\t\tdeclaration.of ??\n\t\t\t(context.cache === 'db' ? soleDatabase(context) : undefined);\n\n\t\tif (!parentId) throw new CacheNeedsAHome(declaration.id, context.cache);\n\n\t\tconst parent = context.provisioned[parentId];\n\t\tif (!parent) throw new UnresolvedParent(declaration.id, parentId);\n\n\t\tconst parentUrl = parent.provides[provideKey(parentId, 'url')];\n\t\tif (!parentUrl) throw new UnresolvedParent(declaration.id, parentId);\n\n\t\tconst table = declaration.table ?? cacheTable(declaration.id);\n\t\tconst schema = schemaOf(context.manifest, parentId);\n\t\tconst qualified = schema ? `${schema}.${table}` : table;\n\n\t\tcontext.deferred.push(\n\t\t\t...cacheTableStatements({ table: qualified }).map((statement) => ({\n\t\t\t\tid: declaration.id,\n\t\t\t\tdatabase: new URL(parentUrl).pathname.slice(1),\n\t\t\t\tdescribe: statement.describe,\n\t\t\t\tsql: statement.sql,\n\t\t\t\t...(statement.exists ? { exists: statement.exists } : {}),\n\t\t\t})),\n\t\t\t// Created by the master, so it belongs to nobody the app connects as\n\t\t\t// until it is handed over — and default privileges cover only what the\n\t\t\t// owner creates.\n\t\t\t{\n\t\t\t\tid: declaration.id,\n\t\t\t\tdatabase: new URL(parentUrl).pathname.slice(1),\n\t\t\t\tdescribe: `${qualified} is owned by its schema's owner`,\n\t\t\t\tsql: `ALTER TABLE ${quoted(qualified)} OWNER TO ${quoted(ownerRole(new URL(parentUrl).username))}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: declaration.id,\n\t\t\t\tdatabase: new URL(parentUrl).pathname.slice(1),\n\t\t\t\tdescribe: `${new URL(parentUrl).username} may read and write ${qualified}`,\n\t\t\t\tsql: `GRANT SELECT, INSERT, UPDATE, DELETE ON ${quoted(qualified)} TO ${quoted(new URL(parentUrl).username)}`,\n\t\t\t},\n\t\t);\n\n\t\tconst url = new URL(parentUrl);\n\t\turl.searchParams.set('table', table);\n\n\t\treturn {\n\t\t\tprovides: { [provideKey(declaration.id, 'url')]: url.toString() },\n\t\t};\n\t},\n\n\t/**\n\t * A bucket: the stage's own, or — allowed — a MinIO stack on the box.\n\t *\n\t * A deployed stage's bucket is an external one — S3, R2, any S3-compatible\n\t * store — whose URL and key pair the stage's secrets hold. Only with\n\t * `--allow-dev-services minio` does this target run MinIO for one, and\n\t * then only for a bucket whose URL the stage did not set.\n\t *\n\t * Dokploy has first-class primitives for Postgres and Redis and none for\n\t * object storage, so MinIO is the one kind whose infrastructure this\n\t * target *writes* rather than configures — a compose file with one\n\t * service in it.\n\t *\n\t * The service is named `cloudName(...)` like everything else, which is not\n\t * cosmetic here: containers on `dokploy-network` resolve each other by\n\t * service name, so the name is the address. Calling it `minio` would work\n\t * for exactly one project on the box and then collide.\n\t *\n\t * A stage's own bucket URL may carry a key scoped to that bucket\n\t * (`s3://KEY:SECRET@bucket`), which the client signs with; the shared\n\t * `AWS_ACCESS_KEY_ID` pair is passed beside it when the stage set one, for\n\t * a bucket whose URL has none. The MinIO this provisions uses that pair —\n\t * the stage's, or one derived for it.\n\t */\n\tobjects: async (declaration, context) => {\n\t\tif (declaration.kind !== 'objects') throw new WrongKind(declaration.kind);\n\n\t\tconst key = provideKey(declaration.id, 'url');\n\t\tconst given = context.supplied?.[key];\n\t\tif (given !== undefined) {\n\t\t\treturn {\n\t\t\t\tprovides: {\n\t\t\t\t\t[key]: given,\n\t\t\t\t\t...storageKeys(context.supplied),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst backend = context.storage ?? 'minio';\n\t\tif (backend !== 'minio')\n\t\t\tthrow new UnprovisionableBucket(declaration.id, backend);\n\t\tif (!context.devServices?.includes('minio')) {\n\t\t\tthrow notConfigured(declaration.id, 'objects', context);\n\t\t}\n\n\t\tconst service = serviceName(\n\t\t\t{ stage: context.stage, app: context.scope ?? context.project },\n\t\t\tdeclaration.id,\n\t\t);\n\t\tconst bucket = resourceName(\n\t\t\tdeclaration.id,\n\t\t\tdeclaration.kind,\n\t\t\tcontext.stage,\n\t\t);\n\t\t// The stage's own key pair where it set one, so a second bucket that is\n\t\t// external signs with the same keys this one does.\n\t\tconst user = context.supplied?.AWS_ACCESS_KEY_ID ?? `${bucket}-root`;\n\t\tconst password =\n\t\t\tcontext.supplied?.AWS_SECRET_ACCESS_KEY ??\n\t\t\tderivedPassword(context, `objects:${declaration.id}`);\n\n\t\tconst { compose } = await context.api.findOrCreateCompose(\n\t\t\tservice,\n\t\t\tcontext.projectId,\n\t\t\tcontext.environmentId,\n\t\t\tminioCompose({ service, bucket, user, password }),\n\t\t);\n\n\t\tawait context.api.deployCompose(compose.composeId);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[key]: s3Url(service, bucket),\n\t\t\t\t// Beside the URL rather than inside it, for the reason above.\n\t\t\t\tAWS_ACCESS_KEY_ID: user,\n\t\t\t\tAWS_SECRET_ACCESS_KEY: password,\n\t\t\t\tAWS_REGION: context.supplied?.AWS_REGION ?? MINIO_REGION,\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * The address a bucket's objects are served on.\n\t *\n\t * The stage's own — a CDN, the bucket's domain — when its secrets hold\n\t * one, which a bucket that is not MinIO's needs.\n\t *\n\t * Over MinIO nothing is provisioned: Dokploy runs Traefik, so a second\n\t * reverse proxy behind the first would terminate TLS twice — which is why\n\t * the local target's Caddy has no equivalent here. What this resolves is\n\t * the address, and the `open` prefixes are applied to the bucket rather\n\t * than to an edge, so a policy is what makes them public wherever the\n\t * bucket lives. Until a Traefik rule exists it answers on MinIO directly,\n\t * path-style, which is honest about the shape it has today: the bucket is\n\t * in the path rather than fronted by a host of its own.\n\t */\n\t'file-server': async (declaration, context) => {\n\t\tif (declaration.kind !== 'file-server')\n\t\t\tthrow new WrongKind(declaration.kind);\n\n\t\tconst key = provideKey(declaration.id, 'url');\n\t\tconst given = context.supplied?.[key];\n\t\tif (given !== undefined) return { provides: { [key]: given } };\n\n\t\tconst parent = context.provisioned[declaration.of];\n\t\tconst parentUrl = parent?.provides[provideKey(declaration.of, 'url')];\n\t\tif (!parentUrl) throw new UnresolvedParent(declaration.id, declaration.of);\n\n\t\tconst endpoint = new URL(parentUrl).searchParams.get('endpoint');\n\t\tconst bucket = new URL(parentUrl).hostname;\n\t\tif (!endpoint) throw new UnresolvedParent(declaration.id, declaration.of);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[key]: `${endpoint}/${bucket}`,\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * Mail: the stage's own SMTP server, or — allowed — Mailpit on the box.\n\t *\n\t * Every provider speaks SMTP, so the provider is whatever the stage's\n\t * `<ID>_URL` names, with the address it sends from beside it. Only with\n\t * `--allow-dev-services mailpit`, and only where the stage set no URL,\n\t * does this run Mailpit — which catches every message and delivers none.\n\t */\n\temail: async (declaration, context) => {\n\t\tif (declaration.kind !== 'email') throw new WrongKind(declaration.kind);\n\n\t\tconst key = provideKey(declaration.id, 'url');\n\t\tconst from = provideKey(declaration.id, 'from');\n\t\tconst given = context.supplied?.[key];\n\t\tif (given !== undefined) {\n\t\t\treturn {\n\t\t\t\tprovides: {\n\t\t\t\t\t[key]: given,\n\t\t\t\t\t[from]: supplied(declaration.id, from, context),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (!context.devServices?.includes('mailpit')) {\n\t\t\tthrow notConfigured(declaration.id, 'email', context);\n\t\t}\n\n\t\tconst service = serviceName(\n\t\t\t{ stage: context.stage, app: context.scope ?? context.project },\n\t\t\tdeclaration.id,\n\t\t);\n\t\tconst { compose } = await context.api.findOrCreateCompose(\n\t\t\tservice,\n\t\t\tcontext.projectId,\n\t\t\tcontext.environmentId,\n\t\t\tmailpitCompose(service),\n\t\t);\n\t\tawait context.api.deployCompose(compose.composeId);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[key]: `smtp://${service}:1025`,\n\t\t\t\t[from]:\n\t\t\t\t\tcontext.supplied?.[from] ??\n\t\t\t\t\t`noreply@${context.domain ?? 'localhost'}`,\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * A topic, and below it a queue — the same broker either way.\n\t *\n\t * Under pg-boss there is nothing to create in Dokploy: the broker is a\n\t * schema tenant of the database the app already declared, exactly as it is\n\t * locally, so what this resolves is an address rather than a service. Which\n\t * is the point of putting the backend in config — the same handlers drain\n\t * pg-boss here and SQS on AWS because the string they were handed said so.\n\t *\n\t * The tenant gets its own role rather than the cluster master, for the\n\t * reason every other tenant does: pg-boss creates and owns its tables, and\n\t * a broker that could also read the application's is a broker with a grant\n\t * nothing asked for.\n\t */\n\ttopic: async (declaration, context) => {\n\t\tif (declaration.kind !== 'topic') throw new WrongKind(declaration.kind);\n\n\t\treturn broker(declaration.id, context);\n\t},\n\n\tqueue: async (declaration, context) => {\n\t\tif (declaration.kind !== 'queue') throw new WrongKind(declaration.kind);\n\n\t\treturn broker(declaration.id, context);\n\t},\n\n\t/**\n\t * A signing key, generated once and remembered in the stage's store.\n\t *\n\t * Random, never derived: a key computed from the project and stage names\n\t * signs sessions anyone reading the repo could forge. The deploy generates\n\t * it before provisioning (`withGeneratedSecrets`) and every later deploy\n\t * reads the same one, so live sessions survive a redeploy. Nothing is\n\t * created in Dokploy: a secret has no address.\n\t */\n\tsecret: async (declaration, context) => {\n\t\tif (declaration.kind !== 'secret') throw new WrongKind(declaration.kind);\n\n\t\t// The key the declaration publishes, not one derived here. A secret's key\n\t\t// is `environmentCase(id)` — `AuthSecret` becomes `AUTH_SECRET` — and\n\t\t// deriving `provideKey(id, 'value')` instead produced `AUTH_SECRET_VALUE`,\n\t\t// which nothing reads. Keys come from the declaration for exactly this\n\t\t// reason: what the build publishes and what the app reads cannot drift.\n\t\tconst key = declaration.provides?.[0];\n\t\tif (!key) return { provides: {} };\n\n\t\treturn { provides: { [key]: supplied(declaration.id, key, context) } };\n\t},\n\n\t/**\n\t * The keyring the stage keeps in its secrets.\n\t *\n\t * Generated on the first deploy (`withGeneratedSecrets`) and rotated only\n\t * by `gkm encryption:rotate`, so a redeploy never changes a key and nothing\n\t * written becomes unreadable. Nothing is created in Dokploy: the process\n\t * holds the keyring.\n\t */\n\tencryption: async (declaration, context) => {\n\t\tif (declaration.kind !== 'encryption') {\n\t\t\tthrow new WrongKind(declaration.kind);\n\t\t}\n\n\t\tconst key = provideKey(declaration.id, 'url');\n\t\treturn { provides: { [key]: supplied(declaration.id, key, context) } };\n\t},\n\n\t/**\n\t * A third party's credentials, as the stage was given them.\n\t *\n\t * Nothing is created and nothing derived: the value was issued by somebody\n\t * else. A stage that was never given one fails the deploy here, naming the\n\t * command that sets it — not the first request that needs it.\n\t */\n\tcredential: async (declaration, context) => {\n\t\tif (declaration.kind !== 'credential') {\n\t\t\tthrow new WrongKind(declaration.kind);\n\t\t}\n\n\t\tconst key = provideKey(declaration.id, 'credentials');\n\t\treturn { provides: { [key]: supplied(declaration.id, key, context) } };\n\t},\n\n\t/**\n\t * An API somebody else runs: the URL this stage calls it at, and the\n\t * credentials it was issued for this stage.\n\t */\n\t'external-api': async (declaration, context) => {\n\t\tif (declaration.kind !== 'external-api') {\n\t\t\tthrow new WrongKind(declaration.kind);\n\t\t}\n\n\t\tconst credentials = provideKey(declaration.id, 'credentials');\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[provideKey(declaration.id, 'url')]: externalApiUrl(\n\t\t\t\t\tdeclaration,\n\t\t\t\t\tcontext.stage,\n\t\t\t\t),\n\t\t\t\t[credentials]: supplied(declaration.id, credentials, context),\n\t\t\t},\n\t\t};\n\t},\n\n\t/**\n\t * A surface, at the address whatever created its domain assigned.\n\t *\n\t * Nothing is provisioned here: the application and its domain are the\n\t * existing engine's, and Dokploy's own Traefik terminates TLS with a Let's\n\t * Encrypt certificate. What this adds is the *derivation* — who may call it,\n\t * and where a cookie it sets is readable — from the graph rather than from a\n\t * hand-maintained list.\n\t */\n\t'rest-api': async (declaration, context) => {\n\t\tif (declaration.kind !== 'rest-api') throw new WrongKind(declaration.kind);\n\n\t\tconst url = context.addresses?.[declaration.id];\n\t\tif (!url) throw new SurfaceHasNoAddress(declaration.id);\n\n\t\t// A surface publishes three facts, not one: where it answers, who may\n\t\t// call it, and where a cookie it sets is readable. The last two are\n\t\t// derived from its *inbound* edges — the constructs that declared they\n\t\t// call it — which is the same derivation the local target makes and the\n\t\t// reason neither is a list anybody maintains.\n\t\t//\n\t\t// Returning only the URL left `AUTH_TRUSTED_ORIGINS` and\n\t\t// `AUTH_COOKIE_DOMAIN` unresolved, and Better Auth rejects an untrusted\n\t\t// origin whether or not it is a browser.\n\t\tconst origins = [\n\t\t\t...new Set(\n\t\t\t\tdependentsOf(context.manifest, declaration.id)\n\t\t\t\t\t.map((caller) => context.addresses?.[caller])\n\t\t\t\t\t.filter((address): address is string => Boolean(address)),\n\t\t\t),\n\t\t].sort();\n\n\t\tconst domain = cookieDomain([url, ...origins]);\n\n\t\t// A mobile caller is reached by its scheme — the bare one, deployed:\n\t\t// what the store build registers.\n\t\tconst schemes = dependentsOf(context.manifest, declaration.id).flatMap(\n\t\t\t(caller) => {\n\t\t\t\tconst app = context.manifest[caller];\n\t\t\t\treturn app?.kind === 'mobile-app'\n\t\t\t\t\t? mobileOrigins(schemeBase(context.project, app.scheme))\n\t\t\t\t\t: [];\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tprovides: {\n\t\t\t\t[provideKey(declaration.id, 'url')]: url,\n\t\t\t\t[provideKey(declaration.id, 'trustedOrigins')]: [\n\t\t\t\t\t...origins,\n\t\t\t\t\t...schemes,\n\t\t\t\t].join(','),\n\t\t\t\t...(domain\n\t\t\t\t\t? { [provideKey(declaration.id, 'cookieDomain')]: domain }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t},\n};\n\n/** The provisioner for a kind, or nothing where this target has none yet. */\nexport function provisionerFor(kind: DeclarationKind): Provisioner | undefined {\n\treturn PROVISIONERS[kind];\n}\n\n/** Which kinds this target can provision today — the rest are §6b's remainder. */\nexport function provisionableKinds(): DeclarationKind[] {\n\treturn Object.keys(PROVISIONERS) as DeclarationKind[];\n}\n\n/**\n * The role DDL for one database or tenant, from the shared generator.\n *\n * The same statements the local target applies and the same ones the AWS\n * bootstrap runs. Dokploy used to write its own, which is how three targets\n * came to hold three definitions of the same split.\n */\nfunction statementsFor(options: {\n\tid: string;\n\tdatabase: string;\n\truntime: string;\n\towner: string;\n\treader?: string;\n\tschema: string;\n\t/** A database's roles rather than a tenant's: its owner may create in it. */\n\townsDatabase?: boolean;\n\tcontext: DokployProvisionContext;\n}): DeferredStatement[] {\n\tconst { id, database, runtime, owner, reader, schema, context } = options;\n\n\treturn roleStatements({\n\t\truntime,\n\t\towner,\n\t\t...(reader ? { reader } : {}),\n\t\tschema,\n\t\t...(options.ownsDatabase ? { database } : {}),\n\t\tpasswords: {\n\t\t\truntime: derivedPassword(context, runtime),\n\t\t\towner: derivedPassword(context, owner),\n\t\t\t...(reader ? { reader: derivedPassword(context, reader) } : {}),\n\t\t},\n\t}).map((statement) => ({ ...statement, id, database }));\n}\n\n/**\n * The connection string a declared queue or topic publishes on.\n *\n * One broker for the whole project, which is what the local target does and\n * what the runtime expects: the generated pollers open a single connection and\n * subscribe each worker by name on it. So every carrier resolves to the same\n * address, and the DDL that backs it is pushed once however many are declared.\n *\n * Only pg-boss is answered here. SNS needs a topic ARN that has to exist\n * first, and RabbitMQ needs a broker Dokploy has no primitive for — both are\n * the §4.3 question, and composing a plausible URL for either would fail at the\n * first publish instead of here.\n */\nfunction broker(id: string, context: DokployProvisionContext): Provisioned {\n\tconst backend = context.events ?? 'pgboss';\n\tif (backend !== 'pgboss') throw new UnprovisionableCarrier(id, backend);\n\n\tconst parentId = soleDatabase(context);\n\tif (!parentId) throw new BrokerNeedsADatabase(id);\n\n\tconst parent = context.provisioned[parentId];\n\tconst parentUrl = parent?.provides[provideKey(parentId, 'url')];\n\tif (!parentUrl) throw new UnresolvedParent(id, parentId);\n\n\tconst url = new URL(parentUrl);\n\tconst database = url.pathname.slice(1);\n\tconst runtime = `${database}_${PGBOSS_SCHEMA}`;\n\tconst owner = ownerRole(runtime);\n\n\t// Pushed under a fixed id rather than the carrier's, so a project declaring\n\t// a topic *and* a queue defers one set of statements rather than two\n\t// identical ones. The applier is convergent either way; this keeps the plan\n\t// honest about there being one broker.\n\tif (!context.provisioned[BROKER_ID]) {\n\t\tcontext.deferred.push(\n\t\t\t...statementsFor({\n\t\t\t\tid: BROKER_ID,\n\t\t\t\tdatabase,\n\t\t\t\truntime,\n\t\t\t\towner,\n\t\t\t\tschema: PGBOSS_SCHEMA,\n\t\t\t\tcontext,\n\t\t\t}),\n\t\t);\n\t\tcontext.provisioned[BROKER_ID] = { provides: {} };\n\t}\n\n\tconst connection = pgbossUrl(\n\t\truntime,\n\t\tderivedPassword(context, runtime),\n\t\turl.host,\n\t\tdatabase,\n\t);\n\n\treturn {\n\t\tprovides: {\n\t\t\t[provideKey(id, 'publisherConnectionString')]: connection,\n\t\t},\n\t};\n}\n\n/** The schema pg-boss creates its tables in, here as locally. */\nconst PGBOSS_SCHEMA = 'pgboss';\n\n/**\n * The id the broker's DDL is pushed under.\n *\n * Not a construct — no declaration names it — but the deferred statements need\n * an id, and every carrier in the project shares this one.\n */\nconst BROKER_ID = 'PgBoss';\n\n/**\n * A pg-boss address: a Postgres URL under a scheme that picks the transport.\n *\n * The protocol is what a producer branches on, so it never branches — the same\n * `.publish()` reaches pg-boss here and SQS on AWS.\n */\nfunction pgbossUrl(\n\trole: string,\n\tpassword: string,\n\thost: string,\n\tdatabase: string,\n): string {\n\treturn `pgboss://${role}:${encodeURIComponent(password)}@${host}/${database}?schema=${PGBOSS_SCHEMA}`;\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/** An `s3://` URL pointing the same S3 client at MinIO on the internal network. */\nfunction s3Url(service: string, bucket: string): string {\n\treturn (\n\t\t`s3://${bucket}?region=${MINIO_REGION}` +\n\t\t`&endpoint=http://${service}:9000&forcePathStyle=true`\n\t);\n}\n\n/**\n * A one-service compose file for a bucket.\n *\n * `dokploy-network` is external and already exists — it is what every Dokploy\n * service is attached to, and joining it is what makes the app able to resolve\n * this one by name. The bucket itself is created by MinIO's entrypoint rather\n * than by a second call, so there is nothing to reconcile afterwards.\n */\nfunction minioCompose(options: {\n\tservice: string;\n\tbucket: string;\n\tuser: string;\n\tpassword: string;\n}): string {\n\tconst { service, bucket, user, password } = options;\n\n\treturn [\n\t\t'services:',\n\t\t` ${service}:`,\n\t\t' image: pgsty/minio:RELEASE.2026-08-04T00-00-00Z',\n\t\t` command: server /data --console-address \":9001\"`,\n\t\t' environment:',\n\t\t` MINIO_ROOT_USER: ${user}`,\n\t\t` MINIO_ROOT_PASSWORD: ${password}`,\n\t\t' volumes:',\n\t\t` - ${service}-data:/data`,\n\t\t' networks:',\n\t\t' - dokploy-network',\n\t\t' healthcheck:',\n\t\t' test: [\"CMD\", \"mc\", \"ready\", \"local\"]',\n\t\t' interval: 10s',\n\t\t' retries: 5',\n\t\t` ${service}-bucket:`,\n\t\t' image: minio/mc:latest',\n\t\t' depends_on:',\n\t\t` ${service}:`,\n\t\t' condition: service_healthy',\n\t\t' entrypoint: >',\n\t\t` /bin/sh -c \"mc alias set s3 http://${service}:9000 ${user} ${password} &&`,\n\t\t` mc mb --ignore-existing s3/${bucket}\"`,\n\t\t' networks:',\n\t\t' - dokploy-network',\n\t\t'volumes:',\n\t\t` ${service}-data:`,\n\t\t'networks:',\n\t\t' dokploy-network:',\n\t\t' external: true',\n\t\t'',\n\t].join('\\n');\n}\n\n/**\n * A one-service compose file for Mailpit, on `dokploy-network` so the apps\n * reach it by its service name. It accepts mail from anything on the network\n * and delivers none of it.\n */\nfunction mailpitCompose(service: string): string {\n\treturn [\n\t\t'services:',\n\t\t` ${service}:`,\n\t\t' image: axllent/mailpit:latest',\n\t\t' environment:',\n\t\t\" MP_SMTP_AUTH_ACCEPT_ANY: '1'\",\n\t\t\" MP_SMTP_AUTH_ALLOW_INSECURE: '1'\",\n\t\t' networks:',\n\t\t' - dokploy-network',\n\t\t'networks:',\n\t\t' dokploy-network:',\n\t\t' external: true',\n\t\t'',\n\t].join('\\n');\n}\n\n/**\n * The S3 client's shared keys the stage set, for a bucket that is its own —\n * none when it set none, since a bucket's URL may carry its own key.\n */\nfunction storageKeys(\n\tvalues: Readonly<Record<string, string>> | undefined,\n): Record<string, string> {\n\tconst keys: Record<string, string> = {};\n\tfor (const key of [...STORAGE_KEY_PAIR, 'AWS_REGION']) {\n\t\tconst value = values?.[key];\n\t\tif (value !== undefined) keys[key] = value;\n\t}\n\treturn keys;\n}\n\n/**\n * The error for a bucket or mail the stage configured nothing for — what\n * `validate` already refused, should a provisioner be reached without it.\n */\nfunction notConfigured(\n\tid: string,\n\tkind: 'email' | 'objects',\n\tcontext: DokployProvisionContext,\n): ExternalServicesNotConfigured {\n\tconst { missing } = externalServices({\n\t\tstage: context.stage,\n\t\tdeclarations: [{ id, kind }],\n\t\tsupplied: context.supplied ?? {},\n\t\tallow: [],\n\t\t...(context.domain ? { domain: context.domain } : {}),\n\t});\n\treturn new ExternalServicesNotConfigured(context.stage, missing);\n}\n\n/** Whether anything reads through a reader on this construct. */\nfunction readsFrom(manifest: ConstructManifest, id: string): boolean {\n\treturn Object.values(manifest).some(\n\t\t(declaration) =>\n\t\t\tdeclaration.kind === 'database-reader' && declaration.of === id,\n\t);\n}\n\n/** The schema a database or tenant pins on its roles. */\nfunction schemaOf(manifest: ConstructManifest, id: string): string | undefined {\n\tconst declaration = manifest[id];\n\n\t// By kind rather than `'schema' in declaration`: a database that names no\n\t// schema has no `schema` key at all, and its roles are still pinned to\n\t// `app` — so a cache table created unqualified landed where its runtime\n\t// role's search_path never looks.\n\tif (declaration?.kind === 'database') return declaration.schema ?? 'app';\n\tif (declaration?.kind === 'database-schema') return declaration.schema;\n\n\treturn undefined;\n}\n\n/**\n * The one declared database, where `cache: 'db'` has to pick.\n *\n * Unambiguous with one and arbitrary with two, so two is an error rather than a\n * coin toss — a cache landing in a database nobody chose surfaces as entries\n * that are never found, long after the deploy reported success.\n */\nfunction soleDatabase(context: DokployProvisionContext): string | undefined {\n\tconst databases = Object.entries(context.manifest)\n\t\t.filter(([, declaration]) => declaration.kind === 'database')\n\t\t.map(([id]) => id);\n\n\tif (databases.length > 1) {\n\t\tthrow new CacheIsAmbiguous(databases);\n\t}\n\n\treturn databases[0];\n}\n\n/**\n * A password derived from the stage's seed, the project, the stage and the role.\n *\n * Derived rather than stored per role so a redeploy hands the running\n * application the password it already has, and two projects never share one.\n * The seed is what makes it secret: random, generated once and kept in the\n * stage's store. Without it the inputs are all in the repo, and so was every\n * production password.\n */\nfunction derivedPassword(\n\tcontext: DokployProvisionContext,\n\trole: string,\n): string {\n\treturn createHash('sha256')\n\t\t.update(`${context.seed}:${context.project}:${context.stage}:role:${role}`)\n\t\t.digest('base64url')\n\t\t.slice(0, 32);\n}\n\n/** A connection string for a role on a cluster. */\nfunction postgresUrl(\n\trole: string,\n\tpassword: string,\n\thost: string,\n\tdatabase: string,\n): string {\n\treturn `postgres://${role}:${encodeURIComponent(password)}@${host}:5432/${database}`;\n}\n\n/** Quote an identifier, per segment, for DDL that cannot be parameterised. */\nfunction quoted(name: string): string {\n\treturn name\n\t\t.split('.')\n\t\t.map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\n\t\t.join('.');\n}\n\n/** A provisioner was handed a declaration of the wrong kind. */\n/**\n * A value only the stage's own secrets can hold.\n *\n * @throws {MissingSuppliedSecret} when the stage was never given it.\n */\nfunction supplied(\n\tid: string,\n\tkey: string,\n\tcontext: DokployProvisionContext,\n): string {\n\tconst value = context.supplied?.[key];\n\tif (value === undefined) {\n\t\tthrow new MissingSuppliedSecret(id, key, context.stage);\n\t}\n\n\treturn value;\n}\n\n/** A construct needs a value the stage was never given. */\nexport class MissingSuppliedSecret extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' needs ${key}, and the stage '${stage}' has none. Nothing can ` +\n\t\t\t\t`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 = 'MissingSuppliedSecret';\n\t}\n}\n\nexport class WrongKind extends Error {\n\tconstructor(readonly kind: string) {\n\t\tsuper(`No Dokploy provisioner handles '${kind}'`);\n\t\tthis.name = 'WrongKind';\n\t}\n}\n\n/** A derived construct whose parent has not been provisioned. */\nexport class UnresolvedParent extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly parent: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' derives from '${parent}', which has not been provisioned. ` +\n\t\t\t\t`Provision in \\`provisionOrder\\`, which puts parents first.`,\n\t\t);\n\t\tthis.name = 'UnresolvedParent';\n\t}\n}\n\n/** A cache with nowhere to live. */\nexport class CacheNeedsAHome extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly backend: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' is a cache and nothing says where it lives. Declare it from ` +\n\t\t\t\t`its database — \\`orders.cache('${id}')\\`.` +\n\t\t\t\t(backend ? ` The deploy target's backend is '${backend}'.` : ''),\n\t\t);\n\t\tthis.name = 'CacheNeedsAHome';\n\t}\n}\n\n/** A `'db'` cache (a server target's default) with more than one database. */\nexport class CacheIsAmbiguous extends Error {\n\tconstructor(readonly databases: readonly string[]) {\n\t\tsuper(\n\t\t\t`A cache backed by the database needs to know which one, and this app ` +\n\t\t\t\t`declares ${databases.length}: ${databases.join(', ')}. Declare the ` +\n\t\t\t\t`cache from its database rather than as a bare new Cache().`,\n\t\t);\n\t\tthis.name = 'CacheIsAmbiguous';\n\t}\n}\n\n/** A surface reached provisioning before its domain existed. */\nexport class SurfaceHasNoAddress extends Error {\n\tconstructor(readonly id: string) {\n\t\tsuper(\n\t\t\t`'${id}' is a surface and no address was supplied for it. The domain is ` +\n\t\t\t\t`created before the manifest is provisioned, so this means the two ` +\n\t\t\t\t`ran out of order.`,\n\t\t);\n\t\tthis.name = 'SurfaceHasNoAddress';\n\t}\n}\n\n/** A queue or topic on a backend this target has no primitive for. */\nexport class UnprovisionableCarrier extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly backend: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' is carried by '${backend}', which this target cannot ` +\n\t\t\t\t`provision. SNS needs a topic ARN that has to exist first and ` +\n\t\t\t\t`RabbitMQ needs a broker Dokploy has no primitive for; pg-boss is a ` +\n\t\t\t\t`schema tenant of a database this app already declares, which is why ` +\n\t\t\t\t`it is the one that works here. Deploy this app to a target that has ` +\n\t\t\t\t`the backend.`,\n\t\t);\n\t\tthis.name = 'UnprovisionableCarrier';\n\t}\n}\n\n/** A pg-boss carrier in an app that declares no database to host it. */\nexport class BrokerNeedsADatabase extends Error {\n\tconstructor(readonly id: string) {\n\t\tsuper(\n\t\t\t`'${id}' is carried by pg-boss, which lives in the database the app ` +\n\t\t\t\t`declares — and this app declares none. Declare a database, or deploy ` +\n\t\t\t\t`to a target whose broker is its own.`,\n\t\t);\n\t\tthis.name = 'BrokerNeedsADatabase';\n\t}\n}\n\n/** A bucket on a backend this target has no primitive for. */\nexport class UnprovisionableBucket extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly backend: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' is stored on '${backend}', which this target cannot ` +\n\t\t\t\t`provision: an S3 or R2 bucket belongs to an account this deploy ` +\n\t\t\t\t`does not hold, the way an API key does. Supply the bucket's URL.`,\n\t\t);\n\t\tthis.name = 'UnprovisionableBucket';\n\t}\n}\n","/**\n * The declared half of a Dokploy deploy.\n *\n * `fromManifest.ts` decides what each construct resolves to; this runs it —\n * discovers the manifest, walks it parents-first, and applies the DDL the\n * provisioners deferred.\n *\n * It is deliberately separate from the engine in `index.ts`. That file deploys\n * *applications*: images, registries, domains, the things a project has whether\n * or not it declares anything. This is the part that exists because the app\n * declared it, and keeping the two apart is what lets a project adopt the model\n * without rewriting its deploy — and lets this one be tested without one.\n */\n\nimport { type ConstructManifest, provisionOrder } from '@geekmidas/manifest';\nimport type { DevService } from '../../deploy/devServices.js';\nimport { discover } from '../../reconcile/discover.js';\nimport {\n\tapplyPostgres,\n\ttype SqlClient,\n\ttype Statement,\n} from '../../reconcile/provision.js';\nimport { constructGlobs } from '../../reconcile/workspace.js';\nimport {\n\tcacheBackendFor,\n\teventsBackendFor,\n\tproviderOf,\n\tstorageBackendFor,\n} from '../../workspace/backends.js';\nimport { appKey } from '../../workspace/derive.js';\nimport type { NormalizedWorkspace } from '../../workspace/types.js';\nimport type { DokployApi } from './dokploy-api';\nimport {\n\ttype DokployCluster,\n\ttype DokployProvisionContext,\n\ttype Provisioned,\n\tprovisionerFor,\n} from './fromManifest';\n\nexport interface DeclaredResult {\n\t/** Every env key the manifest resolved, and its value. */\n\tenv: Record<string, string>;\n\t/** The DDL still to run, once a connection to the cluster exists. */\n\tstatements: Statement[];\n\t/** What was provisioned, keyed by construct id. */\n\tprovisioned: Record<string, Provisioned>;\n\t/**\n\t * The cluster each statement's database lives in, keyed by database name.\n\t *\n\t * The DDL has to run against the Postgres *the manifest created*. A project\n\t * may also have a legacy `services.postgres`, and applying a construct's\n\t * roles there would create them where nothing connects.\n\t */\n\tclusters: Record<string, DokployCluster>;\n}\n\nexport interface DeclaredOptions {\n\tapi: DokployApi;\n\tworkspace: NormalizedWorkspace;\n\tprojectId: string;\n\tenvironmentId: string;\n\tstage: string;\n\t/**\n\t * The prefix every provisioned name carries — the deploy identity's\n\t * `scope`. Defaults to the workspace name, as before identities.\n\t */\n\tscope?: string;\n\t/**\n\t * Where each app answers, keyed by *app* name — `https://api.example.com`.\n\t *\n\t * Computed by the engine before it saves any environment, which is what\n\t * makes a surface's own URL available to the constructs that depend on it.\n\t */\n\tappUrls: Readonly<Record<string, string>>;\n\t/** The stage's random seed, which every derived password is salted with. */\n\tseed: string;\n\t/** The stage's values by key: given by hand, and generated once. */\n\tsupplied?: Readonly<Record<string, string>>;\n\t/** A manifest already in hand, for a caller that has discovered one. */\n\tmanifest?: ConstructManifest;\n\t/**\n\t * The dev services the stage may run for mail and buckets its secrets do\n\t * not configure (`--allow-dev-services`).\n\t */\n\tdevServices?: readonly DevService[];\n}\n\n/**\n * Provision everything the workspace declares, and return what it resolved.\n */\nexport async function provisionDeclared(\n\toptions: DeclaredOptions,\n): Promise<DeclaredResult> {\n\tconst { workspace } = options;\n\tconst empty: DeclaredResult = {\n\t\tenv: {},\n\t\tstatements: [],\n\t\tprovisioned: {},\n\t\tclusters: {},\n\t};\n\n\tconst manifest =\n\t\toptions.manifest ??\n\t\t(await discover({\n\t\t\tpatterns: constructGlobs(workspace),\n\t\t\tcwd: workspace.root,\n\t\t}));\n\n\tif (Object.keys(manifest).length === 0) return empty;\n\n\tconst context: DokployProvisionContext = {\n\t\tmanifest,\n\t\tprovisioned: {},\n\t\tapi: options.api,\n\t\tprojectId: options.projectId,\n\t\tenvironmentId: options.environmentId,\n\t\tstage: options.stage,\n\t\tproject: workspace.name,\n\t\tscope: options.scope ?? workspace.name,\n\t\t// Every backend from the target this deploy goes to, and from nothing\n\t\t// else — the same answer reconcile gave locally.\n\t\tcache: cacheBackendFor(providerOf(workspace)),\n\t\tevents: eventsBackendFor(providerOf(workspace)),\n\t\tstorage: storageBackendFor(providerOf(workspace)),\n\t\t...(options.devServices ? { devServices: options.devServices } : {}),\n\t\t...(workspace.deploy?.domains?.[options.stage]\n\t\t\t? { domain: workspace.deploy.domains[options.stage] }\n\t\t\t: {}),\n\t\taddresses: surfaceAddresses(manifest, options.appUrls),\n\t\tseed: options.seed,\n\t\t...(options.supplied ? { supplied: options.supplied } : {}),\n\t\tdeferred: [],\n\t\tclusters: {},\n\t};\n\n\tconst env: Record<string, string> = {};\n\n\t// Parents first. A derived construct reads its parent's resolved URL, and\n\t// `provisionOrder` is what guarantees there is one to read.\n\tfor (const id of carriersLast(provisionOrder(manifest), manifest)) {\n\t\tconst declaration = manifest[id];\n\t\tif (!declaration) continue;\n\n\t\tconst provisioner = provisionerFor(declaration.kind);\n\n\t\t// A kind this target cannot provision yet is skipped rather than fatal.\n\t\t// Mail and buckets are not among them: a deployed stage's are its own,\n\t\t// from its secrets — and `validate` has refused one that lacks them.\n\t\tif (!provisioner) continue;\n\n\t\tconst result = await provisioner(declaration, context);\n\t\tcontext.provisioned[id] = result;\n\t\tObject.assign(env, result.provides);\n\t}\n\n\treturn {\n\t\tenv,\n\t\tstatements: context.deferred.map((statement) => ({\n\t\t\tid: statement.id,\n\t\t\tdescribe: statement.describe,\n\t\t\t...(statement.database ? { database: statement.database } : {}),\n\t\t\t...(statement.exists ? { exists: statement.exists } : {}),\n\t\t\t// `create` is what the applier calls it — the same convergent applier\n\t\t\t// the local target runs, so a statement that already applied reports\n\t\t\t// unchanged here exactly as it does there.\n\t\t\tcreate: statement.sql,\n\t\t})),\n\t\tprovisioned: context.provisioned,\n\t\tclusters: context.clusters,\n\t};\n}\n\n/**\n * Run the deferred DDL against a cluster that is now reachable.\n *\n * The same applier the local target uses: every statement asks whether it is\n * needed first, so a redeploy is free and a half-applied run recovers by being\n * run again.\n */\nexport async function applyDeclared(\n\tclient: SqlClient,\n\tstatements: readonly Statement[],\n): Promise<number> {\n\tconst applied = await applyPostgres(client, statements);\n\n\treturn applied.filter((entry) => entry.created).length;\n}\n\n/**\n * The provisioning order, with queues and topics moved to the end.\n *\n * `provisionOrder` walks `of` edges, and a carrier has none: a topic is not\n * *derived from* a database, because under SNS it does not live in one. Where\n * it lives is a fact about the backend, which is config — so the dependency is\n * real under pg-boss and absent under SNS, and writing it into the declaration\n * would state it in the one place that cannot know.\n *\n * Here it can. This runs where the backend is known, and the rule needs no\n * branch on it: nothing depends on a carrier. A queue's worker and a topic's\n * subscribers are *bound* to it rather than dependent on it, which is why\n * neither holds a key of its own — so a carrier can always go last, and under\n * pg-boss that is exactly late enough for the database it reads to be there.\n */\nfunction carriersLast(\n\tordered: readonly string[],\n\tmanifest: ConstructManifest,\n): string[] {\n\tconst carries = (id: string) => {\n\t\tconst kind = manifest[id]?.kind;\n\t\treturn kind === 'queue' || kind === 'topic';\n\t};\n\n\treturn [...ordered.filter((id) => !carries(id)), ...ordered.filter(carries)];\n}\n\n/**\n * Where each declared surface answers: its own app's address.\n *\n * Every surface is an app of its own, keyed by its id the way the derivation\n * keyed it — `Api` is `api`, `Webhooks` is `webhooks` — and answers on that\n * app's host, `{subdomain}.{domain}`. It used to be handed the first backend's\n * address, so a workspace with two APIs pointed both at the same one.\n */\nfunction surfaceAddresses(\n\tmanifest: ConstructManifest,\n\tappUrls: Readonly<Record<string, string>>,\n): Record<string, string> {\n\tconst addresses: Record<string, string> = {};\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (declaration.kind !== 'rest-api') continue;\n\t\tconst url = appUrls[appKey(id)];\n\t\tif (url) addresses[id] = url;\n\t}\n\n\treturn addresses;\n}\n","/**\n * DNS Provider Interface\n *\n * Abstracts DNS operations for different providers.\n * Built-in providers: HostingerProvider, Route53Provider\n * Users can also supply custom implementations.\n */\n\nimport type { z } from 'zod/v4';\nimport type {\n\tCloudflareDnsProviderSchema,\n\tCustomDnsProviderSchema,\n\tDnsProviderSchema,\n\tDnsRecordSchema,\n\tDnsRecordTypeSchema,\n\tHostingerDnsProviderSchema,\n\tManualDnsProviderSchema,\n\tRoute53DnsProviderSchema,\n\tUpsertDnsRecordSchema,\n\tUpsertResultSchema,\n} from '../../../workspace/schema';\n\n// =============================================================================\n// DNS Record Types (derived from Zod schemas)\n// =============================================================================\n\n/**\n * DNS record types supported across providers.\n */\nexport type DnsRecordType = z.infer<typeof DnsRecordTypeSchema>;\n\n/**\n * A DNS record as returned by the provider.\n */\nexport type DnsRecord = z.infer<typeof DnsRecordSchema>;\n\n/**\n * A DNS record to create or update.\n */\nexport type UpsertDnsRecord = z.infer<typeof UpsertDnsRecordSchema>;\n\n/**\n * Result of an upsert operation.\n */\nexport type UpsertResult = z.infer<typeof UpsertResultSchema>;\n\n// =============================================================================\n// DNS Provider Interface\n// =============================================================================\n\n/**\n * A record to delete from DNS.\n */\nexport interface DeleteDnsRecord {\n\t/** Record name/subdomain (e.g., 'api' or '@' for root) */\n\tname: string;\n\t/** Record type (A, CNAME, etc.) */\n\ttype: DnsRecordType;\n}\n\n/**\n * Result of a delete operation.\n */\nexport interface DeleteResult {\n\t/** The record that was requested for deletion */\n\trecord: DeleteDnsRecord;\n\t/** Whether the record was deleted */\n\tdeleted: boolean;\n\t/** Whether the record was not found (already deleted) */\n\tnotFound: boolean;\n\t/** Error message if deletion failed */\n\terror?: string;\n}\n\n/**\n * Interface for DNS providers.\n *\n * Implementations must handle:\n * - Getting all records for a domain\n * - Creating or updating records for a domain\n * - Deleting records from a domain\n */\nexport interface DnsProvider {\n\t/** Provider name for logging */\n\treadonly name: string;\n\n\t/**\n\t * Get all DNS records for a domain.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @returns Array of DNS records\n\t */\n\tgetRecords(domain: string): Promise<DnsRecord[]>;\n\n\t/**\n\t * Create or update DNS records.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @param records - Records to create or update\n\t * @returns Results of the upsert operations\n\t */\n\tupsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]>;\n\n\t/**\n\t * Delete DNS records.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @param records - Records to delete\n\t * @returns Results of the delete operations\n\t */\n\tdeleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]>;\n}\n\n// =============================================================================\n// DNS Provider Config Types (derived from Zod schemas)\n// =============================================================================\n\nexport type HostingerDnsConfig = z.infer<typeof HostingerDnsProviderSchema>;\nexport type Route53DnsConfig = z.infer<typeof Route53DnsProviderSchema>;\nexport type CloudflareDnsConfig = z.infer<typeof CloudflareDnsProviderSchema>;\nexport type ManualDnsConfig = z.infer<typeof ManualDnsProviderSchema>;\nexport type CustomDnsConfig = z.infer<typeof CustomDnsProviderSchema>;\n/** Single DNS provider config (for one domain) */\nexport type DnsConfig = z.infer<typeof DnsProviderSchema>;\n\n// =============================================================================\n// DNS Provider Factory\n// =============================================================================\n\n/**\n * Check if value is a DnsProvider implementation.\n */\nexport function isDnsProvider(value: unknown): value is DnsProvider {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as DnsProvider).name === 'string' &&\n\t\ttypeof (value as DnsProvider).getRecords === 'function' &&\n\t\ttypeof (value as DnsProvider).upsertRecords === 'function' &&\n\t\ttypeof (value as DnsProvider).deleteRecords === 'function'\n\t);\n}\n\nexport interface CreateDnsProviderOptions {\n\t/** DNS config from workspace */\n\tconfig: DnsConfig;\n}\n\n/**\n * Create a DNS provider based on configuration.\n *\n * - 'hostinger': HostingerProvider\n * - 'route53': Route53Provider\n * - 'manual': Returns null (user handles DNS)\n * - Custom: Use provided DnsProvider implementation\n */\nexport async function createDnsProvider(\n\toptions: CreateDnsProviderOptions,\n): Promise<DnsProvider | null> {\n\tconst { config } = options;\n\n\t// Manual mode - no provider needed\n\tif (config.provider === 'manual') {\n\t\treturn null;\n\t}\n\n\t// Custom provider implementation\n\tif (isDnsProvider(config.provider)) {\n\t\treturn config.provider;\n\t}\n\n\t// Built-in providers\n\tconst provider = config.provider;\n\n\tif (provider === 'hostinger') {\n\t\tconst { HostingerProvider } = await import('./HostingerProvider');\n\t\treturn new HostingerProvider();\n\t}\n\n\tif (provider === 'route53') {\n\t\tconst { Route53Provider } = await import('./Route53Provider');\n\t\tconst route53Config = config as Route53DnsConfig;\n\t\treturn new Route53Provider({\n\t\t\tregion: route53Config.region,\n\t\t\tprofile: route53Config.profile,\n\t\t\thostedZoneId: route53Config.hostedZoneId,\n\t\t});\n\t}\n\n\tif (provider === 'cloudflare') {\n\t\tthrow new Error('Cloudflare DNS provider not yet implemented');\n\t}\n\n\tthrow new Error(`Unknown DNS provider: ${JSON.stringify(config)}`);\n}\n","/**\n * DNS orchestration for deployments\n *\n * Handles automatic DNS record creation for deployed applications.\n */\n\nimport { lookup } from 'node:dns/promises';\nimport {\n\ttype DokployStageState,\n\tisDnsVerified,\n\tsetDnsRecord,\n\tsetDnsVerification,\n} from '../../../deploy/state';\nimport { output } from '../../../output';\nimport type {\n\tDnsConfig,\n\tDnsProvider as DnsProviderConfig,\n} from '../../../workspace/types';\nimport {\n\tcreateDnsProvider,\n\ttype DnsProvider,\n\ttype DnsConfig as SchemaDnsConfig,\n\ttype UpsertDnsRecord,\n} from './DnsProvider';\n\nconst logger = output;\n\n/**\n * Check if DNS config is legacy format (single domain with `domain` property)\n */\nexport function isLegacyDnsConfig(\n\tconfig: DnsConfig,\n): config is SchemaDnsConfig & { domain: string } {\n\treturn (\n\t\ttypeof config === 'object' &&\n\t\tconfig !== null &&\n\t\t'provider' in config &&\n\t\t'domain' in config\n\t);\n}\n\n/**\n * Normalize DNS config to new multi-domain format\n */\nexport function normalizeDnsConfig(\n\tconfig: DnsConfig,\n): Record<string, DnsProviderConfig> {\n\tif (isLegacyDnsConfig(config)) {\n\t\t// Convert legacy format to new format\n\t\tconst { domain, ...providerConfig } = config;\n\t\treturn { [domain]: providerConfig as DnsProviderConfig };\n\t}\n\treturn config as Record<string, DnsProviderConfig>;\n}\n\n/**\n * Find the root domain for a hostname from available DNS configs\n *\n * @example\n * findRootDomain('api.geekmidas.com', { 'geekmidas.com': {...}, 'geekmidas.dev': {...} })\n * // Returns 'geekmidas.com'\n */\nexport function findRootDomain(\n\thostname: string,\n\tdnsConfig: Record<string, DnsProviderConfig>,\n): string | null {\n\t// Sort domains by length descending to match most specific first\n\tconst domains = Object.keys(dnsConfig).sort((a, b) => b.length - a.length);\n\n\tfor (const domain of domains) {\n\t\tif (hostname === domain || hostname.endsWith(`.${domain}`)) {\n\t\t\treturn domain;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Group hostnames by their root domain\n */\nexport function groupHostnamesByDomain(\n\tappHostnames: Map<string, string>,\n\tdnsConfig: Record<string, DnsProviderConfig>,\n): Map<string, Map<string, string>> {\n\tconst grouped = new Map<string, Map<string, string>>();\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\tconst rootDomain = findRootDomain(hostname, dnsConfig);\n\t\tif (!rootDomain) {\n\t\t\tlogger.log(` ⚠ No DNS config found for hostname: ${hostname}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!grouped.has(rootDomain)) {\n\t\t\tgrouped.set(rootDomain, new Map());\n\t\t}\n\t\tgrouped.get(rootDomain)!.set(appName, hostname);\n\t}\n\n\treturn grouped;\n}\n\n/**\n * Required DNS record for an app\n */\nexport interface RequiredDnsRecord {\n\t/** Full hostname (e.g., 'api.joemoer.traflabs.io') */\n\thostname: string;\n\t/** Subdomain part for the DNS provider (e.g., 'api.joemoer') */\n\tsubdomain: string;\n\t/** Record type */\n\ttype: 'A' | 'CNAME';\n\t/** Target value (IP or hostname) */\n\tvalue: string;\n\t/** App name */\n\tappName: string;\n\t/** Whether the record was created */\n\tcreated?: boolean;\n\t/** Whether the record already existed */\n\texisted?: boolean;\n\t/** Error if creation failed */\n\terror?: string;\n}\n\n/**\n * Result of DNS record creation\n */\nexport interface DnsCreationResult {\n\trecords: RequiredDnsRecord[];\n\tsuccess: boolean;\n\tserverIp: string;\n}\n\n/**\n * Resolve IP address from a hostname\n */\nexport async function resolveHostnameToIp(hostname: string): Promise<string> {\n\ttry {\n\t\tconst addresses = await lookup(hostname, { family: 4 });\n\t\treturn addresses.address;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to resolve IP for ${hostname}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n}\n\n/**\n * Extract subdomain from full hostname relative to root domain\n *\n * @example\n * extractSubdomain('api.joemoer.traflabs.io', 'traflabs.io') => 'api.joemoer'\n * extractSubdomain('joemoer.traflabs.io', 'traflabs.io') => 'joemoer'\n */\nexport function extractSubdomain(hostname: string, rootDomain: string): string {\n\tif (!hostname.endsWith(rootDomain)) {\n\t\tthrow new Error(\n\t\t\t`Hostname ${hostname} is not under root domain ${rootDomain}`,\n\t\t);\n\t}\n\n\tconst subdomain = hostname.slice(0, -(rootDomain.length + 1)); // +1 for the dot\n\treturn subdomain || '@'; // '@' represents the root domain itself\n}\n\n/**\n * Generate required DNS records for a deployment\n */\nexport function generateRequiredRecords(\n\tappHostnames: Map<string, string>, // appName -> hostname\n\trootDomain: string,\n\tserverIp: string,\n): RequiredDnsRecord[] {\n\tconst records: RequiredDnsRecord[] = [];\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\tconst subdomain = extractSubdomain(hostname, rootDomain);\n\t\trecords.push({\n\t\t\thostname,\n\t\t\tsubdomain,\n\t\t\ttype: 'A',\n\t\t\tvalue: serverIp,\n\t\t\tappName,\n\t\t});\n\t}\n\n\treturn records;\n}\n\n/**\n * Print DNS records table\n */\nexport function printDnsRecordsTable(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n): void {\n\tlogger.log(`\\n 📋 DNS Records for ${rootDomain}:`);\n\tlogger.log(\n\t\t' ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐',\n\t);\n\tlogger.log(\n\t\t' │ Subdomain │ Type │ Value │ Status │',\n\t);\n\tlogger.log(\n\t\t' ├─────────────────────────────────────┼──────┼─────────────────┼────────┤',\n\t);\n\n\tfor (const record of records) {\n\t\tconst subdomain = record.subdomain.padEnd(35);\n\t\tconst type = record.type.padEnd(4);\n\t\tconst value = record.value.padEnd(15);\n\t\tlet status: string;\n\n\t\tif (record.error) {\n\t\t\tstatus = '✗';\n\t\t} else if (record.created) {\n\t\t\tstatus = '✓ new';\n\t\t} else if (record.existed) {\n\t\t\tstatus = '✓';\n\t\t} else {\n\t\t\tstatus = '?';\n\t\t}\n\n\t\tlogger.log(\n\t\t\t` │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t' └─────────────────────────────────────┴──────┴─────────────────┴────────┘',\n\t);\n}\n\n/**\n * Print DNS records in a simple format for manual setup\n */\nexport function printDnsRecordsSimple(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n): void {\n\tlogger.log('\\n 📋 Required DNS Records:');\n\tlogger.log(` Add these A records to your DNS provider (${rootDomain}):\\n`);\n\n\tfor (const record of records) {\n\t\tlogger.log(` ${record.subdomain} → ${record.value} (A record)`);\n\t}\n\n\tlogger.log('');\n}\n\n/**\n * Create DNS records for a single domain using its configured provider\n */\nexport async function createDnsRecordsForDomain(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n\tproviderConfig: DnsProviderConfig,\n): Promise<RequiredDnsRecord[]> {\n\t// Get TTL from config, default to 300. Manual mode doesn't have ttl property.\n\tconst ttl =\n\t\t'ttl' in providerConfig && providerConfig.ttl ? providerConfig.ttl : 300;\n\n\t// Get DNS provider from factory\n\tlet provider: DnsProvider | null;\n\ttry {\n\t\t// Cast to schema-derived DnsConfig for provider factory\n\t\tprovider = await createDnsProvider({\n\t\t\tconfig: providerConfig as SchemaDnsConfig,\n\t\t});\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(\n\t\t\t` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`,\n\t\t);\n\t\treturn records.map((r) => ({ ...r, error: message }));\n\t}\n\n\t// Manual mode - no provider, just mark records as needing manual creation\n\tif (!provider) {\n\t\treturn records.map((r) => ({ ...r, created: false, existed: false }));\n\t}\n\n\tconst results: RequiredDnsRecord[] = [];\n\n\t// Convert RequiredDnsRecord to UpsertDnsRecord format\n\tconst upsertRecords: UpsertDnsRecord[] = records.map((r) => ({\n\t\tname: r.subdomain,\n\t\ttype: r.type,\n\t\tttl,\n\t\tvalue: r.value,\n\t}));\n\n\ttry {\n\t\t// Use provider to upsert records\n\t\tconst upsertResults = await provider.upsertRecords(\n\t\t\trootDomain,\n\t\t\tupsertRecords,\n\t\t);\n\n\t\t// Map results back to RequiredDnsRecord format\n\t\tfor (const [i, record] of records.entries()) {\n\t\t\tconst result = upsertResults[i];\n\n\t\t\t// Handle case where upsertResults has fewer items (shouldn't happen but be safe)\n\t\t\tif (!result) {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\terror: 'No result returned from provider',\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (result.unchanged) {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\texisted: true,\n\t\t\t\t\tcreated: false,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\tcreated: result.created,\n\t\t\t\t\texisted: !result.created,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(\n\t\t\t` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`,\n\t\t);\n\t\treturn records.map((r) => ({\n\t\t\thostname: r.hostname,\n\t\t\tsubdomain: r.subdomain,\n\t\t\ttype: r.type,\n\t\t\tvalue: r.value,\n\t\t\tappName: r.appName,\n\t\t\terror: message,\n\t\t}));\n\t}\n\n\treturn results;\n}\n\n/**\n * Create DNS records using the configured provider\n * @deprecated Use createDnsRecordsForDomain for multi-domain support\n */\nexport async function createDnsRecords(\n\trecords: RequiredDnsRecord[],\n\tdnsConfig: DnsConfig,\n): Promise<RequiredDnsRecord[]> {\n\t// Handle legacy config format\n\tif (!isLegacyDnsConfig(dnsConfig)) {\n\t\tthrow new Error(\n\t\t\t'createDnsRecords requires legacy DnsConfig with domain property. Use createDnsRecordsForDomain instead.',\n\t\t);\n\t}\n\tconst { domain: rootDomain, ...providerConfig } = dnsConfig;\n\treturn createDnsRecordsForDomain(\n\t\trecords,\n\t\trootDomain,\n\t\tproviderConfig as DnsProviderConfig,\n\t);\n}\n\n/**\n * Main DNS orchestration function for deployments\n *\n * Supports both legacy single-domain format and new multi-domain format:\n * - Legacy: { provider: 'hostinger', domain: 'example.com' }\n * - Multi: { 'example.com': { provider: 'hostinger' }, 'example.dev': { provider: 'route53' } }\n *\n * @param appHostnames - Map of app names to hostnames\n * @param dnsConfig - DNS configuration (legacy or multi-domain)\n * @param dokployEndpoint - Dokploy server endpoint to resolve IP from\n * @param state - Optional state to save created records for later deletion\n */\nexport async function orchestrateDns(\n\tappHostnames: Map<string, string>, // appName -> hostname\n\tdnsConfig: DnsConfig | undefined,\n\tdokployEndpoint: string,\n\tstate?: DokployStageState,\n): Promise<DnsCreationResult | null> {\n\tif (!dnsConfig) {\n\t\treturn null;\n\t}\n\n\t// Normalize config to multi-domain format\n\tconst normalizedConfig = normalizeDnsConfig(dnsConfig);\n\n\t// Resolve Dokploy server IP from endpoint\n\tlogger.log('\\n🌐 Setting up DNS records...');\n\tlet serverIp: string;\n\n\ttry {\n\t\tconst endpointUrl = new URL(dokployEndpoint);\n\t\tserverIp = await resolveHostnameToIp(endpointUrl.hostname);\n\t\tlogger.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(` ⚠ Failed to resolve server IP: ${message}`);\n\t\treturn null;\n\t}\n\n\t// Group hostnames by their root domain\n\tconst groupedHostnames = groupHostnamesByDomain(\n\t\tappHostnames,\n\t\tnormalizedConfig,\n\t);\n\n\tif (groupedHostnames.size === 0) {\n\t\tlogger.log(\n\t\t\t' No DNS records needed (no hostnames match configured domains)',\n\t\t);\n\t\treturn { records: [], success: true, serverIp };\n\t}\n\n\tconst allRecords: RequiredDnsRecord[] = [];\n\tlet hasFailures = false;\n\n\t// Process each domain group with its specific provider\n\tfor (const [rootDomain, domainHostnames] of groupedHostnames) {\n\t\tconst providerConfig = normalizedConfig[rootDomain];\n\t\tif (!providerConfig) {\n\t\t\tlogger.log(` ⚠ No provider config for ${rootDomain}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst providerName =\n\t\t\ttypeof providerConfig.provider === 'string'\n\t\t\t\t? providerConfig.provider\n\t\t\t\t: 'custom';\n\n\t\t// Generate required records for this domain\n\t\tconst requiredRecords = generateRequiredRecords(\n\t\t\tdomainHostnames,\n\t\t\trootDomain,\n\t\t\tserverIp,\n\t\t);\n\n\t\tif (requiredRecords.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Create records for this domain\n\t\tlogger.log(\n\t\t\t` Creating DNS records for ${rootDomain} (${providerName})...`,\n\t\t);\n\t\tconst domainRecords = await createDnsRecordsForDomain(\n\t\t\trequiredRecords,\n\t\t\trootDomain,\n\t\t\tproviderConfig,\n\t\t);\n\n\t\tallRecords.push(...domainRecords);\n\n\t\tconst created = domainRecords.filter((r) => r.created).length;\n\t\tconst existed = domainRecords.filter((r) => r.existed).length;\n\t\tconst failed = domainRecords.filter((r) => r.error).length;\n\n\t\tif (created > 0) {\n\t\t\tlogger.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);\n\t\t}\n\t\tif (existed > 0) {\n\t\t\tlogger.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);\n\t\t}\n\t\tif (failed > 0) {\n\t\t\tlogger.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);\n\t\t\thasFailures = true;\n\t\t}\n\n\t\t// Save created/existing records to state for later deletion during undeploy\n\t\tif (state) {\n\t\t\tfor (const record of domainRecords) {\n\t\t\t\tif (record.created || record.existed) {\n\t\t\t\t\tsetDnsRecord(state, {\n\t\t\t\t\t\tdomain: rootDomain,\n\t\t\t\t\t\tname: record.subdomain,\n\t\t\t\t\t\ttype: record.type,\n\t\t\t\t\t\tvalue: record.value,\n\t\t\t\t\t\tttl:\n\t\t\t\t\t\t\t'ttl' in providerConfig && providerConfig.ttl\n\t\t\t\t\t\t\t\t? providerConfig.ttl\n\t\t\t\t\t\t\t\t: 300,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Print summary table for this domain\n\t\tprintDnsRecordsTable(domainRecords, rootDomain);\n\n\t\t// If manual mode or some failed, print simple instructions\n\t\tif (providerConfig.provider === 'manual' || failed > 0) {\n\t\t\tprintDnsRecordsSimple(\n\t\t\t\tdomainRecords.filter((r) => !r.created && !r.existed),\n\t\t\t\trootDomain,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\trecords: allRecords,\n\t\tsuccess: !hasFailures,\n\t\tserverIp,\n\t};\n}\n\n/**\n * Result of DNS verification for a single hostname\n */\nexport interface DnsVerificationResult {\n\thostname: string;\n\tappName: string;\n\tverified: boolean;\n\tresolvedIp?: string;\n\texpectedIp: string;\n\terror?: string;\n\tskipped?: boolean; // True if already verified in state\n}\n\n/**\n * Verify DNS records resolve correctly after deployment.\n *\n * This function:\n * 1. Checks state for previously verified hostnames (skips if already verified with same IP)\n * 2. Attempts to resolve each hostname to an IP\n * 3. Compares resolved IP with expected server IP\n * 4. Updates state with verification results\n *\n * @param appHostnames - Map of app names to hostnames\n * @param serverIp - Expected IP address the hostnames should resolve to\n * @param state - Deploy state for caching verification results\n * @returns Array of verification results\n */\nexport async function verifyDnsRecords(\n\tappHostnames: Map<string, string>,\n\tserverIp: string,\n\tstate: DokployStageState,\n): Promise<DnsVerificationResult[]> {\n\tconst results: DnsVerificationResult[] = [];\n\n\tlogger.log('\\n🔍 Verifying DNS records...');\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\t// Check if already verified with same IP\n\t\tif (isDnsVerified(state, hostname, serverIp)) {\n\t\t\tlogger.log(` ✓ ${hostname} (previously verified)`);\n\t\t\tresults.push({\n\t\t\t\thostname,\n\t\t\t\tappName,\n\t\t\t\tverified: true,\n\t\t\t\texpectedIp: serverIp,\n\t\t\t\tskipped: true,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Attempt to resolve hostname\n\t\ttry {\n\t\t\tconst resolvedIp = await resolveHostnameToIp(hostname);\n\n\t\t\tif (resolvedIp === serverIp) {\n\t\t\t\t// DNS verified successfully\n\t\t\t\tsetDnsVerification(state, hostname, serverIp);\n\t\t\t\tlogger.log(` ✓ ${hostname} → ${resolvedIp}`);\n\t\t\t\tresults.push({\n\t\t\t\t\thostname,\n\t\t\t\t\tappName,\n\t\t\t\t\tverified: true,\n\t\t\t\t\tresolvedIp,\n\t\t\t\t\texpectedIp: serverIp,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// DNS resolves but to wrong IP\n\t\t\t\tlogger.log(\n\t\t\t\t\t` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`,\n\t\t\t\t);\n\t\t\t\tresults.push({\n\t\t\t\t\thostname,\n\t\t\t\t\tappName,\n\t\t\t\t\tverified: false,\n\t\t\t\t\tresolvedIp,\n\t\t\t\t\texpectedIp: serverIp,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// DNS resolution failed\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\t\tlogger.log(` ⚠ ${hostname} DNS not propagated (${message})`);\n\t\t\tresults.push({\n\t\t\t\thostname,\n\t\t\t\tappName,\n\t\t\t\tverified: false,\n\t\t\t\texpectedIp: serverIp,\n\t\t\t\terror: message,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Summary\n\tconst verified = results.filter((r) => r.verified).length;\n\tconst skipped = results.filter((r) => r.skipped).length;\n\tconst pending = results.filter((r) => !r.verified).length;\n\n\tif (pending > 0) {\n\t\tlogger.log(`\\n ${verified} verified, ${pending} pending propagation`);\n\t\tlogger.log(' DNS changes may take 5-30 minutes to propagate');\n\t} else if (skipped > 0) {\n\t\tlogger.log(` ${verified} verified (${skipped} from cache)`);\n\t}\n\n\treturn results;\n}\n","/**\n * Environment Variable Resolution for Dokploy Deployments\n *\n * Resolves sniffed environment variables to actual values during deployment.\n * Auto-supports common variables like DATABASE_URL, REDIS_URL, BETTER_AUTH_*,\n * and falls back to user-provided secrets.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport {\n\ttype DokployStageState,\n\tgetGeneratedSecret,\n\tsetGeneratedSecret,\n} from '../../deploy/state';\nimport type { StageSecrets } from '../../secrets/types';\nimport { stripPublicPrefix } from '../../workspace/publicEnv';\nimport type { NormalizedAppConfig } from '../../workspace/types';\n\n/**\n * Context needed for environment variable resolution\n */\nexport interface EnvResolverContext {\n\t/** The app being deployed */\n\tapp: NormalizedAppConfig;\n\t/** The app name */\n\tappName: string;\n\t/** Deployment stage (production, staging, development) */\n\tstage: string;\n\t/** Deploy state (for persisting generated secrets) */\n\tstate: DokployStageState;\n\t/** Public hostname for this app */\n\tappHostname: string;\n\t/** All frontend app URLs (for BETTER_AUTH_TRUSTED_ORIGINS) */\n\tfrontendUrls: string[];\n\t/** User-provided secrets from secrets store */\n\tuserSecrets?: StageSecrets;\n\t/** Master key for runtime decryption (optional) */\n\tmasterKey?: string;\n\t/** URLs of deployed dependency apps (e.g., { auth: 'https://auth.example.com' }) */\n\tdependencyUrls?: Record<string, string>;\n}\n\n/**\n * Result of environment variable resolution\n */\nexport interface EnvResolutionResult {\n\t/** Successfully resolved environment variables */\n\tresolved: Record<string, string>;\n\t/** Environment variable names that could not be resolved */\n\tmissing: string[];\n}\n\n/**\n * Auto-supported environment variable names\n */\nexport const AUTO_SUPPORTED_VARS = [\n\t'PORT',\n\t'NODE_ENV',\n\t'STAGE',\n\t'DATABASE_URL',\n\t'REDIS_URL',\n\t'BETTER_AUTH_URL',\n\t'BETTER_AUTH_SECRET',\n\t'BETTER_AUTH_TRUSTED_ORIGINS',\n\t'GKM_MASTER_KEY',\n] as const;\n\nexport type AutoSupportedVar = (typeof AUTO_SUPPORTED_VARS)[number];\n\n/**\n * Check if a variable name is auto-supported\n */\nexport function isAutoSupportedVar(\n\tvarName: string,\n): varName is AutoSupportedVar {\n\treturn AUTO_SUPPORTED_VARS.includes(varName as AutoSupportedVar);\n}\n\n/**\n * Generate a secure random secret (64 hex characters = 32 bytes)\n */\nexport function generateSecret(): string {\n\treturn randomBytes(32).toString('hex');\n}\n\n/**\n * Get or generate a secret for an app.\n * If the secret already exists in state, returns it.\n * Otherwise generates a new one and stores it.\n */\nexport function getOrGenerateSecret(\n\tstate: DokployStageState,\n\tappName: string,\n\tsecretName: string,\n): string {\n\t// Check if already generated\n\tconst existing = getGeneratedSecret(state, appName, secretName);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\t// Generate new secret\n\tconst generated = generateSecret();\n\n\t// Store in state for persistence\n\tsetGeneratedSecret(state, appName, secretName, generated);\n\n\treturn generated;\n}\n\n/**\n * Resolve a single environment variable\n */\nexport function resolveEnvVar(\n\tvarName: string,\n\tcontext: EnvResolverContext,\n): string | undefined {\n\t// Auto-supported variables\n\tswitch (varName) {\n\t\tcase 'PORT':\n\t\t\treturn String(context.app.port);\n\n\t\tcase 'NODE_ENV':\n\t\t\t// Always 'production' for deployed apps (gkm dev handles development mode)\n\t\t\treturn 'production';\n\n\t\tcase 'STAGE':\n\t\t\treturn context.stage;\n\n\t\tcase 'BETTER_AUTH_URL':\n\t\t\treturn `https://${context.appHostname}`;\n\n\t\tcase 'BETTER_AUTH_SECRET':\n\t\t\treturn getOrGenerateSecret(\n\t\t\t\tcontext.state,\n\t\t\t\tcontext.appName,\n\t\t\t\t'BETTER_AUTH_SECRET',\n\t\t\t);\n\n\t\tcase 'BETTER_AUTH_TRUSTED_ORIGINS':\n\t\t\tif (context.frontendUrls.length > 0) {\n\t\t\t\treturn context.frontendUrls.join(',');\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\n\t\tcase 'GKM_MASTER_KEY':\n\t\t\tif (context.masterKey) {\n\t\t\t\treturn context.masterKey;\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\t}\n\n\t// Check dependency URLs (e.g., AUTH_URL -> dependencyUrls.auth)\n\t// Also supports any known public prefix (NEXT_PUBLIC_, VITE_, ...) so\n\t// VITE_AUTH_URL and NEXT_PUBLIC_AUTH_URL both resolve to dependencyUrls.auth.\n\tif (context.dependencyUrls && varName.endsWith('_URL')) {\n\t\tconst stripped = stripPublicPrefix(varName) ?? varName;\n\t\tconst depName = stripped.slice(0, -4).toLowerCase();\n\n\t\tif (context.dependencyUrls[depName]) {\n\t\t\treturn context.dependencyUrls[depName];\n\t\t}\n\t}\n\n\t// Check user-provided secrets\n\tif (context.userSecrets) {\n\t\t// Check custom secrets first\n\t\tif (context.userSecrets.custom[varName]) {\n\t\t\treturn context.userSecrets.custom[varName];\n\t\t}\n\n\t\t// Check URLs (DATABASE_URL, REDIS_URL, …)\n\t\tif (varName in context.userSecrets.urls) {\n\t\t\treturn context.userSecrets.urls[\n\t\t\t\tvarName as keyof typeof context.userSecrets.urls\n\t\t\t];\n\t\t}\n\n\t\t// Check service-specific vars\n\t\tif (\n\t\t\tvarName === 'POSTGRES_PASSWORD' &&\n\t\t\tcontext.userSecrets.services.postgres\n\t\t) {\n\t\t\treturn context.userSecrets.services.postgres.password;\n\t\t}\n\t\tif (varName === 'REDIS_PASSWORD' && context.userSecrets.services.redis) {\n\t\t\treturn context.userSecrets.services.redis.password;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Resolve all environment variables for an app\n */\nexport function resolveEnvVars(\n\trequiredVars: string[],\n\tcontext: EnvResolverContext,\n): EnvResolutionResult {\n\tconst resolved: Record<string, string> = {};\n\tconst missing: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tconst value = resolveEnvVar(varName, context);\n\t\tif (value !== undefined) {\n\t\t\tresolved[varName] = value;\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn { resolved, missing };\n}\n\n/**\n * Format missing variables error message\n */\nexport function formatMissingVarsError(\n\tappName: string,\n\tmissing: string[],\n\tstage: string,\n): string {\n\tconst varList = missing.map((v) => ` - ${v}`).join('\\n');\n\treturn (\n\t\t`Deployment failed: ${appName} is missing required environment variables:\\n` +\n\t\t`${varList}\\n\\n` +\n\t\t`Add them with:\\n` +\n\t\t` gkm secrets:set <VAR_NAME> <value> --stage ${stage}\\n\\n` +\n\t\t`Or add them to the app's requiredEnv in gkm.config.ts to have them auto-resolved.`\n\t);\n}\n\n/**\n * Validate that all required environment variables can be resolved\n */\nexport function validateEnvVars(\n\trequiredVars: string[],\n\tcontext: EnvResolverContext,\n): { valid: boolean; missing: string[]; resolved: Record<string, string> } {\n\tconst { resolved, missing } = resolveEnvVars(requiredVars, context);\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing,\n\t\tresolved,\n\t};\n}\n","/**\n * Whether a released app answers.\n *\n * Dokploy finishing a deployment means the service was updated, not that the\n * process in it is serving: a container that exits on start, a missing\n * variable read at boot, a database it cannot reach all look like a finished\n * deployment. So an app counts as released once its own health route has\n * answered 2xx several times in a row — one lucky answer from a container\n * about to crash-loop is not enough.\n */\n\nimport type { TargetEvent } from '../types';\n\n/** What the health check of one app is. */\nexport interface HealthCheck {\n\tapp: string;\n\t/** `https://<host><path>`. */\n\turl: string;\n\t/** Consecutive 2xx answers that make the app healthy. */\n\thealthyAfter: number;\n\t/** Between checks. */\n\tintervalMs: number;\n\t/** How long the app may take to become healthy. */\n\ttimeoutMs: number;\n\tsignal: AbortSignal;\n\temit: (event: TargetEvent) => void;\n}\n\n/** How long one request may take: a check that hangs is a failed check. */\nconst REQUEST_TIMEOUT_MS = 10_000;\n\n/** An app never answered healthy enough times in a row. */\nexport class HealthCheckTimedOut extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly url: string,\n\t\treadonly timeoutMs: number,\n\t\t/** The last answer's status, or undefined when the last request failed. */\n\t\treadonly lastStatus: number | undefined,\n\t) {\n\t\tsuper(\n\t\t\t`${app} did not become healthy within ${Math.round(timeoutMs / 1000)}s: ${url} last ` +\n\t\t\t\t`${lastStatus === undefined ? 'did not answer' : `answered ${lastStatus}`}. ` +\n\t\t\t\t\"Check the app's logs in Dokploy. If it is only slow to start, raise deploy.dokploy.verify.healthTimeoutMs; \" +\n\t\t\t\t'if it serves its health route elsewhere, set deploy.dokploy.verify.healthCheckPath.',\n\t\t);\n\t\tthis.name = 'HealthCheckTimedOut';\n\t}\n}\n\n/** Wait `ms`, or reject with the signal's reason once it aborts. */\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal.aborted) return reject(signal.reason);\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timer);\n\t\t\treject(signal.reason);\n\t\t};\n\t\tconst timer = setTimeout(() => {\n\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t});\n}\n\n/** One request: its status, or undefined when it never answered. */\nasync function probe(\n\turl: string,\n\tsignal: AbortSignal,\n): Promise<number | undefined> {\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tsignal: AbortSignal.any([\n\t\t\t\tsignal,\n\t\t\t\tAbortSignal.timeout(REQUEST_TIMEOUT_MS),\n\t\t\t]),\n\t\t});\n\t\t// Only the status is read. Not awaited: a cancel can wait on a body\n\t\t// that never ends, and the check is already answered.\n\t\tresponse.body?.cancel().catch(() => {});\n\t\treturn response.status;\n\t} catch {\n\t\t// The run stopping is not a failed check.\n\t\tsignal.throwIfAborted();\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Check `url` until it answers 2xx `healthyAfter` times in a row, emitting\n * `health.checked` for every check.\n *\n * @throws {HealthCheckTimedOut} when that has not happened within `timeoutMs`.\n */\nexport async function verifyHealth(check: HealthCheck): Promise<void> {\n\tconst { app, url, healthyAfter, intervalMs, timeoutMs, signal, emit } = check;\n\tconst deadline = Date.now() + timeoutMs;\n\tlet consecutive = 0;\n\tlet attempt = 0;\n\n\twhile (true) {\n\t\tattempt++;\n\t\tconst status = await probe(url, signal);\n\t\tconst healthy = status !== undefined && status >= 200 && status < 300;\n\t\temit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp,\n\t\t\turl,\n\t\t\thealthy,\n\t\t\t...(status !== undefined ? { status } : {}),\n\t\t\tattempt,\n\t\t});\n\n\t\tconsecutive = healthy ? consecutive + 1 : 0;\n\t\tif (consecutive >= healthyAfter) return;\n\n\t\tif (Date.now() + intervalMs > deadline) {\n\t\t\tthrow new HealthCheckTimedOut(app, url, timeoutMs, status);\n\t\t}\n\t\tawait sleep(intervalMs, signal);\n\t}\n}\n","/**\n * A deployed stage's migrations, applied by the deploy that ships it.\n *\n * Where they run is the question. A one-off container on the Dokploy server\n * would sit on the database's own network, but there is nothing to run one\n * with: an app's image holds its bundle and not `gkm` or the migration files,\n * and Dokploy has no job that runs to completion and reports an exit code —\n * an application is a service it restarts. So they run where the rest of\n * the project's code does, in the deploy's sandbox, and reach the cluster the\n * way the role DDL already does: through an external port the deploy\n * publishes for the duration and closes again.\n *\n * The owner URLs cross into the sandbox as secret files, never variables: a\n * migration is the project's code, and anything it spawns inherits its\n * environment.\n */\n\nimport { join } from 'node:path';\nimport {\n\ttype ConstructManifest,\n\tmigrationTargets,\n\tprovideKey,\n} from '@geekmidas/manifest';\nimport { z } from 'zod';\nimport { migrationFiles } from '../../migrate/provider';\nimport { LocalSandbox } from '../../sandbox/local';\nimport { activeSandbox, type Sandbox } from '../../sandbox/sandbox';\nimport { runWorker } from '../../sandbox/worker';\n\n/** How long a stage's migrations may run before the deploy stops them. */\nexport const MIGRATIONS_TIMEOUT_MS = 15 * 60_000;\n\n/** The migrations of a deployed stage failed; the release stopped before any app. */\nexport class DeployMigrationsFailed extends Error {\n\tconstructor(\n\t\treadonly stage: string,\n\t\t/** The failure's class name in the sandbox — `MigrationFailed`, … */\n\t\treadonly reason: string,\n\t\tmessage: string,\n\t) {\n\t\tsuper(\n\t\t\t`Migrating \"${stage}\" failed, so no app was released: ${message}. ` +\n\t\t\t\t'Migrations applied before the failing one stay applied; fix it and deploy again.',\n\t\t);\n\t\tthis.name = 'DeployMigrationsFailed';\n\t}\n}\n\n/** One construct's migrations, as the sandbox reports them. */\nexport interface AppliedMigrations {\n\t/** Its folder: `db/database/migrations`. */\n\tmigrations: string;\n\tapplied: string[];\n}\n\n/**\n * The URLs a stage's migrations connect with, keyed as the migrator reads\n * them, grouped by the database their cluster serves — for the targets that\n * have a migration to apply. Empty when none does, so a deploy publishes\n * nothing for a project that has not written one.\n */\nexport async function migrationUrls(\n\troot: string,\n\tmanifest: ConstructManifest,\n\tenv: Readonly<Record<string, string>>,\n): Promise<Map<string, Record<string, string>>> {\n\tconst byDatabase = new Map<string, Record<string, string>>();\n\n\tfor (const target of migrationTargets(manifest)) {\n\t\tconst files = await migrationFiles(join(root, target.migrations));\n\t\tif (files.size === 0) continue;\n\n\t\t// The owner's, and the runtime one a `roles: false` database migrates\n\t\t// with — whichever the migrator asks for is there.\n\t\tfor (const role of ['ownerUrl', 'url']) {\n\t\t\tconst key = provideKey(target.id, role);\n\t\t\tconst url = env[key];\n\t\t\tif (!url) continue;\n\n\t\t\tconst database = new URL(url).pathname.slice(1);\n\t\t\tbyDatabase.set(database, { ...byDatabase.get(database), [key]: url });\n\t\t}\n\t}\n\n\treturn byDatabase;\n}\n\nconst answer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('migrated'),\n\t\truns: z.array(\n\t\t\tz.object({ migrations: z.string(), applied: z.array(z.string()) }),\n\t\t),\n\t}),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.looseObject({ name: z.string(), message: z.string() }),\n\t}),\n]);\n\nexport interface RunMigrationsOptions {\n\troot: string;\n\tstage: string;\n\tmanifest: ConstructManifest;\n\t/** The constructs globs, for where each construct is declared. */\n\tpatterns: readonly string[];\n\t/** The URLs to migrate with, reachable from where the sandbox runs. */\n\turls: Readonly<Record<string, string>>;\n\tsignal: AbortSignal;\n\t/** Defaults to the run's own, else a `LocalSandbox` on `root`. */\n\tsandbox?: Sandbox;\n\ttimeoutMs?: number;\n}\n\n/** Apply every pending migration, in the sandbox, as each construct's owner. */\nexport async function runMigrations(\n\toptions: RunMigrationsOptions,\n): Promise<AppliedMigrations[]> {\n\tconst sandbox =\n\t\toptions.sandbox ??\n\t\tactiveSandbox() ??\n\t\tnew LocalSandbox({ root: options.root });\n\n\tconst { value } = await runWorker(sandbox, 'migrations', {\n\t\tname: 'migrate-worker',\n\t\targs: [\n\t\t\tJSON.stringify({\n\t\t\t\troot: options.root,\n\t\t\t\tmanifest: options.manifest,\n\t\t\t\tpatterns: options.patterns,\n\t\t\t}),\n\t\t],\n\t\tcwd: options.root,\n\t\ttimeoutMs: options.timeoutMs ?? MIGRATIONS_TIMEOUT_MS,\n\t\tsecrets: options.urls,\n\t\tsignal: options.signal,\n\t\tschema: answer,\n\t});\n\n\tif (value.reason === 'failed') {\n\t\tthrow new DeployMigrationsFailed(\n\t\t\toptions.stage,\n\t\t\tvalue.error.name,\n\t\t\tvalue.error.message,\n\t\t);\n\t}\n\treturn value.runs;\n}\n","/**\n * Reaching a Dokploy Postgres from where the deploy runs.\n *\n * A Dokploy Postgres answers on the server's Docker network and nowhere else:\n * its address is its service name, which only another container there\n * resolves. Two steps of a deploy need it from outside — the role DDL the\n * provisioners defer, and the migrations `release` applies — so the cluster\n * is published on an external port for exactly as long as they take, and\n * closed again whatever happens.\n */\n\nimport { createHash } from 'node:crypto';\nimport { Client as PgClient } from 'pg';\nimport { output } from '../../output';\nimport type { SqlClient, Statement } from '../../reconcile/provision.js';\nimport { applyDeclared } from './declared';\nimport type { DokployApi } from './dokploy-api';\nimport type { DokployCluster } from './fromManifest';\n\nconst logger = output;\n\n/** A Postgres published for the role DDL never accepted a connection. */\nexport class PostgresNotReady extends Error {\n\tconstructor(\n\t\treadonly host: string,\n\t\treadonly port: number,\n\t\treadonly attempts: number,\n\t) {\n\t\tsuper(\n\t\t\t`Postgres not ready after ${attempts} retries (${host}:${port}). Check that the port is reachable from here — a firewall in front of the server drops it silently — and deploy again.`,\n\t\t);\n\t\tthis.name = 'PostgresNotReady';\n\t}\n}\n\n/** No port could be published for a cluster, so its DDL cannot reach it. */\nexport class PostgresPortUnavailable extends Error {\n\tconstructor(\n\t\treadonly appName: string,\n\t\treadonly taken: readonly number[],\n\t) {\n\t\tsuper(\n\t\t\t`Could not publish a port for ${appName}. ` +\n\t\t\t\t`In use on this server: ${[...taken].sort((a, b) => a - b).join(', ') || 'none reported'}. ` +\n\t\t\t\t`The role DDL needs to reach the cluster from here.`,\n\t\t);\n\t\tthis.name = 'PostgresPortUnavailable';\n\t}\n}\n\n/**\n * Wait for Postgres to be ready to accept connections.\n *\n * Polls the Postgres server until it accepts a connection or max retries reached.\n * Used after enabling the external port to ensure the database is accessible\n * before creating users.\n *\n * @throws {PostgresNotReady} if Postgres is not ready after maxRetries\n */\nexport async function waitForPostgres(\n\thost: string,\n\tport: number,\n\tuser: string,\n\tpassword: string,\n\tdatabase: string,\n\tmaxRetries = 30,\n\tretryIntervalMs = 2000,\n): Promise<void> {\n\tfor (let i = 0; i < maxRetries; i++) {\n\t\ttry {\n\t\t\t// Bounded, because the interesting failure is not a refused connection\n\t\t\t// but a dropped one: while the container restarts around a port change,\n\t\t\t// the host drops the SYN rather than answering it, and an unbounded\n\t\t\t// connect waits out the OS timeout — a minute and a quarter — and then\n\t\t\t// reports ETIMEDOUT from inside a retry loop that never got to retry.\n\t\t\tconst client = new PgClient({\n\t\t\t\thost,\n\t\t\t\tport,\n\t\t\t\tuser,\n\t\t\t\tpassword,\n\t\t\t\tdatabase,\n\t\t\t\tconnectionTimeoutMillis: 5_000,\n\t\t\t});\n\t\t\t// A socket that dies *after* connecting emits on the client, and an\n\t\t\t// unhandled 'error' event takes the whole process down — which is how\n\t\t\t// a deploy went from \"retrying\" to a Node stack trace mid-run. The\n\t\t\t// retry loop below is the thing that decides what to do about it.\n\t\t\tclient.on('error', () => {});\n\t\t\tawait client.connect();\n\t\t\tawait client.end();\n\t\t\treturn;\n\t\t} catch {\n\t\t\tif (i < maxRetries - 1) {\n\t\t\t\tlogger.log(` Waiting for Postgres... (${i + 1}/${maxRetries})`);\n\t\t\t\tawait new Promise((r) => setTimeout(r, retryIntervalMs));\n\t\t\t}\n\t\t}\n\t}\n\tthrow new PostgresNotReady(host, port, maxRetries);\n}\n\n/**\n * A high port for one service, the same one every time.\n *\n * Derived from the service name rather than random so two deploys of the same\n * database agree and two different databases do not collide — and in the\n * ephemeral range, above anything a server is likely to have bound\n * deliberately.\n */\nfunction derivedPort(appName: string): number {\n\tconst digest = createHash('sha256').update(appName).digest();\n\n\treturn 49152 + (((digest[0]! << 8) | digest[1]!) % 16000);\n}\n\n/** A cluster reachable from here, until `close` is called. */\nexport interface PublishedPostgres {\n\tcluster: DokployCluster;\n\t/** The server's own hostname, where the port is published. */\n\thost: string;\n\tport: number;\n\t/**\n\t * Unpublish the port, if this opened it. Safe to call more than once; it\n\t * never throws — a port it cannot close is reported to close by hand.\n\t */\n\tclose(): Promise<void>;\n}\n\n/** The hostname of the Dokploy server, from its API endpoint. */\nexport function serverHostname(endpoint: string): string {\n\treturn new URL(endpoint).hostname;\n}\n\n/**\n * Publish `cluster` on an external port of the server at `host`, and wait\n * until it accepts a connection there.\n */\nexport async function publishPostgres(\n\tapi: DokployApi,\n\tcluster: DokployCluster,\n\thost: string,\n): Promise<PublishedPostgres> {\n\t// Reuse whatever is already published, and otherwise pick a high port that\n\t// nothing on the host is likely to hold.\n\t//\n\t// 5432 was hardcoded, which fails the moment a server runs a second Postgres\n\t// — and this one runs fourteen. The error is `Port 5432 is already in use`,\n\t// from Docker rather than from anything the deploy could anticipate.\n\tconst existing = await api\n\t\t.getPostgres(cluster.postgresId)\n\t\t.then((current) => current.externalPort)\n\t\t.catch(() => null);\n\n\t// 5432 first, then a derived port — and the order matters more than it looks.\n\t//\n\t// A high port is the tidier choice on a host running several clusters, and it\n\t// is also the one a firewall almost certainly drops: a VPS typically permits\n\t// 22, 80, 443 and whatever was opened deliberately. Publishing 55337 here\n\t// produced thirty polite retries against a port nothing outside could ever\n\t// reach, while 5432 had worked minutes earlier.\n\t//\n\t// So: the conventional port, which is the one an operator has plausibly\n\t// allowed, and a derived fallback only when something already holds it.\n\t// Already published? Use it. Re-saving the port a container already holds is\n\t// rejected by Docker as a conflict with *itself*, which reads like the port\n\t// being taken by something else.\n\tlet externalPort = existing ?? undefined;\n\tconst opened = externalPort === undefined;\n\n\tif (externalPort === undefined) {\n\t\t// Ask the server what it has bound rather than guessing and retrying. A\n\t\t// port free from here can be held by a service in another project, and\n\t\t// the failure names a container the caller has never heard of.\n\t\tconst taken = await api.publishedPorts().catch(() => new Set<number>());\n\n\t\t// 5432 first when it is free: it is conventional, and therefore the port\n\t\t// an operator has plausibly allowed through the firewall. Being *free* and\n\t\t// being *reachable* are different questions and only the first has an API.\n\t\tconst candidates = [5432, derivedPort(cluster.appName)].filter(\n\t\t\t(port) => !taken.has(port),\n\t\t);\n\n\t\tfor (const candidate of candidates) {\n\t\t\ttry {\n\t\t\t\tawait api.savePostgresExternalPort(cluster.postgresId, candidate);\n\t\t\t\texternalPort = candidate;\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tif (!message.includes('already in use')) throw error;\n\n\t\t\t\tlogger.log(` Port ${candidate} is taken; trying another...`);\n\t\t\t}\n\t\t}\n\n\t\tif (externalPort === undefined) {\n\t\t\tthrow new PostgresPortUnavailable(cluster.appName, [...taken]);\n\t\t}\n\n\t\tlogger.log(` Publishing ${cluster.appName} on ${externalPort}...`);\n\t}\n\n\tconst port = externalPort;\n\tlet closed = false;\n\t// Whatever happens after this, the database does not stay exposed. A port\n\t// opened to run DDL and left open is a database on the public internet —\n\t// which is what a failure part way used to leave behind.\n\tconst close = async () => {\n\t\t// Only what this call opened. A port somebody published deliberately is\n\t\t// theirs, and closing it would be a deploy quietly changing how their\n\t\t// database is reached.\n\t\tif (!opened || closed) return;\n\t\tclosed = true;\n\n\t\tawait api\n\t\t\t.savePostgresExternalPort(cluster.postgresId, null)\n\t\t\t.then(() => api.deployPostgres(cluster.postgresId))\n\t\t\t.catch(() => {\n\t\t\t\tlogger.log(\n\t\t\t\t\t` ⚠ Could not close external port ${port} on ${cluster.appName} — close it in Dokploy.`,\n\t\t\t\t);\n\t\t\t});\n\t};\n\n\ttry {\n\t\tawait api.deployPostgres(cluster.postgresId);\n\t\tawait waitForPostgres(\n\t\t\thost,\n\t\t\tport,\n\t\t\tcluster.databaseUser,\n\t\t\tcluster.databasePassword,\n\t\t\tcluster.databaseName,\n\t\t);\n\t} catch (error) {\n\t\tawait close();\n\t\tthrow error;\n\t}\n\n\treturn { cluster, host, port, close };\n}\n\n/**\n * A URL the cluster's containers use — its service name, its internal port —\n * pointed at where `published` answers from here instead.\n */\nexport function publishedUrl(\n\turl: string,\n\tpublished: PublishedPostgres,\n): string {\n\tconst parsed = new URL(url);\n\tparsed.hostname = published.host;\n\tparsed.port = String(published.port);\n\treturn parsed.toString();\n}\n\n/**\n * Run the manifest's DDL against a published Dokploy Postgres.\n *\n * The applier is the local target's, so every statement asks whether it is\n * needed first: a redeploy is free, and a half-applied run recovers by being\n * run again.\n */\nexport async function applyDeclaredStatements(\n\tpublished: PublishedPostgres,\n\tstatements: readonly Statement[],\n): Promise<number> {\n\tconst { cluster, host, port } = published;\n\n\t// As the cluster master, which is the only credential that exists before any\n\t// role does — the same reason the AWS bootstrap connects as one.\n\tconst client: SqlClient = {\n\t\tasync query(database, sql, values) {\n\t\t\tconst connection = new PgClient({\n\t\t\t\thost,\n\t\t\t\tport,\n\t\t\t\tuser: cluster.databaseUser,\n\t\t\t\tpassword: cluster.databasePassword,\n\t\t\t\tdatabase: database ?? cluster.databaseName,\n\t\t\t\tconnectionTimeoutMillis: 15_000,\n\t\t\t});\n\t\t\t// See `waitForPostgres`: the port is only reachable while published,\n\t\t\t// and the container restarts around that change, so the socket can\n\t\t\t// drop mid-statement. Swallowed here and surfaced by the awaited\n\t\t\t// call, which the retry can actually act on.\n\t\t\tconnection.on('error', () => {});\n\n\t\t\tawait connection.connect();\n\t\t\ttry {\n\t\t\t\tconst result = await connection.query(sql, values as never[]);\n\t\t\t\treturn result.rows;\n\t\t\t} finally {\n\t\t\t\tawait connection.end();\n\t\t\t}\n\t\t},\n\t};\n\n\t// Attempt, then wait for the cluster and attempt again.\n\t//\n\t// Publishing an external port *restarts* the container, and a TCP connect\n\t// succeeds against an instance that is still settling — so a pass can die\n\t// partway with `terminating connection due to administrator command`, or\n\t// with the connection dropped outright while the port rule is rewritten.\n\t// Retrying is safe because the applier is convergent: every statement asks\n\t// whether it is needed, so a later pass reapplies nothing an earlier one\n\t// managed. Three passes rather than two because the first restart and the\n\t// settling after it are separate events, and hitting both in one run is\n\t// ordinary rather than exceptional.\n\tlet lastError: unknown;\n\tfor (let attempt = 1; attempt <= 3; attempt++) {\n\t\ttry {\n\t\t\treturn await applyDeclared(client, statements);\n\t\t} catch (error) {\n\t\t\tlastError = error;\n\t\t\tif (attempt === 3) break;\n\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tlogger.log(\n\t\t\t\t` ⏳ Cluster still settling (${message}); retrying (${attempt}/2)...`,\n\t\t\t);\n\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10_000));\n\t\t\tawait waitForPostgres(\n\t\t\t\thost,\n\t\t\t\tport,\n\t\t\t\tcluster.databaseUser,\n\t\t\t\tcluster.databasePassword,\n\t\t\t\tcluster.databaseName,\n\t\t\t).catch(() => {});\n\t\t}\n\t}\n\n\tthrow lastError;\n}\n","/**\n * The Dokploy engine: what the built-in `dokploy` target runs, phase by phase.\n *\n * ```\n * gkm deploy --stage production\n * ├─ validate the stage's secrets, what each app reads\n * ├─ provision project, environment, registry; declared constructs —\n * │ each database's roles applied over a port published\n * │ for the purpose\n * ├─ release migrations (over that port, then closed); each backend\n * │ built, pushed, deployed and waited on, then checked;\n * │ then each site\n * ├─ verify each site checked\n * └─ rollback on a failed release or verify: what failed (or, atomic,\n * everything released) back on the image it ran before\n * ```\n *\n * Every app's database URL names its cluster's service on Dokploy's network,\n * never the server's public address; only the deploy reaches the cluster from\n * outside, and only while a step needs it.\n *\n * @module deploy\n */\n\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { type WorkerUnit, workerUnits } from '../../build/workers.js';\nimport {\n\ttype CredentialProvider,\n\tMissingCredential,\n} from '../../deploy/credentials';\nimport {\n\tassertExternalServices,\n\ttype DevService,\n\tdevServicesUsed,\n\tmanifestServiceDeclarations,\n\treportDevServices,\n} from '../../deploy/devServices.js';\nimport { deployDocker } from '../../deploy/docker';\nimport {\n\teventError,\n\ttype ResourceChange,\n\ttype ResourceVia,\n} from '../../deploy/events';\nimport { withGeneratedSecrets } from '../../deploy/generated.js';\nimport {\n\tapplicationName,\n\ttype DeployIdentity,\n\timageName,\n\timageRef as imageRefFor,\n\tprojectName,\n} from '../../deploy/identity.js';\nimport { DeployJournal } from '../../deploy/journal.js';\nimport { otelEnv } from '../../deploy/otel.js';\nimport {\n\tfindProject,\n\ttype ResolvedProject,\n\tresolveProject,\n} from '../../deploy/ownership.js';\nimport { resolveRegistry } from '../../deploy/registry.js';\nimport {\n\ttype StateStore,\n\tStateStoreBusy,\n\tStateVersionConflict,\n} from '../../deploy/StateStore.js';\nimport {\n\ttype EncryptedAppSecrets,\n\tgenerateSecretsReport,\n\tprepareSecretsForAllApps,\n\tprepareSecretsForApp,\n} from '../../deploy/secrets.js';\nimport { type SniffedEnvironment, sniffAllApps } from '../../deploy/sniffer.js';\nimport {\n\tcreateEmptyState,\n\ttype DeployedImage,\n\tgetBackupState,\n\trecordRelease,\n\trecordRollback,\n\tsetApplicationId,\n\tsetBackupState,\n\tsetPostgresBackupId,\n} from '../../deploy/state.js';\nimport type { AppDeployResult, DeployResult } from '../../deploy/types';\nimport { workerDockerfileOf } from '../../docker/index.js';\nimport { WORKER_PORT } from '../../docker/templates.js';\nimport { output } from '../../output';\nimport { workerEnvKeys } from '../../reconcile/apps.js';\nimport { constructGlobs } from '../../reconcile/workspace.js';\nimport type { RunOptions } 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 { derivedApps } from '../../workspace/derive.js';\nimport { getAppBuildOrder, getPublicEnvPrefix } from '../../workspace/index.js';\nimport type {\n\tDokployVerifyConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../../workspace/types.js';\nimport type {\n\tDeployFailure,\n\tDeployPhaseContext,\n\tDeploySecrets,\n\tTargetEvent,\n} from '../types';\nimport { provisionDeclared } from './declared';\nimport { orchestrateDns, verifyDnsRecords } from './dns/index.js';\nimport {\n\tDEFAULT_DEPLOYMENT_TIMEOUT_MS,\n\tDokployApi,\n\ttype DokployApplication,\n\ttype DokployRegistry,\n} from './dokploy-api';\nimport { isMainFrontendApp, resolveHost } from './domain.js';\nimport {\n\ttype EnvResolverContext,\n\tformatMissingVarsError,\n\tvalidateEnvVars,\n} from './env-resolver.js';\nimport type { DokployCluster } from './fromManifest';\nimport { verifyHealth } from './health';\nimport { migrationUrls, runMigrations } from './migrations';\nimport {\n\tapplyDeclaredStatements,\n\ttype PublishedPostgres,\n\tpublishedUrl,\n\tpublishPostgres,\n\tserverHostname,\n} from './postgres';\n\nexport { PostgresNotReady, PostgresPortUnavailable } from './postgres';\n\n// Through `output`: the console from the terminal, the run's own events\n// inside `deploy()`.\nconst logger = output;\n\n/**\n * Service URLs including both connection URLs and individual parameters\n */\ninterface ServiceUrls {\n\tDATABASE_URL?: string;\n\tDATABASE_HOST?: string;\n\tDATABASE_PORT?: string;\n\tDATABASE_NAME?: string;\n\tDATABASE_USER?: string;\n\tDATABASE_PASSWORD?: string;\n\tREDIS_URL?: string;\n\tREDIS_HOST?: string;\n\tREDIS_PORT?: string;\n\tREDIS_PASSWORD?: string;\n}\n\n/**\n * Result from provisioning services\n */\nexport interface ProvisionServicesResult {\n\tserviceUrls: ServiceUrls;\n\tserviceIds: {\n\t\tpostgresId?: string;\n\t\tredisId?: string;\n\t};\n}\n\n/**\n * The things this deploy creates a container for.\n *\n * A deploy unit is a *declaration*, not a config entry — and since that is now\n * true of every app, not just the ones being deployed, this is the workspace's\n * own derivation under the name the deploy phases call it by.\n */\nexport function deployUnits(\n\tmanifest: ConstructManifest,\n\tworkspace: NormalizedWorkspace,\n): Record<string, NormalizedAppConfig> {\n\treturn derivedApps(manifest, workspace);\n}\n\n/**\n * The variables an app cannot start without.\n *\n * The sniffer reports every key it saw in `requiredEnvVars` and says which of\n * them were read through `.optional()` or `.default()` in `optionalEnvVars`.\n * Reading only the first treats a key that is *absent by design* as a missing\n * secret — `AUTH_COOKIE_DOMAIN` is published only when a surface has a domain\n * to widen a cookie to, and one host has nothing to share it with.\n *\n * The same distinction `bundleServer` draws. It is drawn twice because the\n * bundle and the deploy each validate, and the deploy was the half still\n * failing on an answer that was correct.\n */\nfunction requiredOf(\n\trequirements:\n\t\t| { requiredEnvVars: string[]; optionalEnvVars: string[] }\n\t\t| undefined,\n): string[] {\n\tif (!requirements) return [];\n\n\tconst optional = new Set(requirements.optionalEnvVars);\n\n\treturn requirements.requiredEnvVars\n\t\t.map((name) => (name.endsWith('?') ? name.slice(0, -1) : name))\n\t\t.filter((name) => !optional.has(name));\n}\n\n/**\n * What the Dokploy engine is handed by its target: where its events go,\n * where it gets credentials, and whether it may change anything.\n */\ninterface DokployContext {\n\temit: (event: TargetEvent) => void;\n\tcredentials: CredentialProvider;\n\tsignal: AbortSignal;\n\t/** Look everything up, create, build and push nothing. */\n\tdryRun: boolean;\n\t/** Where docker's own output goes. Defaults to the terminal. */\n\tstdio?: RunOptions['stdio'];\n}\n\n/** A backend failed, so the run stopped before deploying anything after it. */\nexport class BackendDeployFailed extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Backend deployment failed for ${app}. Aborting to prevent partial deployment.`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'BackendDeployFailed';\n\t}\n}\n\n/**\n * Sites failed to release or to answer. Every site is attempted before this\n * is thrown, so one broken site does not keep the others back — but the run\n * fails, and what failed is rolled back.\n */\nexport class FrontendDeployFailed extends Error {\n\tconstructor(\n\t\treadonly apps: readonly string[],\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Frontend deployment failed for ${apps.join(', ')}: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'FrontendDeployFailed';\n\t}\n}\n\n/** An app's environment needs values the stage does not have. */\nexport class MissingEnvVars extends Error {\n\tconstructor(\n\t\treadonly app: string,\n\t\treadonly missing: readonly string[],\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(formatMissingVarsError(app, [...missing], stage));\n\t\tthis.name = 'MissingEnvVars';\n\t}\n}\n\n/** How `resolveProject` found a project, in the journal's words. */\nconst PROJECT_VIA: Record<ResolvedProject['via'], ResourceVia> = {\n\tstate: 'recorded',\n\tmarker: 'found',\n\tcreated: 'created',\n};\n\n/** `childOutput` as `spawn` reads it, where it is not the default. */\nconst CHILD_STDIO: Record<'stderr' | 'ignore', RunOptions['stdio']> = {\n\tstderr: ['ignore', 2, 2],\n\tignore: 'ignore',\n};\n\n/**\n * A Dokploy deploy in progress: what `validate` found, and what each later\n * phase adds for the next.\n */\nexport interface DokployRun {\n\tworkspace: NormalizedWorkspace;\n\tmanifest: ConstructManifest;\n\tstage: string;\n\timageTag: string;\n\tappsToDeployNames: string[];\n\tidentity: DeployIdentity;\n\tstore: StateStore;\n\tskipped: readonly { app: string; reason: string }[];\n\tsecrets: DeploySecrets;\n\tctx: DokployContext;\n\tpreflight: Preflight;\n\t/** How each release is waited for and checked. */\n\tverify: VerifySettings;\n\t/** Roll back every app the run released, not only the failed ones. */\n\tatomic: boolean;\n\t/** The dev services the stage may run for mail and buckets. */\n\tallowDevServices: readonly DevService[];\n\t/**\n\t * The Workers this run deploys — each with background work whose host app\n\t * is being deployed — as applications of their own, with no domain.\n\t */\n\tworkers: readonly WorkerUnit[];\n\t/** Each owner's runnables' edges, from discovery: what a worker reads. */\n\trunnables: Readonly<Record<string, readonly string[]>>;\n\tprovisioned?: Provisioned;\n\treleased?: Released;\n\t/** What the run changed live, for `rollback` to undo. */\n\treleasing: Releasing;\n\t/**\n\t * Clusters published for the migrations, by database: opened by\n\t * `provision` for the role DDL, closed by `release` once they have run.\n\t */\n\tpublished: Map<string, PublishedPostgres>;\n\tresult?: DeployResult;\n}\n\n/** `deploy.dokploy.verify`, with its defaults. */\nexport type VerifySettings = Required<DokployVerifyConfig>;\n\n/** The defaults of `deploy.dokploy.verify`. */\nexport function verifySettings(\n\tconfig: DokployVerifyConfig | undefined,\n): VerifySettings {\n\treturn {\n\t\tdeploymentTimeoutMs:\n\t\t\tconfig?.deploymentTimeoutMs ?? DEFAULT_DEPLOYMENT_TIMEOUT_MS,\n\t\thealthCheckPath: config?.healthCheckPath ?? '/health',\n\t\thealthyAfter: config?.healthyAfter ?? 3,\n\t\tintervalMs: config?.intervalMs ?? 2_000,\n\t\thealthTimeoutMs: config?.healthTimeoutMs ?? 5 * 60_000,\n\t};\n}\n\n/** What a run has changed live, app by app. */\ninterface Releasing {\n\t/**\n\t * Each app whose Dokploy application was pointed at a new image, with what\n\t * ran before — undefined for an app that had never been released.\n\t */\n\tswitched: Map<string, { applicationId: string; before?: DeployedImage }>;\n\t/** The apps that failed to release or to answer. */\n\tfailed: Set<string>;\n}\n\n/**\n * Deploy every app in a workspace to Dokploy: the engine under the built-in\n * `dokploy` target.\n *\n * Two-phase orchestration:\n * - PHASE 1: Deploy backend apps (with encrypted secrets)\n * - PHASE 2: Deploy frontend apps (with public URLs from backends)\n *\n * Security model:\n * - Backend apps get encrypted secrets embedded at build time\n * - Only GKM_MASTER_KEY is injected as Dokploy env var\n * - Frontend apps get public URLs baked in at build time (no secrets)\n *\n * The run around it — the target, the apps, the lock, the phase events — is\n * `runDeploy`'s. This says what it is doing and checks what Dokploy needs.\n *\n * @internal\n */\nexport async function validateDokploy(\n\tphase: DeployPhaseContext<unknown>,\n): Promise<DokployRun> {\n\tconst { workspace, stage, identity, tag: imageTag } = phase;\n\tconst ctx: DokployContext = {\n\t\temit: phase.emit,\n\t\tcredentials: phase.credentials,\n\t\tsignal: phase.signal,\n\t\tdryRun: phase.dryRun,\n\t\t...(phase.childOutput !== 'inherit'\n\t\t\t? { stdio: CHILD_STDIO[phase.childOutput] }\n\t\t\t: {}),\n\t};\n\n\tlogger.log(`\\n🚀 Deploying workspace \"${workspace.name}\" to Dokploy...`);\n\tlogger.log(` Stage: ${stage}`);\n\tlogger.log(` Tag: ${imageTag}`);\n\n\t// Every app asked for, in build order, including those another target\n\t// deploys: the line says what was asked, the skips below what was not done.\n\tconst askedFor = new Set([\n\t\t...phase.apps,\n\t\t...phase.skipped.map((skipped) => skipped.app),\n\t]);\n\tconst asked = getAppBuildOrder(workspace).filter((name) =>\n\t\taskedFor.has(name),\n\t);\n\tlogger.log(\n\t\tasked.length === Object.keys(workspace.apps).length\n\t\t\t? ` Deploying all apps: ${asked.join(', ')}`\n\t\t\t: ` Deploying apps: ${asked.join(', ')}`,\n\t);\n\tfor (const { app, reason } of phase.skipped) {\n\t\tlogger.log(` ⚠️ Skipping ${app}: ${reason}`);\n\t}\n\n\t// Mobile apps deploy via their own toolchain (e.g. EAS Build for Expo).\n\t// They stay in the list, for the line that says they were skipped.\n\tconst appsToDeployNames = [...phase.apps];\n\tfor (const name of appsToDeployNames) {\n\t\tif (workspace.apps[name]!.type === 'mobile') {\n\t\t\tphase.skip(name, MOBILE_SKIP_REASON);\n\t\t}\n\t}\n\n\tconst run = {\n\t\tworkspace,\n\t\tmanifest: phase.manifest,\n\t\tstage,\n\t\timageTag,\n\t\tappsToDeployNames,\n\t\tidentity,\n\t\tstore: phase.state,\n\t\tskipped: phase.skipped,\n\t\tsecrets: phase.secrets,\n\t\tctx,\n\t};\n\n\t// Mail and storage before anything else is read or written: a deployed\n\t// stage's are its own, from its secrets, unless a dev service is allowed\n\t// to stand in — and one missing any key stops here, naming every one.\n\tconst stored = await phase.secrets.read();\n\tconst services = assertExternalServices({\n\t\tstage,\n\t\tdeclarations: manifestServiceDeclarations(phase.manifest),\n\t\tsupplied: stored?.custom ?? {},\n\t\tallow: phase.allowDevServices,\n\t\t...(workspace.deploy?.domains?.[stage]\n\t\t\t? { domain: workspace.deploy.domains[stage] }\n\t\t\t: {}),\n\t});\n\treportDevServices(phase, devServicesUsed(services));\n\n\t// An address an older gkm stored for what a construct now provides: a\n\t// `localhost` URL is never where a deployed app finds anything.\n\tassertNoStaleSecrets({\n\t\tmanifest: phase.manifest,\n\t\tstage,\n\t\tsupplied: stored?.custom ?? {},\n\t});\n\n\t// A third party's credentials against their construct's schema, before\n\t// anything is built with one every app reading it would refuse.\n\tawait assertStageCredentials({\n\t\troot: workspace.root,\n\t\tpatterns: constructGlobs(workspace),\n\t\tmanifest: phase.manifest,\n\t\tstage,\n\t\tsupplied: stored?.custom ?? {},\n\t});\n\n\t// Which workers run, and what each reads: the runnables' edges and where\n\t// each worker's work is declared, from the run's own discovery.\n\tconst runnables = phase.runnables ?? {};\n\tconst background = phase.background ?? {};\n\tconst workers = workerUnits(workspace, phase.manifest, background).filter(\n\t\t(worker) => appsToDeployNames.includes(worker.app),\n\t);\n\tif (workers.length > 0) {\n\t\tlogger.log(\n\t\t\t` Deploying workers: ${workers.map((w) => `${w.name} (from ${w.app})`).join(', ')}`,\n\t\t);\n\t}\n\n\treturn {\n\t\t...run,\n\t\tallowDevServices: phase.allowDevServices,\n\t\tworkers,\n\t\trunnables,\n\t\tpreflight: await preflight(run),\n\t\tverify: verifySettings(workspace.deploy.dokploy?.verify),\n\t\tatomic: phase.atomic,\n\t\treleasing: { switched: new Map(), failed: new Set() },\n\t\tpublished: new Map(),\n\t};\n}\n\n/** What the preflight found: the stage's secrets and what each app reads. */\ninterface Preflight {\n\tstageSecrets: StageSecrets;\n\tsniffedApps: Map<string, SniffedEnvironment>;\n\tencryptedSecrets: Map<string, EncryptedAppSecrets>;\n}\n\n/**\n * The stage's secrets and every app's environment requirements. A dry run\n * reads the secrets and generates nothing into the store.\n */\nasync function preflight({\n\tworkspace,\n\tmanifest,\n\tstage,\n\tsecrets: secretsStore,\n\tctx,\n}: Pick<\n\tDokployRun,\n\t'workspace' | 'manifest' | 'stage' | 'secrets' | 'ctx'\n>): Promise<Preflight> {\n\tlogger.log('\\n🔐 Loading secrets and analyzing environment requirements...');\n\n\t// The stage's own store — SSM or Secrets Manager in its account, for a stage kept there —\n\t// read through the run, which masks every value from here on.\n\tconst stored = await secretsStore.read();\n\tif (!stored) {\n\t\tlogger.log(` ⚠️ No secrets found for stage \"${stage}\"; starting them`);\n\t}\n\n\t// What the stage generates once — its seed, each `secret` construct's\n\t// value — written back before anything is provisioned with it, so the next\n\t// deploy derives the same passwords and signs with the same key.\n\tconst { secrets: stageSecrets, generated } = withGeneratedSecrets(\n\t\tstored ?? initStageSecrets(stage),\n\t\tmanifest,\n\t);\n\tif (generated.length > 0) {\n\t\tif (ctx.dryRun) {\n\t\t\tlogger.log(\n\t\t\t\t` 🔑 Would generate for \"${stage}\" (${secretsStore.store}): ${generated.join(', ')}`,\n\t\t\t);\n\t\t} else {\n\t\t\tawait secretsStore.write(stageSecrets);\n\t\t\tlogger.log(\n\t\t\t\t` 🔑 Generated for \"${stage}\" (${secretsStore.store}): ${generated.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Sniff environment variables for all apps\n\tconst sniffedApps = await sniffAllApps(workspace.apps, workspace.root);\n\n\t// Prepare encrypted secrets for backend apps\n\tconst encryptedSecrets = stageSecrets\n\t\t? prepareSecretsForAllApps(stageSecrets, sniffedApps)\n\t\t: new Map<string, EncryptedAppSecrets>();\n\n\t// Report on secrets preparation\n\tif (stageSecrets) {\n\t\tconst report = generateSecretsReport(encryptedSecrets, sniffedApps);\n\t\tif (report.appsWithSecrets.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t` ✓ Encrypted secrets for: ${report.appsWithSecrets.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (report.appsWithMissingSecrets.length > 0) {\n\t\t\tfor (const { appName, missing } of report.appsWithMissingSecrets) {\n\t\t\t\tlogger.log(` ⚠️ ${appName}: Missing secrets: ${missing.join(', ')}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { stageSecrets, sniffedApps, encryptedSecrets };\n}\n\n/** What `provision` leaves for `release` and `verify`. */\ninterface Provisioned {\n\tapi: DokployApi;\n\tendpoint: string;\n\tjournal: DeployJournal;\n\tstate: DeployJournal['state'];\n\tprojectId: string;\n\tenvironmentId: string;\n\tregistry: string | undefined;\n\tregistryId: string;\n\tdeclaredEnv: Record<string, string>;\n\t/** Each declared cluster, by the database it serves. */\n\tdeclaredClusters: Record<string, DokployCluster>;\n\t/** The URLs `release` migrates with, by database; none when nothing is pending. */\n\tmigrations: Map<string, Record<string, string>>;\n\tchanges: ResourceChange[];\n\tapplied: Applied;\n}\n\n/** What `release` leaves for `verify` and the result. */\ninterface Released {\n\tresults: AppDeployResult[];\n\tpublicUrls: Record<string, string>;\n\tappHostnames: Map<string, string>;\n\t/** The apps whose domain exists, and so can be checked by name. */\n\tappDomainIds: Map<string, string>;\n\tapplicationIds: Map<string, string>;\n}\n\n/**\n * The project, environment and registry, then what the manifest declares.\n * Each is looked up — by the id the stage's state recorded, else by name —\n * before it is created, so a run stopped part way is finished by the next.\n */\nexport async function provisionDokploy(run: DokployRun): Promise<void> {\n\ttry {\n\t\tawait provision(run);\n\t} catch (error) {\n\t\t// A cluster kept published for the migrations is closed here when the\n\t\t// run never reaches them.\n\t\tawait closePublished(run);\n\t\tthrow error;\n\t}\n}\n\n/** Unpublish every cluster the run still has published. */\nasync function closePublished(run: DokployRun): Promise<void> {\n\tfor (const published of run.published.values()) await published.close();\n\trun.published.clear();\n}\n\nasync function provision(run: DokployRun): Promise<void> {\n\tconst {\n\t\tworkspace,\n\t\tmanifest,\n\t\tstage,\n\t\tappsToDeployNames,\n\t\tidentity,\n\t\tstore,\n\t\tctx,\n\t} = run;\n\tconst { stageSecrets } = run.preflight;\n\n\tconst changes: ResourceChange[] = [];\n\tconst applied: Applied = (change, via) => {\n\t\tchanges.push(change);\n\t\tctx.emit({ type: 'resource.applied', ...change, via });\n\t};\n\n\t// ==================================================================\n\t// SETUP: Credentials, Project, Registry\n\t// ==================================================================\n\tconst { api, endpoint } = await dokployApi(workspace, ctx);\n\n\t// ==================================================================\n\t// STATE: the stage's journal, written after every resource\n\t// ==================================================================\n\t// Before the project: the id it recorded is the first place the project is\n\t// looked for, and the only one that needs no ownership marker. A first\n\t// deploy writes an empty state now, so there is somewhere to record the\n\t// project before it is created.\n\tlogger.log('\\n📋 Loading deploy state...');\n\n\tconst journal = await DeployJournal.open(store, stage, () =>\n\t\tcreateEmptyState(stage, '', ''),\n\t);\n\tconst state = journal.state;\n\tif (journal.existed) {\n\t\tlogger.log(` Found existing state for stage \"${stage}\"`);\n\t} else {\n\t\tlogger.log(` Creating new state for stage \"${stage}\"`);\n\t}\n\tconst unfinished = journal.unfinished();\n\tif (unfinished.length > 0) {\n\t\tlogger.log(\n\t\t\t` ⚠ A previous run stopped while creating: ${unfinished.join(', ')} — looking for them before creating anything`,\n\t\t);\n\t}\n\n\t// Find or create the project this identity owns\n\tlogger.log('\\n📁 Setting up Dokploy project...');\n\tlogger.log(` Identity: ${identity.key}`);\n\tconst projectEntry = {\n\t\tkey: 'project',\n\t\ttype: 'project',\n\t\tdata: { name: projectName(identity), identity: identity.key },\n\t};\n\tconst project = await resolveProject(\n\t\tapi,\n\t\tidentity,\n\t\tstate.projectId || undefined,\n\t\t(message) => logger.log(message),\n\t\t{ beforeCreate: () => journal.pending(projectEntry) },\n\t);\n\tawait journal.ready(projectEntry, project.projectId);\n\tapplied(\n\t\t{\n\t\t\tkey: 'project',\n\t\t\tresourceType: 'project',\n\t\t\taction: project.via === 'created' ? 'create' : 'reuse',\n\t\t\tid: project.projectId,\n\t\t},\n\t\tPROJECT_VIA[project.via],\n\t);\n\n\tif (project.via === 'created') {\n\t\tlogger.log(` ✓ Created project: ${project.projectId}`);\n\t} else {\n\t\tlogger.log(` Found existing project: ${project.name}`);\n\t}\n\n\tconst environmentEntry = {\n\t\tkey: 'environment',\n\t\ttype: 'environment',\n\t\tdata: { name: stage },\n\t};\n\tconst environment = await journal.ensure(environmentEntry, {\n\t\t// By name, in the project just resolved: an environment id from state\n\t\t// may belong to a project this deploy no longer uses.\n\t\tfind: async () =>\n\t\t\tproject.environments.find(\n\t\t\t\t(e) => e.name.toLowerCase() === stage.toLowerCase(),\n\t\t\t),\n\t\tcreate: () => {\n\t\t\tlogger.log(` Creating \"${stage}\" environment...`);\n\t\t\treturn api.createEnvironment(project.projectId, stage);\n\t\t},\n\t\tid: (e) => e.environmentId,\n\t});\n\tconst environmentId = environment.resource.environmentId;\n\tapplied(\n\t\t{\n\t\t\tkey: 'environment',\n\t\t\tresourceType: 'environment',\n\t\t\taction: environment.via === 'created' ? 'create' : 'reuse',\n\t\t\tid: environmentId,\n\t\t},\n\t\tenvironment.via,\n\t);\n\tif (environment.via === 'created') {\n\t\tlogger.log(` ✓ Created environment: ${stage}`);\n\t} else {\n\t\tlogger.log(` Using environment: ${environment.resource.name}`);\n\t}\n\n\tif (journal.existed) {\n\t\t// Verify project ID matches (in case of recreation)\n\t\tif (state.projectId && state.projectId !== project.projectId) {\n\t\t\tlogger.log(` ⚠ Project ID changed, updating state`);\n\t\t}\n\t\t// Verify environment ID matches (in case of recreation)\n\t\tif (state.environmentId && state.environmentId !== environmentId) {\n\t\t\tlogger.log(` ⚠ Environment ID changed, updating state`);\n\t\t}\n\t}\n\tstate.projectId = project.projectId;\n\tstate.environmentId = environmentId;\n\tstate.identity = identity.key;\n\n\t// The registry Dokploy pulls through, kept with the stage\n\tlogger.log('\\n🐳 Checking registry...');\n\tconst registry = workspace.deploy.registry;\n\tlet registryCreated = false;\n\tconst dokployRegistry = await resolveRegistry(api, {\n\t\tstage,\n\t\tregistry,\n\t\tconfiguredId: workspace.deploy.dokploy?.registryId,\n\t\tstateId: state.registryId,\n\t\tlog: (message) => logger.log(message),\n\t\t// Dokploy has nothing for the configured registry, so it needs a login\n\t\t// to pull with — from the run's provider, never from a prompt here.\n\t\tcreate: async (url) => {\n\t\t\tconst login = await ctx.credentials.get(\n\t\t\t\t{ kind: 'registry', url },\n\t\t\t\t{ signal: ctx.signal },\n\t\t\t);\n\t\t\tif (!login) throw new MissingCredential('registry', url);\n\n\t\t\tconst created = await api.createRegistry(\n\t\t\t\t'Default Registry',\n\t\t\t\turl,\n\t\t\t\tlogin.username,\n\t\t\t\tlogin.password,\n\t\t\t);\n\t\t\tregistryCreated = true;\n\t\t\tlogger.log(` ✓ Registry created: ${created.registryId}`);\n\t\t\treturn created;\n\t\t},\n\t});\n\tconst registryId = dokployRegistry.registryId;\n\tstate.registryId = registryId;\n\tapplied(\n\t\t{\n\t\t\tkey: 'registry',\n\t\t\tresourceType: 'registry',\n\t\t\taction: registryCreated ? 'create' : 'reuse',\n\t\t\tid: registryId,\n\t\t},\n\t\tregistryCreated ? 'created' : 'found',\n\t);\n\tlogger.log(` Using registry: ${dokployRegistry.registryName}`);\n\tawait journal.save();\n\n\t// ==================================================================\n\t// Separate apps by type for two-phase deployment\n\t// ==================================================================\n\t// Mobile apps deploy via their own toolchain (e.g. EAS Build for Expo)\n\t// — skip them in the Dokploy deploy phases.\n\tconst skippedMobileApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'mobile',\n\t);\n\tif (skippedMobileApps.length > 0) {\n\t\tlogger.log(\n\t\t\t`\\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(', ')}`,\n\t\t);\n\t}\n\n\t// ==================================================================\n\t// The declared half: everything the construct manifest says exists\n\t// ==================================================================\n\t// Separate from the block above on purpose. That one deploys *applications*\n\t// — images, registries, domains — which a project has whether or not it\n\t// declares anything. This is what exists because the app said so, and it is\n\t// skipped entirely for a project that has not adopted the model.\n\t//\n\t// It runs before any application environment is saved, because the URLs it\n\t// resolves are what those applications read.\n\tlet declaredEnv: Record<string, string> = {};\n\t// The clusters the manifest provisioned, for anything downstream that needs\n\t// one — a backup schedule names a database, and that database is now\n\t// declared rather than configured.\n\tlet declaredClusters: Record<string, DokployCluster> = {};\n\t// What `release` migrates, by the database its cluster serves.\n\tlet migrations = new Map<string, Record<string, string>>();\n\n\t{\n\t\tlogger.log('\\n📦 Provisioning declared constructs...');\n\n\t\t// Every surface answers on its process's address, so the address has to\n\t\t// exist before the manifest is walked. Computed here rather than in the\n\t\t// app loop, which is where it used to be decided and is too late.\n\t\tconst appUrls: Record<string, string> = {};\n\t\tfor (const appName of appsToDeployNames) {\n\t\t\tif (workspace.apps[appName]?.type !== 'backend') continue;\n\t\t\tappUrls[appName] = `https://${hostOf(workspace, appName, stage)}`;\n\t\t}\n\n\t\tconst declared = await provisionDeclared({\n\t\t\tapi,\n\t\t\tworkspace,\n\t\t\tprojectId: project.projectId,\n\t\t\tenvironmentId: environmentId as string,\n\t\t\tstage,\n\t\t\tscope: identity.scope,\n\t\t\tappUrls,\n\t\t\t// What the stage holds by key — a third party's credentials, and what\n\t\t\t// it generated — which a construct reads itself and the sniffer\n\t\t\t// therefore never sees.\n\t\t\tsupplied: stageSecrets.custom,\n\t\t\tseed: stageSecrets.seed as string,\n\t\t\t// The one already discovered above, so a deploy reads the manifest once\n\t\t\t// and cannot act on two different versions of it.\n\t\t\tmanifest,\n\t\t\tdevServices: run.allowDevServices,\n\t\t});\n\n\t\tdeclaredEnv = declared.env;\n\t\tdeclaredClusters = declared.clusters;\n\n\t\tif (Object.keys(declaredEnv).length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t` 🔌 Resolved ${Object.keys(declaredEnv).length} declared URL(s)`,\n\t\t\t);\n\t\t}\n\n\t\t// The DDL the provisioners deferred. Roles and tables need a connection\n\t\t// to a cluster that only exists once the calls above have been made —\n\t\t// which is why they were accumulated rather than run.\n\t\t//\n\t\t// Grouped by the cluster each belongs to, and *the manifest's* cluster\n\t\t// rather than whichever Postgres happens to be around: a project may also\n\t\t// have a legacy `services.postgres`, and applying a construct's roles to\n\t\t// that one would create them where nothing connects.\n\t\t//\n\t\t// A cluster whose migrations `release` will apply stays published until\n\t\t// they have run: publishing restarts the container, and doing it twice\n\t\t// per deploy is two restarts of a database apps are serving from.\n\t\tmigrations = await migrationUrls(workspace.root, manifest, declaredEnv);\n\t\tconst host = serverHostname(endpoint);\n\n\t\tfor (const [databaseName, cluster] of Object.entries(declared.clusters)) {\n\t\t\tconst statements = declared.statements.filter(\n\t\t\t\t(statement) => statement.database === databaseName,\n\t\t\t);\n\t\t\tif (statements.length === 0) continue;\n\n\t\t\tconst published = await publishPostgres(api, cluster, host);\n\t\t\trun.published.set(databaseName, published);\n\t\t\tconst created = await applyDeclaredStatements(published, statements);\n\t\t\tif (!migrations.has(databaseName)) {\n\t\t\t\tawait published.close();\n\t\t\t\trun.published.delete(databaseName);\n\t\t\t}\n\n\t\t\tlogger.log(\n\t\t\t\t` 🗄️ ${databaseName}: applied ${statements.length} statement(s), ${created} new`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// Provision backup destination if configured\n\t// ==================================================================\n\t// The first declared database. A workspace that declares two and wants both\n\t// backed up needs a per-database schedule, which the config has no way to\n\t// express yet — worth saying rather than backing up one and calling it done.\n\tconst backupCluster = Object.values(declaredClusters)[0];\n\n\tif (workspace.deploy?.backups && backupCluster) {\n\t\tlogger.log('\\n💾 Provisioning backup destination...');\n\n\t\tconst { provisionBackupDestination } = await import(\n\t\t\t'./backup-provisioner.js'\n\t\t);\n\n\t\tconst backupState = await provisionBackupDestination({\n\t\t\tapi,\n\t\t\tprojectId: project.projectId,\n\t\t\tprojectName: identity.scope,\n\t\t\tstage,\n\t\t\tconfig: workspace.deploy.backups,\n\t\t\texistingState: getBackupState(state),\n\t\t\tlogger,\n\t\t});\n\n\t\t// Save backup state\n\t\tsetBackupState(state, backupState);\n\n\t\t// Create backup schedule for postgres if not already configured\n\t\tif (!backupState.postgresBackupId) {\n\t\t\tconst backupSchedule = workspace.deploy.backups.schedule ?? '0 2 * * *';\n\t\t\tconst backupRetention = workspace.deploy.backups.retention ?? 30;\n\n\t\t\tlogger.log(' Creating postgres backup schedule...');\n\t\t\tconst backup = await api.createPostgresBackup({\n\t\t\t\tschedule: backupSchedule,\n\t\t\t\tprefix: `${stage}/postgres`,\n\t\t\t\tdestinationId: backupState.destinationId,\n\t\t\t\tdatabase: backupCluster.databaseName,\n\t\t\t\tpostgresId: backupCluster.postgresId,\n\t\t\t\tenabled: true,\n\t\t\t\tkeepLatestCount: backupRetention,\n\t\t\t});\n\t\t\tsetPostgresBackupId(state, backup.backupId);\n\t\t\tlogger.log(` ✓ Postgres backup schedule created (${backupSchedule})`);\n\t\t} else {\n\t\t\tlogger.log(' ✓ Using existing postgres backup schedule');\n\t\t}\n\t}\n\n\trun.provisioned = {\n\t\tapi,\n\t\tendpoint,\n\t\tjournal,\n\t\tstate,\n\t\tprojectId: project.projectId,\n\t\tenvironmentId,\n\t\tregistry,\n\t\tregistryId,\n\t\tdeclaredEnv,\n\t\tdeclaredClusters,\n\t\tmigrations,\n\t\tchanges,\n\t\tapplied,\n\t};\n}\n\n/**\n * The stage's migrations, then each app's image built and pushed, its\n * application configured and deployed, and its domain attached — counted as\n * released only once Dokploy's deployment has finished.\n *\n * Backends first, each failure stopping the run; then they are checked, and\n * a backend that does not answer stops the run too — a site built against an\n * API that is down is a site that is down. Then the sites, whose build args\n * are the backends' public URLs: every one is attempted, and any that failed\n * fails the run. `verify` checks the sites.\n *\n * Building is here rather than in a `build` phase of its own because an\n * image is built beside its application — a site's build args are resolved\n * per app, against the backends released before it.\n */\nexport async function releaseDokploy(run: DokployRun): Promise<void> {\n\tconst { workspace, stage, imageTag, appsToDeployNames, identity, ctx } = run;\n\tconst { stageSecrets, sniffedApps, encryptedSecrets } = run.preflight;\n\tconst {\n\t\tapi,\n\t\tjournal,\n\t\tstate,\n\t\tenvironmentId,\n\t\tregistry,\n\t\tregistryId,\n\t\tdeclaredEnv,\n\t\tchanges,\n\t\tapplied,\n\t} = run.provisioned!;\n\tconst project = { projectId: run.provisioned!.projectId };\n\n\t// ==================================================================\n\t// MIGRATIONS: before any app is pointed at code that expects them\n\t// ==================================================================\n\ttry {\n\t\tawait migrate(run);\n\t} finally {\n\t\tawait closePublished(run);\n\t}\n\n\t// ==================================================================\n\t// Separate apps by type for two-phase deployment\n\t// ==================================================================\n\tconst backendApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'backend',\n\t);\n\tconst frontendApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'web',\n\t);\n\n\t// Track deployed app public URLs for frontend builds\n\tconst publicUrls: Record<string, string> = {};\n\tconst results: AppDeployResult[] = [];\n\n\t// Track domain IDs and hostnames for DNS orchestration\n\tconst appHostnames = new Map<string, string>(); // appName -> hostname\n\tconst appDomainIds = new Map<string, string>(); // appName -> domainId\n\tconst released: Released = {\n\t\tresults,\n\t\tpublicUrls,\n\t\tappHostnames,\n\t\tappDomainIds,\n\t\tapplicationIds: new Map(),\n\t};\n\trun.released = released;\n\n\t/** An app is up: say so, and remember where. */\n\tconst deployed = (\n\t\tappName: string,\n\t\tresult: Omit<AppDeployResult, 'success'> & {\n\t\t\tapplicationId: string;\n\t\t\timageRef: string;\n\t\t},\n\t\thost: string,\n\t) => {\n\t\tconst url = `https://${host}`;\n\t\tresults.push({ ...result, success: true, url });\n\t\tctx.emit({\n\t\t\ttype: 'app.deployed',\n\t\t\tapp: appName,\n\t\t\tapplicationId: result.applicationId,\n\t\t\timageRef: result.imageRef,\n\t\t\turl,\n\t\t});\n\t};\n\n\t/** An image is pushed: worth keeping even if what follows fails. */\n\tconst built = (\n\t\tappName: string,\n\t\timage: { imageRef?: string; digest?: string },\n\t\tref: string,\n\t) => {\n\t\tctx.emit({\n\t\t\ttype: 'artifact.built',\n\t\t\tapp: appName,\n\t\t\timageRef: image.imageRef ?? ref,\n\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t});\n\t\tchanges.push({\n\t\t\tkey: `image:${appName}`,\n\t\t\tresourceType: 'image',\n\t\t\taction: 'build',\n\t\t\tid: image.digest ?? image.imageRef ?? ref,\n\t\t});\n\t};\n\n\t/**\n\t * Point an app's application at its image and environment, deploy it,\n\t * attach its domain, and wait for Dokploy to finish — then record the\n\t * release, with what ran before it as the one a rollback restores.\n\t */\n\tconst release = async (\n\t\tappName: string,\n\t\tapplicationId: string,\n\t\timage: DeployedImage,\n\t\tenvVars: string[],\n\t\t/** Where it answers — none for a worker, which has no route. */\n\t\thost: string | undefined,\n\t): Promise<void> => {\n\t\treleased.applicationIds.set(appName, applicationId);\n\n\t\t// Dokploy's clock, read before deploying: the deployment to wait for is\n\t\t// the first one after it.\n\t\tconst since = await api.latestDeploymentAt(applicationId);\n\t\tconst before = state.releases?.[appName]?.current;\n\t\trun.releasing.switched.set(appName, {\n\t\t\tapplicationId,\n\t\t\t...(before ? { before } : {}),\n\t\t});\n\n\t\t// Configure and deploy application in Dokploy\n\t\tawait api.saveDockerProvider(applicationId, image.ref, { registryId });\n\t\tawait api.saveApplicationEnv(applicationId, envVars.join('\\n'));\n\n\t\tlogger.log(` Deploying to Dokploy...`);\n\t\tawait api.deployApplication(applicationId);\n\n\t\tif (host) {\n\t\t\tconst domainId = await ensureDomain(\n\t\t\t\tapi,\n\t\t\t\tjournal,\n\t\t\t\thost,\n\t\t\t\tworkspace.apps[appName]!.port,\n\t\t\t\tapplicationId,\n\t\t\t\tapplied,\n\t\t\t);\n\t\t\tappHostnames.set(appName, host);\n\t\t\tif (domainId) appDomainIds.set(appName, domainId);\n\t\t}\n\n\t\tlogger.log(` Waiting for the deployment to finish...`);\n\t\tawait api.waitForDeployment(applicationId, {\n\t\t\tsince,\n\t\t\ttimeoutMs: run.verify.deploymentTimeoutMs,\n\t\t\tintervalMs: run.verify.intervalMs,\n\t\t\tsignal: ctx.signal,\n\t\t});\n\t\trecordRelease(state, appName, { ...image, tag: imageTag });\n\t\tawait journal.save();\n\t\tif (host) publicUrls[appName] = `https://${host}`;\n\t};\n\n\t// ==================================================================\n\t// PRE-COMPUTE: Frontend URLs for BETTER_AUTH_TRUSTED_ORIGINS\n\t// ==================================================================\n\tconst frontendUrls: string[] = [];\n\tfor (const appName of frontendApps) {\n\t\tfrontendUrls.push(`https://${hostOf(workspace, appName, stage)}`);\n\t}\n\n\t// ==================================================================\n\t// PHASE 1: Deploy backend apps (with encrypted secrets)\n\t// ==================================================================\n\tif (backendApps.length > 0) {\n\t\tlogger.log('\\n📦 PHASE 1: Deploying backend applications...');\n\n\t\tfor (const appName of backendApps) {\n\t\t\tctx.signal?.throwIfAborted();\n\t\t\tconst app = workspace.apps[appName]!;\n\n\t\t\tlogger.log(`\\n ⚙️ Deploying ${appName}...`);\n\n\t\t\ttry {\n\t\t\t\t// Scoped exactly as a construct is, by the stage and the deploy\n\t\t\t\t// identity: an application's name is also its Docker service name,\n\t\t\t\t// unique on the whole server, so two workspaces called `shop`\n\t\t\t\t// cannot both run `production-shop-api`.\n\t\t\t\tconst dokployAppName = applicationName(identity, appName);\n\n\t\t\t\tconst application = await ensureApplication(\n\t\t\t\t\tapi,\n\t\t\t\t\tjournal,\n\t\t\t\t\tappName,\n\t\t\t\t\tdokployAppName,\n\t\t\t\t\tproject.projectId,\n\t\t\t\t\tenvironmentId,\n\t\t\t\t\tapplied,\n\t\t\t\t);\n\n\t\t\t\t// Get encrypted secrets for this app\n\t\t\t\tconst appSecrets = encryptedSecrets.get(appName);\n\t\t\t\t// A build secret, not build args: those are visible in `ps` and\n\t\t\t\t// recorded in the image history.\n\t\t\t\tconst credentials =\n\t\t\t\t\tappSecrets && appSecrets.secretCount > 0\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tencrypted: appSecrets.payload.encrypted,\n\t\t\t\t\t\t\t\tiv: appSecrets.payload.iv,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\tif (appSecrets && credentials) {\n\t\t\t\t\tlogger.log(` Encrypted ${appSecrets.secretCount} secrets`);\n\t\t\t\t}\n\n\t\t\t\t// Build Docker image with encrypted secrets\n\t\t\t\tconst imageRef = imageRefFor(identity, appName, registry, imageTag);\n\n\t\t\t\tlogger.log(` Building Docker image: ${imageRef}`);\n\n\t\t\t\tconst image = await deployDocker({\n\t\t\t\t\tstage,\n\t\t\t\t\ttag: imageTag,\n\t\t\t\t\tskipPush: false,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\timageName: imageName(identity, appName),\n\t\t\t\t\t\tappName,\n\t\t\t\t\t},\n\t\t\t\t\tcredentials,\n\t\t\t\t\t...dockerRun(workspace, app, ctx),\n\t\t\t\t});\n\t\t\t\tbuilt(appName, image, imageRef);\n\n\t\t\t\t// Compute hostname first (needed for BETTER_AUTH_URL)\n\t\t\t\tconst backendHost = hostOf(workspace, appName, stage);\n\n\t\t\t\t// Build dependency URLs from already-deployed apps\n\t\t\t\tconst dependencyUrls: Record<string, string> = {};\n\t\t\t\tif (app.dependencies) {\n\t\t\t\t\tfor (const dep of app.dependencies) {\n\t\t\t\t\t\tif (publicUrls[dep]) {\n\t\t\t\t\t\t\tdependencyUrls[dep] = publicUrls[dep];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Build env resolver context\n\t\t\t\tconst envContext: EnvResolverContext = {\n\t\t\t\t\tapp,\n\t\t\t\t\tappName,\n\t\t\t\t\tstage,\n\t\t\t\t\tstate,\n\t\t\t\t\tappHostname: backendHost,\n\t\t\t\t\tfrontendUrls,\n\t\t\t\t\tuserSecrets: stageSecrets ?? undefined,\n\t\t\t\t\tmasterKey: appSecrets?.masterKey,\n\t\t\t\t\tdependencyUrls,\n\t\t\t\t};\n\n\t\t\t\t// Resolve all required environment variables\n\t\t\t\t// Always include PORT, NODE_ENV, STAGE even if not explicitly required\n\t\t\t\tconst appRequirements = sniffedApps.get(appName);\n\t\t\t\tconst sniffedVars = requiredOf(appRequirements);\n\t\t\t\tconst requiredVars = [\n\t\t\t\t\t...new Set(['PORT', 'NODE_ENV', 'STAGE', ...sniffedVars]),\n\t\t\t\t];\n\t\t\t\tconst { valid, missing, resolved } = validateEnvVars(\n\t\t\t\t\trequiredVars,\n\t\t\t\t\tenvContext,\n\t\t\t\t);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tthrow new MissingEnvVars(appName, missing, stage);\n\t\t\t\t}\n\n\t\t\t\t// Declared URLs win over anything sniffed or stored, which is the\n\t\t\t\t// same precedence the local target applies: the manifest is the\n\t\t\t\t// statement of what exists, and a value left over from before it\n\t\t\t\t// was declared is exactly the drift this replaces.\n\t\t\t\t//\n\t\t\t\t// They are merged *after* validation rather than added to the\n\t\t\t\t// required list, because the sniffer cannot see them — a construct\n\t\t\t\t// reads its own key inside `@geekmidas/constructs`, so requiring\n\t\t\t\t// them would fail every app that declares anything.\n\t\t\t\t//\n\t\t\t\t// The stage's `OTEL_*` go to every backend, whatever it reads: they\n\t\t\t\t// say where its telemetry goes, which no construct declares. A site\n\t\t\t\t// never gets them — its environment ends up in a browser bundle.\n\t\t\t\t// (`deploy.compose.logs` is the compose target's; it is not read\n\t\t\t\t// here.)\n\t\t\t\tconst withDeclared = {\n\t\t\t\t\t...resolved,\n\t\t\t\t\t...declaredEnv,\n\t\t\t\t\t...otelEnv(stageSecrets?.custom ?? {}, appName),\n\t\t\t\t};\n\n\t\t\t\t// Build env vars string for Dokploy\n\t\t\t\tconst envVars: string[] = Object.entries(withDeclared).map(\n\t\t\t\t\t([key, value]) => `${key}=${value}`,\n\t\t\t\t);\n\n\t\t\t\tif (Object.keys(withDeclared).length > 0) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t` Resolved ${Object.keys(withDeclared).length} env vars: ${Object.keys(withDeclared).sort().join(', ')}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tawait release(\n\t\t\t\t\tappName,\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t\t{\n\t\t\t\t\t\tref: image.imageRef ?? imageRef,\n\t\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tenvVars,\n\t\t\t\t\tbackendHost,\n\t\t\t\t);\n\n\t\t\t\tdeployed(\n\t\t\t\t\tappName,\n\t\t\t\t\t{\n\t\t\t\t\t\tappName,\n\t\t\t\t\t\ttype: app.type,\n\t\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\t\timageRef,\n\t\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tbackendHost,\n\t\t\t\t);\n\n\t\t\t\tlogger.log(` ✓ ${appName} deployed successfully`);\n\t\t\t} catch (error) {\n\t\t\t\t// The caller stopping the run is not this app failing.\n\t\t\t\tif (ctx.signal?.aborted) throw ctx.signal.reason;\n\t\t\t\tfailed(run, appName, error);\n\n\t\t\t\t// Abort on backend failure to prevent incomplete deployment\n\t\t\t\tthrow new BackendDeployFailed(appName, error);\n\t\t\t}\n\t\t}\n\n\t\t// Every backend answering before any site is released against it.\n\t\tawait settleDns(run, backendApps);\n\t\tfor (const appName of backendApps) {\n\t\t\ttry {\n\t\t\t\tawait checkHealth(run, appName);\n\t\t\t} catch (error) {\n\t\t\t\tif (ctx.signal?.aborted) throw ctx.signal.reason;\n\t\t\t\tfailed(run, appName, error);\n\t\t\t\tthrow new BackendDeployFailed(appName, error);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// PHASE 1b: Deploy workers — an application each, with no domain\n\t// ==================================================================\n\tif (run.workers.length > 0) {\n\t\tlogger.log('\\n🧵 Deploying workers...');\n\n\t\tfor (const worker of run.workers) {\n\t\t\tctx.signal?.throwIfAborted();\n\t\t\tlogger.log(`\\n 🧵 Deploying ${worker.name} (worker ${worker.id})...`);\n\n\t\t\ttry {\n\t\t\t\tconst application = await ensureApplication(\n\t\t\t\t\tapi,\n\t\t\t\t\tjournal,\n\t\t\t\t\tworker.name,\n\t\t\t\t\tapplicationName(identity, worker.name),\n\t\t\t\t\tproject.projectId,\n\t\t\t\t\tenvironmentId,\n\t\t\t\t\tapplied,\n\t\t\t\t);\n\n\t\t\t\t// Exactly what its constructs read: the stage's secrets among\n\t\t\t\t// them embedded, encrypted, as a backend's are; the declared\n\t\t\t\t// URLs among them as its environment.\n\t\t\t\tconst keys = [\n\t\t\t\t\t...(workerEnvKeys(run.manifest, worker.id, run.runnables) ?? []),\n\t\t\t\t].sort();\n\t\t\t\tconst secrets = prepareSecretsForApp(stageSecrets, {\n\t\t\t\t\tappName: worker.name,\n\t\t\t\t\trequiredEnvVars: keys,\n\t\t\t\t\toptionalEnvVars: [],\n\t\t\t\t});\n\t\t\t\tconst credentials =\n\t\t\t\t\tsecrets.secretCount > 0\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tencrypted: secrets.payload.encrypted,\n\t\t\t\t\t\t\t\tiv: secrets.payload.iv,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\tconst imageRef = imageRefFor(identity, worker.name, registry, imageTag);\n\t\t\t\tlogger.log(` Building Docker image: ${imageRef}`);\n\t\t\t\tconst image = await deployDocker({\n\t\t\t\t\tstage,\n\t\t\t\t\ttag: imageTag,\n\t\t\t\t\tskipPush: false,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\timageName: imageName(identity, worker.name),\n\t\t\t\t\t\tappName: worker.name,\n\t\t\t\t\t},\n\t\t\t\t\tcredentials,\n\t\t\t\t\tcwd: workspace.root,\n\t\t\t\t\tdockerfile: workerDockerfileOf(worker.name),\n\t\t\t\t\t...(ctx.signal ? { signal: ctx.signal } : {}),\n\t\t\t\t\t...(ctx.stdio ? { stdio: ctx.stdio } : {}),\n\t\t\t\t});\n\t\t\t\tbuilt(worker.name, image, imageRef);\n\n\t\t\t\tconst env: Record<string, string> = {\n\t\t\t\t\t...Object.fromEntries(\n\t\t\t\t\t\tObject.entries(declaredEnv).filter(([key]) => keys.includes(key)),\n\t\t\t\t\t),\n\t\t\t\t\t...otelEnv(stageSecrets?.custom ?? {}, worker.name),\n\t\t\t\t\t...(credentials ? { GKM_MASTER_KEY: secrets.masterKey } : {}),\n\t\t\t\t\tNODE_ENV: 'production',\n\t\t\t\t\tPORT: String(WORKER_PORT),\n\t\t\t\t\tSTAGE: stage,\n\t\t\t\t};\n\t\t\t\tlogger.log(\n\t\t\t\t\t` Resolved ${Object.keys(env).length} env vars: ${Object.keys(env).sort().join(', ')}`,\n\t\t\t\t);\n\n\t\t\t\tawait release(\n\t\t\t\t\tworker.name,\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t\t{\n\t\t\t\t\t\tref: image.imageRef ?? imageRef,\n\t\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tObject.entries(env).map(([key, value]) => `${key}=${value}`),\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\t// No domain: Dokploy's finished deployment — the container up,\n\t\t\t\t// past its own HEALTHCHECK — is its check.\n\t\t\t\tawait checkHealth(run, worker.name);\n\n\t\t\t\tresults.push({\n\t\t\t\t\tappName: worker.name,\n\t\t\t\t\ttype: 'backend',\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\timageRef,\n\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t});\n\t\t\t\tlogger.log(` ✓ ${worker.name} deployed successfully`);\n\t\t\t} catch (error) {\n\t\t\t\tif (ctx.signal?.aborted) throw ctx.signal.reason;\n\t\t\t\tfailed(run, worker.name, error);\n\t\t\t\tthrow new BackendDeployFailed(worker.name, error);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// PHASE 2: Deploy frontend apps (with public URLs from backends)\n\t// ==================================================================\n\tlet frontendFailure: unknown;\n\tif (frontendApps.length > 0) {\n\t\tlogger.log('\\n🌐 PHASE 2: Deploying frontend applications...');\n\n\t\tfor (const appName of frontendApps) {\n\t\t\tctx.signal?.throwIfAborted();\n\t\t\tconst app = workspace.apps[appName]!;\n\n\t\t\tlogger.log(`\\n 🌐 Deploying ${appName}...`);\n\n\t\t\ttry {\n\t\t\t\t// Scoped exactly as a construct is, by the stage and the deploy\n\t\t\t\t// identity: an application's name is also its Docker service name,\n\t\t\t\t// unique on the whole server, so two workspaces called `shop`\n\t\t\t\t// cannot both run `production-shop-api`.\n\t\t\t\tconst dokployAppName = applicationName(identity, appName);\n\n\t\t\t\tconst application = await ensureApplication(\n\t\t\t\t\tapi,\n\t\t\t\t\tjournal,\n\t\t\t\t\tappName,\n\t\t\t\t\tdokployAppName,\n\t\t\t\t\tproject.projectId,\n\t\t\t\t\tenvironmentId,\n\t\t\t\t\tapplied,\n\t\t\t\t);\n\n\t\t\t\t// Build dependency URLs for frontend (same pattern as backend)\n\t\t\t\tconst dependencyUrls: Record<string, string> = {};\n\t\t\t\tif (app.dependencies) {\n\t\t\t\t\tfor (const dep of app.dependencies) {\n\t\t\t\t\t\tif (publicUrls[dep]) {\n\t\t\t\t\t\t\tdependencyUrls[dep] = publicUrls[dep];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Compute hostname for this frontend app\n\t\t\t\tconst frontendHost = hostOf(workspace, appName, stage);\n\n\t\t\t\t// Build env context for frontend\n\t\t\t\tconst envContext: EnvResolverContext = {\n\t\t\t\t\tapp,\n\t\t\t\t\tappName,\n\t\t\t\t\tstage,\n\t\t\t\t\tstate,\n\t\t\t\t\tappHostname: frontendHost,\n\t\t\t\t\tfrontendUrls: [],\n\t\t\t\t\tuserSecrets: stageSecrets ?? undefined,\n\t\t\t\t\tdependencyUrls,\n\t\t\t\t};\n\n\t\t\t\t// Resolve all env vars BEFORE Docker build (public-prefixed vars\n\t\t\t\t// must be present at bundler build time so they get inlined).\n\t\t\t\tconst sniffedVars = requiredOf(sniffedApps.get(appName));\n\t\t\t\tconst { valid, missing, resolved } = validateEnvVars(\n\t\t\t\t\tsniffedVars,\n\t\t\t\t\tenvContext,\n\t\t\t\t);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tthrow new MissingEnvVars(appName, missing, stage);\n\t\t\t\t}\n\n\t\t\t\tif (Object.keys(resolved).length > 0) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(', ')}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build args: only the framework's public-prefixed vars get baked\n\t\t\t\t// into the bundle. Server-only vars stay as runtime env.\n\t\t\t\tconst publicPrefix = getPublicEnvPrefix(app.framework);\n\t\t\t\tconst buildArgs: string[] = [];\n\t\t\t\tconst publicUrlArgNames: string[] = [];\n\n\t\t\t\tif (publicPrefix) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\t\tif (key.startsWith(publicPrefix)) {\n\t\t\t\t\t\t\tbuildArgs.push(`${key}=${value}`);\n\t\t\t\t\t\t\tpublicUrlArgNames.push(key);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (buildArgs.length > 0) {\n\t\t\t\t\tlogger.log(` Build args: ${publicUrlArgNames.join(', ')}`);\n\t\t\t\t}\n\n\t\t\t\t// Build Docker image with public-prefixed vars as build args\n\t\t\t\tconst imageRef = imageRefFor(identity, appName, registry, imageTag);\n\n\t\t\t\tlogger.log(` Building Docker image: ${imageRef}`);\n\n\t\t\t\tconst image = await deployDocker({\n\t\t\t\t\tstage,\n\t\t\t\t\ttag: imageTag,\n\t\t\t\t\tskipPush: false,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\timageName: imageName(identity, appName),\n\t\t\t\t\t\tappName,\n\t\t\t\t\t},\n\t\t\t\t\tbuildArgs,\n\t\t\t\t\t// Pass arg names for Dockerfile ARG generation\n\t\t\t\t\tpublicUrlArgs: publicUrlArgNames,\n\t\t\t\t\t...dockerRun(workspace, app, ctx),\n\t\t\t\t});\n\t\t\t\tbuilt(appName, image, imageRef);\n\n\t\t\t\t// Prepare runtime environment variables\n\t\t\t\tconst envVars: string[] = [\n\t\t\t\t\t`NODE_ENV=production`,\n\t\t\t\t\t`PORT=${app.port}`,\n\t\t\t\t\t`STAGE=${stage}`,\n\t\t\t\t];\n\n\t\t\t\t// Add all resolved vars as runtime env (for SSR and server components)\n\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\tenvVars.push(`${key}=${value}`);\n\t\t\t\t}\n\n\t\t\t\tawait release(\n\t\t\t\t\tappName,\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t\t{\n\t\t\t\t\t\tref: image.imageRef ?? imageRef,\n\t\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tenvVars,\n\t\t\t\t\tfrontendHost,\n\t\t\t\t);\n\n\t\t\t\tdeployed(\n\t\t\t\t\tappName,\n\t\t\t\t\t{\n\t\t\t\t\t\tappName,\n\t\t\t\t\t\ttype: app.type,\n\t\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\t\timageRef,\n\t\t\t\t\t\t...(image.digest ? { digest: image.digest } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tfrontendHost,\n\t\t\t\t);\n\n\t\t\t\tlogger.log(` ✓ ${appName} deployed successfully`);\n\t\t\t} catch (error) {\n\t\t\t\t// The caller stopping the run is not this app failing.\n\t\t\t\tif (ctx.signal?.aborted) throw ctx.signal.reason;\n\t\t\t\tfailed(run, appName, error);\n\t\t\t\t// Every site is attempted — one broken site does not hold the\n\t\t\t\t// others back — but the run fails once they have been.\n\t\t\t\tfrontendFailure ??= error;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// STATE: Save deploy state\n\t// ==================================================================\n\tlogger.log('\\n📋 Saving deploy state...');\n\tawait journal.save();\n\tlogger.log(' ✓ State saved');\n\n\tif (frontendFailure !== undefined) {\n\t\tthrow new FrontendDeployFailed(\n\t\t\tfrontendApps.filter((app) => run.releasing.failed.has(app)),\n\t\t\tfrontendFailure,\n\t\t);\n\t}\n}\n\n/** Each released site answering, after its DNS. Backends were checked in `release`. */\nexport async function verifyDokploy(run: DokployRun): Promise<void> {\n\tconst { workspace, ctx } = run;\n\tconst sites = run\n\t\t.released!.results.filter((result) => result.success)\n\t\t.map((result) => result.appName)\n\t\t.filter((app) => workspace.apps[app]?.type === 'web');\n\tif (sites.length === 0) return;\n\n\tawait settleDns(run, sites);\n\n\tlet failure: unknown;\n\tfor (const appName of sites) {\n\t\ttry {\n\t\t\tawait checkHealth(run, appName);\n\t\t} catch (error) {\n\t\t\tif (ctx.signal.aborted) throw ctx.signal.reason;\n\t\t\tfailed(run, appName, error);\n\t\t\tfailure ??= error;\n\t\t}\n\t}\n\tif (failure !== undefined) {\n\t\tthrow new FrontendDeployFailed(\n\t\t\tsites.filter((app) => run.releasing.failed.has(app)),\n\t\t\tfailure,\n\t\t);\n\t}\n}\n\n/**\n * An app failed to release or to answer: say so, mark it for rollback, and\n * record it in the result — over the success it was recorded as, if its\n * health is what failed.\n */\nfunction failed(run: DokployRun, appName: string, error: unknown): void {\n\t// A worker is no app of the workspace's, and runs on a server: a backend.\n\tconst type = run.workspace.apps[appName]?.type ?? 'backend';\n\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\tlogger.log(` ✗ Failed to deploy ${appName}: ${message}`);\n\n\tconst results = run.released!.results;\n\tconst recorded = results.find((result) => result.appName === appName);\n\tif (recorded) {\n\t\trecorded.success = false;\n\t\trecorded.error = message;\n\t} else {\n\t\tresults.push({ appName, type, success: false, error: message });\n\t}\n\trun.releasing.failed.add(appName);\n\trun.ctx.emit({ type: 'app.failed', app: appName, error: eventError(error) });\n}\n\n/**\n * The stage's pending migrations, applied in the deploy's sandbox against\n * each cluster published for them. Nothing is published, and nothing runs,\n * for a project with no migration to apply.\n */\nasync function migrate(run: DokployRun): Promise<void> {\n\tconst { workspace, manifest, stage, ctx } = run;\n\tconst { api, endpoint, migrations, declaredClusters } = run.provisioned!;\n\tif (migrations.size === 0) return;\n\n\tlogger.log('\\n🗄️ Applying migrations...');\n\tconst host = serverHostname(endpoint);\n\tconst urls: Record<string, string> = {};\n\tfor (const [database, keys] of migrations) {\n\t\tconst cluster = declaredClusters[database];\n\t\tif (!cluster) continue;\n\n\t\tlet published = run.published.get(database);\n\t\tif (!published) {\n\t\t\tpublished = await publishPostgres(api, cluster, host);\n\t\t\trun.published.set(database, published);\n\t\t}\n\t\tfor (const [key, url] of Object.entries(keys)) {\n\t\t\turls[key] = publishedUrl(url, published);\n\t\t}\n\t}\n\n\tconst runs = await runMigrations({\n\t\troot: workspace.root,\n\t\tstage,\n\t\tmanifest,\n\t\tpatterns: constructGlobs(workspace),\n\t\turls,\n\t\tsignal: ctx.signal,\n\t});\n\tfor (const { migrations: folder, applied } of runs) {\n\t\tlogger.log(\n\t\t\tapplied.length === 0\n\t\t\t\t? ` ✓ ${folder}: up to date`\n\t\t\t\t: ` ✓ ${folder}: applied ${applied.join(', ')}`,\n\t\t);\n\t}\n}\n\n/**\n * DNS records for `apps`' hosts, their propagation, and Dokploy's validation\n * of each domain — before anything is asked of them by name.\n */\nasync function settleDns(\n\trun: DokployRun,\n\tapps: readonly string[],\n): Promise<void> {\n\tconst { workspace } = run;\n\tconst { api, endpoint, journal, state } = run.provisioned!;\n\tconst appHostnames = new Map(\n\t\t[...run.released!.appHostnames].filter(([app]) => apps.includes(app)),\n\t);\n\t// ==================================================================\n\t// DNS: Create DNS records, verify propagation, and validate for SSL\n\t// ==================================================================\n\tconst dnsConfig = workspace.deploy.dns;\n\tif (!dnsConfig || appHostnames.size === 0) return;\n\n\tconst dnsResult = await orchestrateDns(appHostnames, dnsConfig, endpoint);\n\n\t// Verify DNS records resolve correctly (with state caching)\n\tif (dnsResult?.serverIp) {\n\t\tawait verifyDnsRecords(appHostnames, dnsResult.serverIp, state);\n\n\t\t// Save state again to persist DNS verification results\n\t\tawait journal.save();\n\t}\n\n\t// Validate domains to trigger SSL certificate generation\n\tif (dnsResult?.success) {\n\t\tlogger.log('\\n🔒 Validating domains for SSL certificates...');\n\t\tfor (const [appName, hostname] of appHostnames) {\n\t\t\ttry {\n\t\t\t\tconst result = await api.validateDomain(hostname);\n\t\t\t\tif (result.isValid) {\n\t\t\t\t\tlogger.log(` ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(` ⚠ ${appName}: ${hostname} not valid`);\n\t\t\t\t}\n\t\t\t} catch (validationError) {\n\t\t\t\tconst message =\n\t\t\t\t\tvalidationError instanceof Error\n\t\t\t\t\t\t? validationError.message\n\t\t\t\t\t\t: 'Unknown error';\n\t\t\t\tlogger.log(` ⚠ ${appName}: validation failed - ${message}`);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Whether a released app answers: `healthyAfter` 2xx in a row from its\n * health route under its domain. An app without a domain has nothing to ask\n * by name, so Dokploy's finished deployment is its check.\n */\nasync function checkHealth(run: DokployRun, appName: string): Promise<void> {\n\tconst { workspace, verify, ctx } = run;\n\tconst { appHostnames, appDomainIds, applicationIds } = run.released!;\n\tconst host = appHostnames.get(appName);\n\n\tif (!host || !appDomainIds.has(appName)) {\n\t\tctx.emit({\n\t\t\ttype: 'health.checked',\n\t\t\tapp: appName,\n\t\t\turl: `dokploy:application.status/${applicationIds.get(appName)}`,\n\t\t\thealthy: true,\n\t\t\tattempt: 1,\n\t\t});\n\t\tlogger.log(\n\t\t\t` ✓ ${appName}: no domain, so its finished deployment is its check`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst path =\n\t\tworkspace.apps[appName]!.type === 'web' ? '/' : verify.healthCheckPath;\n\tconst url = `https://${host}${path}`;\n\tlogger.log(`\\n🩺 Checking ${appName} at ${url}...`);\n\tawait verifyHealth({\n\t\tapp: appName,\n\t\turl,\n\t\thealthyAfter: verify.healthyAfter,\n\t\tintervalMs: verify.intervalMs,\n\t\ttimeoutMs: verify.healthTimeoutMs,\n\t\tsignal: ctx.signal,\n\t\temit: ctx.emit,\n\t});\n\tlogger.log(` ✓ ${appName} healthy (${verify.healthyAfter} in a row)`);\n}\n\n/**\n * Point an application back at `image`, deploy it, and wait for Dokploy to\n * finish. The environment stays the newer release's: it is resolved from the\n * stage, which a rollback does not change, and holds no image of its own.\n */\nexport async function restoreImage(\n\tapi: DokployApi,\n\toptions: {\n\t\tapplicationId: string;\n\t\timage: DeployedImage;\n\t\tregistryId: string | undefined;\n\t\tverify: VerifySettings;\n\t\tsignal: AbortSignal;\n\t},\n): Promise<void> {\n\tconst { applicationId, image, registryId, verify, signal } = options;\n\tconst since = await api.latestDeploymentAt(applicationId);\n\tawait api.saveDockerProvider(\n\t\tapplicationId,\n\t\timage.ref,\n\t\tregistryId ? { registryId } : undefined,\n\t);\n\tawait api.deployApplication(applicationId);\n\tawait api.waitForDeployment(applicationId, {\n\t\tsince,\n\t\ttimeoutMs: verify.deploymentTimeoutMs,\n\t\tintervalMs: verify.intervalMs,\n\t\tsignal,\n\t});\n}\n\n/**\n * Put back what ran before this run, after its `release` or `verify` failed:\n * the apps that failed — or, `atomic`, every app the run released — each\n * pointed at its previous image and redeployed. An app released for the\n * first time has nothing to go back to and is left as it is.\n */\nexport async function rollbackDokploy(\n\trun: DokployRun,\n\tfailure: DeployFailure,\n): Promise<void> {\n\tconst { switched, failed: failedApps } = run.releasing;\n\tconst apps = [...switched.keys()].filter(\n\t\t(app) => run.atomic || failedApps.has(app),\n\t);\n\tif (!run.provisioned || apps.length === 0) {\n\t\tlogger.log(\n\t\t\t`\\n⏪ Nothing to roll back: the ${failure.phase} failed before any app was switched.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst { api, journal, state, registryId } = run.provisioned;\n\tlogger.log(\n\t\t`\\n⏪ Rolling back ${run.atomic ? 'every app this run released' : 'what failed'}: ${apps.join(', ')}`,\n\t);\n\n\tfor (const appName of apps) {\n\t\tconst { applicationId, before } = switched.get(appName)!;\n\t\tif (!before) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ ${appName}: this was its first release, so there is nothing to restore`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tawait restoreImage(api, {\n\t\t\tapplicationId,\n\t\t\timage: before,\n\t\t\tregistryId,\n\t\t\tverify: run.verify,\n\t\t\tsignal: run.ctx.signal,\n\t\t});\n\t\trecordRollback(state, appName, before);\n\t\tawait journal.save();\n\t\tlogger.log(` ✓ ${appName} rolled back to ${before.ref}`);\n\t}\n}\n\n/** What the run did, printed as the summary it always ended with. */\nexport function dokployResult(run: DokployRun): DeployResult {\n\tif (run.result) return run.result;\n\n\tconst { stage, identity, imageTag } = run;\n\tconst { projectId, environmentId, changes } = run.provisioned!;\n\tconst { results, publicUrls } = run.released!;\n\tconst project = { projectId };\n\n\t// ==================================================================\n\t// Summary\n\t// ==================================================================\n\tconst successCount = results.filter((r) => r.success).length;\n\tconst failedCount = results.filter((r) => !r.success).length;\n\n\tlogger.log(`\\n${'─'.repeat(50)}`);\n\tlogger.log(`\\n✅ Workspace deployment complete!`);\n\tlogger.log(` Project: ${project.projectId}`);\n\tlogger.log(` Successful: ${successCount}`);\n\tif (failedCount > 0) {\n\t\tlogger.log(` Failed: ${failedCount}`);\n\t}\n\n\t// Print deployed URLs\n\tif (Object.keys(publicUrls).length > 0) {\n\t\tlogger.log('\\n 📡 Deployed URLs:');\n\t\tfor (const [name, url] of Object.entries(publicUrls)) {\n\t\t\tlogger.log(` ${name}: ${url}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tapps: results,\n\t\tprojectId: project.projectId,\n\t\tenvironmentId,\n\t\tsuccessCount,\n\t\tfailedCount,\n\t\tstage,\n\t\tidentity: identity.key,\n\t\ttag: imageTag,\n\t\tdryRun: false,\n\t\tskipped: [...run.skipped],\n\t\turls: publicUrls,\n\t\tchanges,\n\t};\n}\n\n/**\n * An app's Dokploy application, through the journal: by the id recorded for\n * it, else by its name in the stage's environment, else created. Its id goes\n * into `state.applications` too, which the env resolver and `state:show` read.\n */\nasync function ensureApplication(\n\tapi: DokployApi,\n\tjournal: DeployJournal,\n\tappName: string,\n\tdokployAppName: string,\n\tprojectId: string,\n\tenvironmentId: string,\n\tapplied: Applied,\n): Promise<DokployApplication> {\n\tconst recorded = journal.record(`application:${appName}`);\n\tif (recorded?.status === 'ready' && recorded.id) {\n\t\tlogger.log(` Using cached ID: ${recorded.id}`);\n\t}\n\n\tconst { resource, via, staleId } = await journal.ensure(\n\t\t{\n\t\t\tkey: `application:${appName}`,\n\t\t\ttype: 'application',\n\t\t\tdata: { name: dokployAppName },\n\t\t},\n\t\t{\n\t\t\tget: (id) => api.getApplication(id),\n\t\t\tfind: () =>\n\t\t\t\tapi.findApplicationByName(projectId, dokployAppName, environmentId),\n\t\t\tcreate: () =>\n\t\t\t\tapi.createApplication(dokployAppName, projectId, environmentId),\n\t\t\tid: (application) => application.applicationId,\n\t\t},\n\t);\n\n\tif (staleId) logger.log(` ⚠ Cached ID invalid, will create new`);\n\tconst said: Record<typeof via, string> = {\n\t\trecorded: '✓ Application found',\n\t\tresumed: 'Resumed application a stopped run created',\n\t\tfound: 'Found existing application',\n\t\tcreated: 'Created application',\n\t};\n\tlogger.log(` ${said[via]}: ${resource.applicationId}`);\n\tapplied(\n\t\t{\n\t\t\tkey: `application:${appName}`,\n\t\t\tresourceType: 'application',\n\t\t\taction: via === 'created' ? 'create' : 'reuse',\n\t\t\tid: resource.applicationId,\n\t\t},\n\t\tvia,\n\t);\n\n\tsetApplicationId(journal.state, appName, resource.applicationId);\n\treturn resource;\n}\n\n/**\n * The domain `host` routes to an application, through the journal — found on\n * the application before it is created, so a re-run never adds a second.\n *\n * A domain that cannot be created is reported and skipped rather than\n * failing the app: the application is deployed and reachable on Dokploy's\n * own address, and DNS is fixed by hand more easily than a half deploy.\n */\nasync function ensureDomain(\n\tapi: DokployApi,\n\tjournal: DeployJournal,\n\thost: string,\n\tport: number,\n\tapplicationId: string,\n\tapplied: Applied,\n): Promise<string | undefined> {\n\ttry {\n\t\tconst { resource, via } = await journal.ensure(\n\t\t\t{ key: `domain:${host}`, type: 'domain', data: { host, applicationId } },\n\t\t\t{\n\t\t\t\tfind: async () =>\n\t\t\t\t\t(await api.getDomainsByApplicationId(applicationId)).find(\n\t\t\t\t\t\t(d) => d.host === host,\n\t\t\t\t\t),\n\t\t\t\tcreate: () =>\n\t\t\t\t\tapi.createDomain({\n\t\t\t\t\t\thost,\n\t\t\t\t\t\tport,\n\t\t\t\t\t\thttps: true,\n\t\t\t\t\t\tcertificateType: 'letsencrypt',\n\t\t\t\t\t\tapplicationId,\n\t\t\t\t\t}),\n\t\t\t\tid: (domain) => domain.domainId,\n\t\t\t},\n\t\t);\n\t\tlogger.log(\n\t\t\t` ✓ Domain: https://${host} (${via === 'created' ? 'created' : 'existing'})`,\n\t\t);\n\t\tapplied(\n\t\t\t{\n\t\t\t\tkey: `domain:${host}`,\n\t\t\t\tresourceType: 'domain',\n\t\t\t\taction: via === 'created' ? 'create' : 'reuse',\n\t\t\t\tid: resource.domainId,\n\t\t\t},\n\t\t\tvia,\n\t\t);\n\t\treturn resource.domainId;\n\t} catch (domainError) {\n\t\t// The state store failing is not a domain failing: a conflict means\n\t\t// another run wrote the stage, and carrying on would overwrite it. Nor\n\t\t// is the caller stopping the run.\n\t\tif (\n\t\t\tdomainError instanceof StateVersionConflict ||\n\t\t\tdomainError instanceof StateStoreBusy ||\n\t\t\tisAbort(domainError)\n\t\t) {\n\t\t\tthrow domainError;\n\t\t}\n\t\tconst message =\n\t\t\tdomainError instanceof Error ? domainError.message : 'Unknown error';\n\t\tlogger.log(` ⚠ Domain creation failed: ${message}`);\n\t\treturn undefined;\n\t}\n}\n\n/** Whether `error` is a run being stopped rather than something failing. */\nfunction isAbort(error: unknown): boolean {\n\treturn error instanceof Error && error.name === 'AbortError';\n}\n\n/** Records a resource the run created or found, and tells the caller. */\ntype Applied = (\n\tchange: ResourceChange & { id: string },\n\tvia: ResourceVia,\n) => void;\n\n/**\n * Where docker runs for one app: the workspace root, building from the\n * Dockerfile `gkm docker` writes for the app there.\n */\nfunction dockerRun(\n\tworkspace: NormalizedWorkspace,\n\tapp: NormalizedAppConfig,\n\tctx: DokployContext,\n): {\n\tcwd: string;\n\tappPath: string;\n\tsignal?: AbortSignal;\n\tstdio?: RunOptions['stdio'];\n} {\n\treturn {\n\t\t// The workspace's root, never the process's: a deploy started anywhere\n\t\t// — or by a host whose working directory is its own — builds the\n\t\t// same image.\n\t\tcwd: workspace.root,\n\t\tappPath: app.path,\n\t\t...(ctx.signal ? { signal: ctx.signal } : {}),\n\t\t...(ctx.stdio ? { stdio: ctx.stdio } : {}),\n\t};\n}\n\n/** The Dokploy login, from the run's provider, or `MissingCredential`. */\nexport async function dokployApi(\n\tworkspace: NormalizedWorkspace,\n\tctx: Pick<DokployContext, 'credentials' | 'signal'>,\n): Promise<{ api: DokployApi; endpoint: string }> {\n\tconst configured = workspace.deploy.dokploy?.endpoint;\n\tconst creds = await ctx.credentials.get(\n\t\t{ kind: 'dokploy', ...(configured ? { endpoint: configured } : {}) },\n\t\t{ signal: ctx.signal },\n\t);\n\tif (!creds) throw new MissingCredential('dokploy', configured);\n\n\treturn {\n\t\tapi: new DokployApi({\n\t\t\tbaseUrl: creds.endpoint,\n\t\t\ttoken: creds.token,\n\t\t\t...(ctx.signal ? { signal: ctx.signal } : {}),\n\t\t}),\n\t\tendpoint: creds.endpoint,\n\t};\n}\n\n/** Each app's public host, the same way the deploy resolves it. */\nfunction hostOf(\n\tworkspace: NormalizedWorkspace,\n\tappName: string,\n\tstage: string,\n): string {\n\tconst app = workspace.apps[appName]!;\n\treturn resolveHost(\n\t\tappName,\n\t\tapp,\n\t\tstage,\n\t\tworkspace.deploy?.domains,\n\t\tapp.type === 'web' && isMainFrontendApp(appName, app, workspace.apps),\n\t);\n}\n\n/**\n * What a deploy would do, from the same lookups it starts with — and nothing\n * else: no lock, no state written, no secret generated, no Dokploy resource\n * created or changed, no image built or pushed.\n */\nexport async function planDokploy(run: DokployRun): Promise<void> {\n\tconst { workspace, manifest, stage, imageTag, appsToDeployNames, identity } =\n\t\trun;\n\tconst { ctx } = run;\n\tlogger.log(\n\t\t'\\n🔎 Dry run: nothing will be created, changed, built or pushed.',\n\t);\n\n\tconst changes: ResourceChange[] = [];\n\tconst plan = (change: ResourceChange, detail: string) => {\n\t\tchanges.push(change);\n\t\tctx.emit({ type: 'resource.planned', ...change });\n\t\tconst sign = change.action === 'reuse' ? '=' : '+';\n\t\tlogger.log(` ${sign} ${change.action} ${change.key} (${detail})`);\n\t};\n\n\tconst { api } = await dokployApi(workspace, ctx);\n\tconst state = (await run.store.read(stage))?.state;\n\n\tconst project = await findProject(api, identity, state?.projectId);\n\tif (project) {\n\t\tplan(\n\t\t\t{\n\t\t\t\tkey: 'project',\n\t\t\t\tresourceType: 'project',\n\t\t\t\taction: 'reuse',\n\t\t\t\tid: project.projectId,\n\t\t\t},\n\t\t\tproject.needsClaim\n\t\t\t\t? `${project.name}, would be claimed for ${identity.key}`\n\t\t\t\t: project.name,\n\t\t);\n\t} else {\n\t\tplan(\n\t\t\t{ key: 'project', resourceType: 'project', action: 'create' },\n\t\t\tprojectName(identity),\n\t\t);\n\t}\n\n\tconst environment = project?.environments.find(\n\t\t(e) => e.name.toLowerCase() === stage.toLowerCase(),\n\t);\n\tplan(\n\t\tenvironment\n\t\t\t? {\n\t\t\t\t\tkey: 'environment',\n\t\t\t\t\tresourceType: 'environment',\n\t\t\t\t\taction: 'reuse',\n\t\t\t\t\tid: environment.environmentId,\n\t\t\t\t}\n\t\t\t: { key: 'environment', resourceType: 'environment', action: 'create' },\n\t\tstage,\n\t);\n\n\tlet registryPlanned: ResourceChange | undefined;\n\tconst registry = await resolveRegistry(api, {\n\t\tstage,\n\t\tregistry: workspace.deploy.registry,\n\t\tconfiguredId: workspace.deploy.dokploy?.registryId,\n\t\tstateId: state?.registryId,\n\t\tlog: (message) => logger.log(message),\n\t\t// Planned, not made: what a deploy would create is recorded instead.\n\t\tcreate: async (url) => {\n\t\t\tregistryPlanned = {\n\t\t\t\tkey: 'registry',\n\t\t\t\tresourceType: 'registry',\n\t\t\t\taction: 'create',\n\t\t\t};\n\t\t\treturn { registryId: '', registryName: url } as DokployRegistry;\n\t\t},\n\t});\n\tplan(\n\t\tregistryPlanned ?? {\n\t\t\tkey: 'registry',\n\t\t\tresourceType: 'registry',\n\t\t\taction: 'reuse',\n\t\t\tid: registry.registryId,\n\t\t},\n\t\tregistry.registryName,\n\t);\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tplan(\n\t\t\t{\n\t\t\t\tkey: `construct:${id}`,\n\t\t\t\tresourceType: declaration.kind,\n\t\t\t\taction: 'ensure',\n\t\t\t},\n\t\t\tdeclaration.kind,\n\t\t);\n\t}\n\n\tconst apps: AppDeployResult[] = [];\n\tconst urls: Record<string, string> = {};\n\tfor (const appName of appsToDeployNames) {\n\t\tconst app = workspace.apps[appName]!;\n\t\tif (app.type === 'mobile') continue;\n\n\t\tconst dokployAppName = applicationName(identity, appName);\n\t\tconst recordedId = state?.applications?.[appName];\n\t\tconst existing =\n\t\t\tproject && environment\n\t\t\t\t? ((recordedId\n\t\t\t\t\t\t? await api.getApplication(recordedId).catch(() => null)\n\t\t\t\t\t\t: null) ??\n\t\t\t\t\t(await api.findApplicationByName(\n\t\t\t\t\t\tproject.projectId,\n\t\t\t\t\t\tdokployAppName,\n\t\t\t\t\t\tenvironment.environmentId,\n\t\t\t\t\t)))\n\t\t\t\t: null;\n\t\tplan(\n\t\t\texisting\n\t\t\t\t? {\n\t\t\t\t\t\tkey: `application:${appName}`,\n\t\t\t\t\t\tresourceType: 'application',\n\t\t\t\t\t\taction: 'reuse',\n\t\t\t\t\t\tid: existing.applicationId,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tkey: `application:${appName}`,\n\t\t\t\t\t\tresourceType: 'application',\n\t\t\t\t\t\taction: 'create',\n\t\t\t\t\t},\n\t\t\tdokployAppName,\n\t\t);\n\n\t\tconst ref = imageRefFor(\n\t\t\tidentity,\n\t\t\tappName,\n\t\t\tworkspace.deploy.registry,\n\t\t\timageTag,\n\t\t);\n\t\tplan(\n\t\t\t{ key: `image:${appName}`, resourceType: 'image', action: 'build' },\n\t\t\tref,\n\t\t);\n\n\t\tconst host = hostOf(workspace, appName, stage);\n\t\tconst domain = existing\n\t\t\t? (await api.getDomainsByApplicationId(existing.applicationId)).find(\n\t\t\t\t\t(d) => d.host === host,\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tplan(\n\t\t\tdomain\n\t\t\t\t? {\n\t\t\t\t\t\tkey: `domain:${host}`,\n\t\t\t\t\t\tresourceType: 'domain',\n\t\t\t\t\t\taction: 'reuse',\n\t\t\t\t\t\tid: domain.domainId,\n\t\t\t\t\t}\n\t\t\t\t: { key: `domain:${host}`, resourceType: 'domain', action: 'create' },\n\t\t\t`https://${host}`,\n\t\t);\n\n\t\turls[appName] = `https://${host}`;\n\t\tapps.push({\n\t\t\tappName,\n\t\t\ttype: app.type,\n\t\t\tsuccess: true,\n\t\t\timageRef: ref,\n\t\t\turl: urls[appName],\n\t\t\t...(existing ? { applicationId: existing.applicationId } : {}),\n\t\t});\n\t}\n\n\tfor (const worker of run.workers) {\n\t\tconst dokployAppName = applicationName(identity, worker.name);\n\t\tconst recordedId = state?.applications?.[worker.name];\n\t\tconst existing =\n\t\t\tproject && environment\n\t\t\t\t? ((recordedId\n\t\t\t\t\t\t? await api.getApplication(recordedId).catch(() => null)\n\t\t\t\t\t\t: null) ??\n\t\t\t\t\t(await api.findApplicationByName(\n\t\t\t\t\t\tproject.projectId,\n\t\t\t\t\t\tdokployAppName,\n\t\t\t\t\t\tenvironment.environmentId,\n\t\t\t\t\t)))\n\t\t\t\t: null;\n\t\tplan(\n\t\t\texisting\n\t\t\t\t? {\n\t\t\t\t\t\tkey: `application:${worker.name}`,\n\t\t\t\t\t\tresourceType: 'application',\n\t\t\t\t\t\taction: 'reuse',\n\t\t\t\t\t\tid: existing.applicationId,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tkey: `application:${worker.name}`,\n\t\t\t\t\t\tresourceType: 'application',\n\t\t\t\t\t\taction: 'create',\n\t\t\t\t\t},\n\t\t\t`${dokployAppName}, worker ${worker.id} — no domain`,\n\t\t);\n\t\tconst ref = imageRefFor(\n\t\t\tidentity,\n\t\t\tworker.name,\n\t\t\tworkspace.deploy.registry,\n\t\t\timageTag,\n\t\t);\n\t\tplan(\n\t\t\t{ key: `image:${worker.name}`, resourceType: 'image', action: 'build' },\n\t\t\tref,\n\t\t);\n\t\tapps.push({\n\t\t\tappName: worker.name,\n\t\t\ttype: 'backend',\n\t\t\tsuccess: true,\n\t\t\timageRef: ref,\n\t\t\t...(existing ? { applicationId: existing.applicationId } : {}),\n\t\t});\n\t}\n\n\tconst creates = changes.filter((c) => c.action !== 'reuse').length;\n\tlogger.log(\n\t\t`\\n✅ Dry run complete: ${creates} to create or build, ${changes.length - creates} to reuse.`,\n\t);\n\n\trun.result = {\n\t\tapps,\n\t\tprojectId: project?.projectId ?? '',\n\t\tenvironmentId: environment?.environmentId ?? '',\n\t\tsuccessCount: apps.length,\n\t\tfailedCount: 0,\n\t\tstage,\n\t\tidentity: identity.key,\n\t\ttag: imageTag,\n\t\tdryRun: true,\n\t\tskipped: [...run.skipped],\n\t\turls,\n\t\tchanges,\n\t};\n}\n\n/** Why a mobile app is left out of a Dokploy deploy. */\nconst MOBILE_SKIP_REASON = 'deploys via its framework toolchain';\n"],"mappings":"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"}
|