@geekmidas/cli 10.0.0-alpha.96 → 10.0.0-alpha.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{GoDaddyProvider-BsUKjGcg.mjs → GoDaddyProvider-AqNu60WQ.mjs} +2 -2
- package/dist/{GoDaddyProvider-BsUKjGcg.mjs.map → GoDaddyProvider-AqNu60WQ.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-DyHXHDHe.cjs → GoDaddyProvider-B4R_QFl8.cjs} +2 -2
- package/dist/{GoDaddyProvider-DyHXHDHe.cjs.map → GoDaddyProvider-B4R_QFl8.cjs.map} +1 -1
- package/dist/{LegacyStateStore-B6SOqRFi.mjs → LegacyStateStore-8F05-BOo.mjs} +3 -3
- package/dist/{LegacyStateStore-B6SOqRFi.mjs.map → LegacyStateStore-8F05-BOo.mjs.map} +1 -1
- package/dist/{LegacyStateStore-BnMcONE0.cjs → LegacyStateStore-B-aRqRdD.cjs} +3 -3
- package/dist/{LegacyStateStore-BnMcONE0.cjs.map → LegacyStateStore-B-aRqRdD.cjs.map} +1 -1
- package/dist/{LocalStateStore-pd4bbdJJ.cjs → LocalStateStore-B_bRI8M7.cjs} +2 -2
- package/dist/{LocalStateStore-pd4bbdJJ.cjs.map → LocalStateStore-B_bRI8M7.cjs.map} +1 -1
- package/dist/{LocalStateStore-6CrsZzqI.mjs → LocalStateStore-B_mfgcO8.mjs} +2 -2
- package/dist/{LocalStateStore-6CrsZzqI.mjs.map → LocalStateStore-B_mfgcO8.mjs.map} +1 -1
- package/dist/{S3StateStore-DP_7Q4yb.mjs → S3StateStore-CMN0Uzdp.mjs} +69 -8
- package/dist/S3StateStore-CMN0Uzdp.mjs.map +1 -0
- package/dist/{S3StateStore-CoGk6ZKU.cjs → S3StateStore-zK9zcd9f.cjs} +69 -8
- package/dist/S3StateStore-zK9zcd9f.cjs.map +1 -0
- package/dist/{SSMStateStore-D9s4_Do3.cjs → SSMStateStore-C489DnR6.cjs} +58 -7
- package/dist/SSMStateStore-C489DnR6.cjs.map +1 -0
- package/dist/{SSMStateStore-Bo6_KDYY.mjs → SSMStateStore-Cv7VcMak.mjs} +58 -7
- package/dist/SSMStateStore-Cv7VcMak.mjs.map +1 -0
- package/dist/{add-BQS2QZHp.mjs → add-BA5d4pA0.mjs} +4 -4
- package/dist/{add-BQS2QZHp.mjs.map → add-BA5d4pA0.mjs.map} +1 -1
- package/dist/{add-CjURJ-vI.cjs → add-HXzTCy_I.cjs} +4 -4
- package/dist/{add-CjURJ-vI.cjs.map → add-HXzTCy_I.cjs.map} +1 -1
- package/dist/{bundler-BMM3UsGm.mjs → bundler-CBomFsnd.mjs} +5 -5
- package/dist/{bundler-BMM3UsGm.mjs.map → bundler-CBomFsnd.mjs.map} +1 -1
- package/dist/{bundler-DmLJQ7AY.cjs → bundler-SX3Uy8qT.cjs} +5 -5
- package/dist/{bundler-DmLJQ7AY.cjs.map → bundler-SX3Uy8qT.cjs.map} +1 -1
- package/dist/{cli-C2c-jOVK.cjs → cli-1l0L9LCA.cjs} +2 -2
- package/dist/{cli-C2c-jOVK.cjs.map → cli-1l0L9LCA.cjs.map} +1 -1
- package/dist/{cli-Ce6NgaQF.mjs → cli-D7z1lQtO.mjs} +2 -2
- package/dist/{cli-Ce6NgaQF.mjs.map → cli-D7z1lQtO.mjs.map} +1 -1
- package/dist/{compose-ETFKqkTu.cjs → compose-C39XupJu.cjs} +7 -7
- package/dist/{compose-ETFKqkTu.cjs.map → compose-C39XupJu.cjs.map} +1 -1
- package/dist/{compose-BJDPFBAN.mjs → compose-DgWrNd2k.mjs} +7 -7
- package/dist/{compose-BJDPFBAN.mjs.map → compose-DgWrNd2k.mjs.map} +1 -1
- package/dist/{config-C8NPCn1l.d.mts → config-D-k0gaAr.d.mts} +4 -4
- package/dist/{config-4yirvxS8.d.cts.map → config-D-k0gaAr.d.mts.map} +1 -1
- package/dist/{config-4yirvxS8.d.cts → config-xIWIaDhW.d.cts} +4 -4
- package/dist/{config-C8NPCn1l.d.mts.map → config-xIWIaDhW.d.cts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/deploy/public.cjs +7 -7
- package/dist/deploy/public.d.cts +5 -5
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +5 -5
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +7 -7
- package/dist/{deploy-BdN0ym2i.cjs → deploy-Cu_HyWoJ.cjs} +19 -8
- package/dist/deploy-Cu_HyWoJ.cjs.map +1 -0
- package/dist/{deploy-DktQl7ti.mjs → deploy-LY-20Yeb.mjs} +19 -8
- package/dist/{deploy-DktQl7ti.mjs.map → deploy-LY-20Yeb.mjs.map} +1 -1
- package/dist/{discover-D-MdXZgm.d.mts → discover-CbJCQq4J.d.mts} +2 -2
- package/dist/{discover-BtFofyQB.d.cts.map → discover-CbJCQq4J.d.mts.map} +1 -1
- package/dist/{discover-BtFofyQB.d.cts → discover-RCW5mBXb.d.cts} +2 -2
- package/dist/{discover-D-MdXZgm.d.mts.map → discover-RCW5mBXb.d.cts.map} +1 -1
- package/dist/{dns-C-X6PLkV.cjs → dns-BFnoawgh.cjs} +3 -3
- package/dist/{dns-C-X6PLkV.cjs.map → dns-BFnoawgh.cjs.map} +1 -1
- package/dist/{dns-C2EeR6n2.mjs → dns-BbTOzmVp.mjs} +3 -3
- package/dist/{dns-C2EeR6n2.mjs.map → dns-BbTOzmVp.mjs.map} +1 -1
- package/dist/{dns-BjHECDO7.mjs → dns-Bmbhmz41.mjs} +5 -5
- package/dist/{dns-BjHECDO7.mjs.map → dns-Bmbhmz41.mjs.map} +1 -1
- package/dist/{dns-ClI7-d5g.cjs → dns-Dro_vbk9.cjs} +5 -5
- package/dist/{dns-ClI7-d5g.cjs.map → dns-Dro_vbk9.cjs.map} +1 -1
- package/dist/{dokploy-CD_Bc4EV.cjs → dokploy-CKgSww82.cjs} +2 -2
- package/dist/{dokploy-CD_Bc4EV.cjs.map → dokploy-CKgSww82.cjs.map} +1 -1
- package/dist/{dokploy-CxtkS5hl.mjs → dokploy-LR94sBVI.mjs} +2 -2
- package/dist/{dokploy-CxtkS5hl.mjs.map → dokploy-LR94sBVI.mjs.map} +1 -1
- package/dist/{encryption-BgQd4f2S.mjs → encryption-C0plOf4a.mjs} +3 -3
- package/dist/{encryption-BgQd4f2S.mjs.map → encryption-C0plOf4a.mjs.map} +1 -1
- package/dist/{encryption-CqVfz-m7.cjs → encryption-CUyw-8sc.cjs} +3 -3
- package/dist/{encryption-CqVfz-m7.cjs.map → encryption-CUyw-8sc.cjs.map} +1 -1
- package/dist/{engine-OVVKtPmW.cjs → engine-D8TeraDK.cjs} +4 -4
- package/dist/{engine-OVVKtPmW.cjs.map → engine-D8TeraDK.cjs.map} +1 -1
- package/dist/{engine-YlXzlTUl.mjs → engine-DqbqQhck.mjs} +4 -4
- package/dist/{engine-YlXzlTUl.mjs.map → engine-DqbqQhck.mjs.map} +1 -1
- package/dist/{github-CsMloeSL.cjs → github-DC4SIqV1.cjs} +35 -20
- package/dist/github-DC4SIqV1.cjs.map +1 -0
- package/dist/{github-DuuvqI3Z.mjs → github-zgaBOQvh.mjs} +35 -20
- package/dist/github-zgaBOQvh.mjs.map +1 -0
- package/dist/{index-5eL8rM6H.d.mts → index-ClqOsbBl.d.mts} +2 -2
- package/dist/{index-5eL8rM6H.d.mts.map → index-ClqOsbBl.d.mts.map} +1 -1
- package/dist/{index-Dz-gyjm_.d.cts → index-DgOBAEl5.d.cts} +2 -2
- package/dist/{index-Dz-gyjm_.d.cts.map → index-DgOBAEl5.d.cts.map} +1 -1
- package/dist/index.cjs +56 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +56 -52
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-CB8B6W9y.mjs → migrate-BJ8aLOWk.mjs} +3 -3
- package/dist/{migrate-CB8B6W9y.mjs.map → migrate-BJ8aLOWk.mjs.map} +1 -1
- package/dist/{migrate-CsPFHgTs.mjs → migrate-C230QeXU.mjs} +3 -3
- package/dist/{migrate-CsPFHgTs.mjs.map → migrate-C230QeXU.mjs.map} +1 -1
- package/dist/{migrate-BAmJeVq1.cjs → migrate-CWq8-s21.cjs} +3 -3
- package/dist/{migrate-BAmJeVq1.cjs.map → migrate-CWq8-s21.cjs.map} +1 -1
- package/dist/{migrate-BdkoNdIu.cjs → migrate-CsMrI7Dk.cjs} +3 -3
- package/dist/{migrate-BdkoNdIu.cjs.map → migrate-CsMrI7Dk.cjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/projectBucket-BFp-SFee.mjs +177 -0
- package/dist/projectBucket-BFp-SFee.mjs.map +1 -0
- package/dist/projectBucket-Cho9DpSh.cjs +206 -0
- package/dist/projectBucket-Cho9DpSh.cjs.map +1 -0
- package/dist/reconcile/public.d.cts +2 -2
- package/dist/reconcile/public.d.mts +2 -2
- package/dist/{resolve-CUne0qOm.mjs → resolve-6EYNqYdr.mjs} +3 -3
- package/dist/{resolve-CUne0qOm.mjs.map → resolve-6EYNqYdr.mjs.map} +1 -1
- package/dist/{resolve-BDatNOoG.cjs → resolve-C8VkR4oW.cjs} +3 -3
- package/dist/{resolve-BDatNOoG.cjs.map → resolve-C8VkR4oW.cjs.map} +1 -1
- package/dist/{rollback-CCdEEEcF.mjs → rollback-BsThTeSN.mjs} +7 -6
- package/dist/{rollback-CCdEEEcF.mjs.map → rollback-BsThTeSN.mjs.map} +1 -1
- package/dist/{rollback-CuG3DkTY.cjs → rollback-CvGfm4DX.cjs} +7 -6
- package/dist/{rollback-CuG3DkTY.cjs.map → rollback-CvGfm4DX.cjs.map} +1 -1
- package/dist/{runtime-Vr6mleo2.d.mts → runtime-CaW4QqF2.d.cts} +2 -2
- package/dist/{runtime-DUQdM-mW.d.cts.map → runtime-CaW4QqF2.d.cts.map} +1 -1
- package/dist/{runtime-DUQdM-mW.d.cts → runtime-K5uxp6HE.d.mts} +2 -2
- package/dist/{runtime-Vr6mleo2.d.mts.map → runtime-K5uxp6HE.d.mts.map} +1 -1
- package/dist/{sandbox-DGOsMPMf.d.mts → sandbox-B_BkfmTP.d.mts} +2 -2
- package/dist/{sandbox-BbJmh2rI.d.cts.map → sandbox-B_BkfmTP.d.mts.map} +1 -1
- package/dist/{sandbox-BbJmh2rI.d.cts → sandbox-D8cfZUAA.d.cts} +2 -2
- package/dist/{sandbox-DGOsMPMf.d.mts.map → sandbox-D8cfZUAA.d.cts.map} +1 -1
- package/dist/{secrets-C5qROlbp.cjs → secrets-BTY6JhTp.cjs} +3 -3
- package/dist/{secrets-C5qROlbp.cjs.map → secrets-BTY6JhTp.cjs.map} +1 -1
- package/dist/{secrets-ZikTIxEm.mjs → secrets-HzKNTWg9.mjs} +3 -3
- package/dist/{secrets-ZikTIxEm.mjs.map → secrets-HzKNTWg9.mjs.map} +1 -1
- package/dist/{seeds-BjXW-Krf.cjs → seeds-BQlj9Fsg.cjs} +4 -4
- package/dist/{seeds-BjXW-Krf.cjs.map → seeds-BQlj9Fsg.cjs.map} +1 -1
- package/dist/{seeds-CbJSne1A.mjs → seeds-BsJRUL1K.mjs} +4 -4
- package/dist/{seeds-CbJSne1A.mjs.map → seeds-BsJRUL1K.mjs.map} +1 -1
- package/dist/{sniffer-NPD1dyab.cjs → sniffer-CeUKUoHn.cjs} +100 -10
- package/dist/sniffer-CeUKUoHn.cjs.map +1 -0
- package/dist/{sniffer-DQGBYY8i.mjs → sniffer-DVsvP8s-.mjs} +77 -11
- package/dist/sniffer-DVsvP8s-.mjs.map +1 -0
- package/dist/{stack-BFq3K-_z.mjs → stack-BQOyqaVG.mjs} +3 -3
- package/dist/{stack-BFq3K-_z.mjs.map → stack-BQOyqaVG.mjs.map} +1 -1
- package/dist/{stack-DOVvEd1T.cjs → stack-Clzi40EE.cjs} +3 -3
- package/dist/{stack-DOVvEd1T.cjs.map → stack-Clzi40EE.cjs.map} +1 -1
- package/dist/{stages-Cw6urZyJ.cjs → stages-BpDXFPGg.cjs} +4 -4
- package/dist/{stages-Cw6urZyJ.cjs.map → stages-BpDXFPGg.cjs.map} +1 -1
- package/dist/{stages-BEn2ArJZ.mjs → stages-DEmn7qI8.mjs} +4 -4
- package/dist/{stages-BEn2ArJZ.mjs.map → stages-DEmn7qI8.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-dipJRmKV.d.cts → types-4vPS_YFX.d.cts} +21 -4
- package/dist/types-4vPS_YFX.d.cts.map +1 -0
- package/dist/{types-bkqVscdN.d.mts → types-CFsEyFb1.d.mts} +21 -4
- package/dist/types-CFsEyFb1.d.mts.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-CqFUjObk.mjs → workspace-Bv4xROeu.mjs} +8 -4
- package/dist/workspace-Bv4xROeu.mjs.map +1 -0
- package/dist/{workspace-DDkm4y6D.cjs → workspace-C1M-S4al.cjs} +8 -4
- package/dist/workspace-C1M-S4al.cjs.map +1 -0
- package/package.json +16 -15
- package/dist/S3StateStore-CoGk6ZKU.cjs.map +0 -1
- package/dist/S3StateStore-DP_7Q4yb.mjs.map +0 -1
- package/dist/SSMStateStore-Bo6_KDYY.mjs.map +0 -1
- package/dist/SSMStateStore-D9s4_Do3.cjs.map +0 -1
- package/dist/deploy-BdN0ym2i.cjs.map +0 -1
- package/dist/github-CsMloeSL.cjs.map +0 -1
- package/dist/github-DuuvqI3Z.mjs.map +0 -1
- package/dist/sniffer-DQGBYY8i.mjs.map +0 -1
- package/dist/sniffer-NPD1dyab.cjs.map +0 -1
- package/dist/types-bkqVscdN.d.mts.map +0 -1
- package/dist/types-dipJRmKV.d.cts.map +0 -1
- package/dist/workspace-CqFUjObk.mjs.map +0 -1
- package/dist/workspace-DDkm4y6D.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-CqFUjObk.mjs","names":["z.union","z.string","z.array","z.object","z.boolean","z.number","z.enum","z.custom","z.tuple","z.unknown","z\n\t.object","z.url","z\n\t\t\t.record","z\n\t\t\t.object","z\n\t\t\t\t\t.string","z.literal","z\n\t\t.object","z.record","z\n\t\t.number","z.discriminatedUnion","z\n\t\t\t.union","z\n\t\t\t\t\t.object","z\n\t.record","z\n\t\t\t\t.object","z\n\t\t.record","z\n\t\t.string","z\n\t\t\t.array"],"sources":["../src/secrets/providers.ts","../src/compose/dnsConfig.ts","../src/compose/proxy.ts","../src/providers/s3/errors.ts","../src/providers/s3/config.ts","../src/providers/config.ts","../src/compose/logsConfig.ts","../src/telemetry/config.ts","../src/workspace/stages.ts","../src/workspace/schema.ts","../src/workspace/types.ts","../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"sourcesContent":["/**\n * The secrets stores gkm ships, by name — with no imports, so the config\n * loader can check `secrets.store` without loading any store.\n */\n\nimport { GkmError } from '../errors';\n\n/** The stores this package ships, by the name `secrets.store` gives them. */\nexport const SECRETS_STORE_PROVIDERS = [\n\t'file',\n\t'ssm',\n\t'secrets-manager',\n] as const;\n\nexport type SecretsStoreProvider = (typeof SECRETS_STORE_PROVIDERS)[number];\n\n/**\n * `secrets.store` names a provider this package does not ship — a typo such\n * as `'secretsmanager'` or `'ssm-parameter'`. Refused rather than read as the\n * file, which would leave a deployed stage's secrets on one machine.\n */\nexport class UnknownSecretsStoreProvider extends GkmError {\n\tconstructor(readonly provider: unknown) {\n\t\tsuper(\n\t\t\t`secrets.store names the provider ${JSON.stringify(provider)}, which is not one gkm ships. ` +\n\t\t\t\t`Use 'file', { provider: 'ssm', region }, { provider: 'secrets-manager', region }, ` +\n\t\t\t\t'or { provider: <an object with name, read() and write()> } in gkm.config.ts.',\n\t\t);\n\t\tthis.name = 'UnknownSecretsStoreProvider';\n\t}\n}\n\n/**\n * Refuse a `secrets.store` naming a provider that is not one, before the\n * schema reduces it to a generic validation failure.\n */\nexport function assertKnownSecretsStore(store: unknown): void {\n\tif (store === undefined) return;\n\tconst provider =\n\t\ttypeof store === 'object' && store !== null && 'provider' in store\n\t\t\t? (store as { provider: unknown }).provider\n\t\t\t: store;\n\tif (\n\t\ttypeof provider === 'string' &&\n\t\t!(SECRETS_STORE_PROVIDERS as readonly string[]).includes(provider)\n\t) {\n\t\tthrow new UnknownSecretsStoreProvider(provider);\n\t}\n}\n","/**\n * `dns['<root domain>'].records` — how a domain's hosts point at a compose\n * stage's server — checked and read. Pure, and kept apart from the DNS step\n * so the workspace schema checks a config with the same rules and the same\n * named errors the step applies.\n */\n\nimport { GkmError } from '../errors';\n\n/** The stage-secret key holding the server's public IPv4 address. */\nexport const SERVER_IPV4_KEY = 'GKM_SERVER_IPV4';\n/** The stage-secret key holding the server's public IPv6 address, if any. */\nexport const SERVER_IPV6_KEY = 'GKM_SERVER_IPV6';\n\n/**\n * Whether a stage secret is gkm's own — the server's address — and so never\n * written into an app's or a worker's environment.\n */\nexport function isReservedStageKey(key: string): boolean {\n\treturn key.startsWith('GKM_SERVER_');\n}\n\n/** A records mode as written: `'a'`, or a CNAME target — one, or per stage. */\nexport type DnsRecordsMode =\n\t| 'a'\n\t| {\n\t\t\tmode: 'cname';\n\t\t\ttarget: string | Readonly<Record<string, string>>;\n\t };\n\n/** A DNS hostname: dot-separated labels of letters, digits and inner '-'. */\nconst HOSTNAME =\n\t/^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/i;\n\n/** Whether `value` is a DNS hostname with at least two labels. */\nexport function isHostname(value: unknown): value is string {\n\treturn typeof value === 'string' && HOSTNAME.test(value);\n}\n\n/** A CNAME target that is not a hostname under its own domain. */\nexport class DnsTargetInvalid extends GkmError {\n\tconstructor(\n\t\treadonly domain: string,\n\t\treadonly target: unknown,\n\t\treadonly stage?: string,\n\t) {\n\t\tsuper(\n\t\t\t`dns['${domain}'].records.target${stage ? ` for '${stage}'` : ''} is ` +\n\t\t\t\t`${JSON.stringify(target)}, which is not a hostname under ${domain}. ` +\n\t\t\t\t\"Every host's CNAME points at it and gkm writes its A record, so it \" +\n\t\t\t\t`must be a name in the same zone — like 'server.${domain}'.`,\n\t\t);\n\t\tthis.name = 'DnsTargetInvalid';\n\t}\n}\n\n/** The CNAME target names under one domain, by the stage they are for, checked. */\nfunction targets(records: {\n\ttarget?: unknown;\n}): [string | undefined, unknown][] {\n\tconst { target } = records;\n\tif (target && typeof target === 'object' && !Array.isArray(target)) {\n\t\treturn Object.entries(target);\n\t}\n\treturn [[undefined, target]];\n}\n\n/**\n * One domain's records mode checked.\n *\n * @throws {DnsTargetInvalid} for a target that is not a hostname under it\n */\nexport function checkDnsRecordsMode(domain: string, records: unknown): void {\n\tif (!records || typeof records !== 'object') return;\n\tconst mode = records as { mode?: unknown; target?: unknown };\n\tif (mode.mode !== 'cname') return;\n\tfor (const [stage, target] of targets(mode)) {\n\t\tconst name = typeof target === 'string' ? target.toLowerCase() : target;\n\t\tif (\n\t\t\t!isHostname(name) ||\n\t\t\t!(name as string).endsWith(`.${domain.toLowerCase()}`)\n\t\t) {\n\t\t\tthrow new DnsTargetInvalid(domain, target, stage);\n\t\t}\n\t}\n}\n\n/**\n * The CNAME target a domain's hosts point at on `stage`, or `undefined` for\n * A records — including a per-stage map that names no target for it.\n */\nexport function cnameTarget(\n\trecords: DnsRecordsMode | undefined,\n\tstage: string,\n): string | undefined {\n\tif (!records || records === 'a') return undefined;\n\tconst target =\n\t\ttypeof records.target === 'string' ? records.target : records.target[stage];\n\treturn target?.toLowerCase();\n}\n","/**\n * Which proxy a stage's stack is served by, and with whose certificate —\n * `deploy.compose.proxy` and `deploy.compose.tls`, resolved for one stage.\n *\n * Pure, and kept apart from the stack so the workspace schema can check a\n * config with the same rules — and the same named errors — the stack applies.\n */\n\nimport { isAbsolute, resolve } from 'node:path';\nimport { GkmError } from '../errors';\nimport type {\n\tComposeProxy,\n\tComposeTlsConfig,\n\tComposeWorkspaceConfig,\n} from '../workspace/types.js';\n\n/** A per-stage setting keyed by a stage the workspace does not have. */\nexport class ComposeStageUnknown extends GkmError {\n\tconstructor(\n\t\treadonly setting: 'proxy' | 'tls',\n\t\treadonly stage: string,\n\t\treadonly stages: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`deploy.compose.${setting} names the stage '${stage}', which is not one ` +\n\t\t\t\t`of this workspace's (${stages.join(', ')}). Use a stage from ` +\n\t\t\t\t'stages.local or stages.deployed.',\n\t\t);\n\t\tthis.name = 'ComposeStageUnknown';\n\t}\n}\n\n/**\n * A certificate for the local stage, whose certificates are always Caddy's\n * own CA — the one `gkm trust` installs.\n */\nexport class ComposeTlsOnLocalStage extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`deploy.compose.tls sets a certificate for '${stage}', the local stage, ` +\n\t\t\t\t\"whose certificates always come from Caddy's local CA (`gkm trust` \" +\n\t\t\t\t'installs it). Remove it, or set it for a deployed stage.',\n\t\t);\n\t\tthis.name = 'ComposeTlsOnLocalStage';\n\t}\n}\n\n/** The stage's certificate or key file is not there to read. */\nexport class ComposeTlsFileMissing extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly file: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.compose.tls for '${stage}' names ${file}, and there is no file ` +\n\t\t\t\t'there. Point certFile and keyFile at the PEM certificate (with its ' +\n\t\t\t\t'chain) and key — relative to the workspace root, or absolute.',\n\t\t);\n\t\tthis.name = 'ComposeTlsFileMissing';\n\t}\n}\n\n/**\n * The proxy a stage's stack is served by. The local stage is always Caddy —\n * its internal CA and `gkm trust` — whatever is configured.\n */\nexport function proxyFor(\n\tconfig: ComposeWorkspaceConfig | undefined,\n\tstage: string,\n\tlocal: boolean,\n): ComposeProxy {\n\tif (local) return 'caddy';\n\tconst proxy = config?.proxy;\n\tif (!proxy) return 'caddy';\n\tif (typeof proxy === 'string') return proxy;\n\treturn proxy[stage] ?? 'caddy';\n}\n\n/** A deployed stage's own certificate, its paths absolute, when it sets one. */\nexport function certificateFor(\n\tconfig: ComposeWorkspaceConfig | undefined,\n\tstage: string,\n\troot: string,\n): ComposeTlsConfig | undefined {\n\tconst tls = config?.tls?.[stage];\n\tif (!tls) return undefined;\n\tconst absolute = (file: string) =>\n\t\tisAbsolute(file) ? file : resolve(root, file);\n\treturn { certFile: absolute(tls.certFile), keyFile: absolute(tls.keyFile) };\n}\n\n/**\n * Throws the named error for the first thing wrong with the per-stage\n * settings: a stage the workspace does not have, or a certificate for the\n * local stage.\n */\nexport function checkComposeStages(\n\tconfig: ComposeWorkspaceConfig | undefined,\n\tstages: { local: string; deployed: readonly string[] },\n): void {\n\tconst known = [stages.local, ...stages.deployed];\n\tif (config?.proxy && typeof config.proxy === 'object') {\n\t\tfor (const stage of Object.keys(config.proxy)) {\n\t\t\tif (!known.includes(stage)) {\n\t\t\t\tthrow new ComposeStageUnknown('proxy', stage, known);\n\t\t\t}\n\t\t}\n\t}\n\tfor (const stage of Object.keys(config?.tls ?? {})) {\n\t\tif (stage === stages.local) throw new ComposeTlsOnLocalStage(stage);\n\t\tif (!known.includes(stage)) {\n\t\t\tthrow new ComposeStageUnknown('tls', stage, known);\n\t\t}\n\t}\n}\n","/** What the `s3` provider refuses, and how each is put right. */\n\nimport { GkmError } from '../../errors';\n\n/** An `objects` entry for `s3` with a field it does not take or cannot use. */\nexport class S3ProviderConfigInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly field: string,\n\t\treadonly value: unknown,\n\t\treadonly expected: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.objects.${stage}.${field} is ${JSON.stringify(value)}; ${expected}.`,\n\t\t);\n\t\tthis.name = 'S3ProviderConfigInvalid';\n\t}\n}\n\n/** No region anywhere to create the stage's buckets in. */\nexport class S3RegionRequired extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The s3 provider has no region for the stage '${stage}'. Name one in ` +\n\t\t\t\t`gkm.config.ts: deploy: { objects: { ${stage}: { provider: 's3', ` +\n\t\t\t\t\"region: 'eu-west-1' } } } — or set AWS_REGION.\",\n\t\t);\n\t\tthis.name = 'S3RegionRequired';\n\t}\n}\n\n/** The good name and every suffixed one are taken by other accounts. */\nexport class BucketNameUnavailable extends GkmError {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly tried: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Every name tried for the bucket '${id}' is taken by another AWS ` +\n\t\t\t\t`account: ${tried.join(', ')}. Set deploy.namespace in gkm.config.ts ` +\n\t\t\t\t'to something more particular to you, and run the provision again.',\n\t\t);\n\t\tthis.name = 'BucketNameUnavailable';\n\t}\n}\n\n/** A bucket in this account carries another project's tag. */\nexport class BucketOwnedByAnotherProject extends GkmError {\n\tconstructor(\n\t\treadonly bucket: string,\n\t\treadonly owner: string,\n\t\treadonly project: string,\n\t) {\n\t\tsuper(\n\t\t\t`The bucket '${bucket}' is in this account and tagged gkm:project=` +\n\t\t\t\t`${owner}, not ${project}: another project's. gkm never adopts it. ` +\n\t\t\t\t'Set deploy.namespace in gkm.config.ts so this project names its ' +\n\t\t\t\t'buckets differently.',\n\t\t);\n\t\tthis.name = 'BucketOwnedByAnotherProject';\n\t}\n}\n\n/** The bucket the stage's state names exists, and this account cannot reach it. */\nexport class RecordedBucketUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly bucket: string,\n\t) {\n\t\tsuper(\n\t\t\t`The stage's state records '${bucket}' as the bucket for '${id}', and ` +\n\t\t\t\t'this account cannot reach it — it is in another account, or the ' +\n\t\t\t\t\"credentials are not the stage account's. Run with the account that \" +\n\t\t\t\t'created it (--profile).',\n\t\t);\n\t\tthis.name = 'RecordedBucketUnreachable';\n\t}\n}\n\n/** An IAM user by gkm's name exists, and gkm did not create it for this stage. */\nexport class IamUserNotOwned extends GkmError {\n\tconstructor(\n\t\treadonly user: string,\n\t\treadonly project: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`The IAM user '${user}' exists and is not tagged gkm:project=${project}, ` +\n\t\t\t\t`gkm:stage=${stage}, so gkm leaves it alone. Rename or delete it, or ` +\n\t\t\t\t'set deploy.namespace in gkm.config.ts so gkm names its users differently.',\n\t\t);\n\t\tthis.name = 'IamUserNotOwned';\n\t}\n}\n\n/** The user already has the two access keys IAM allows. */\nexport class AccessKeyLimit extends GkmError {\n\tconstructor(\n\t\treadonly user: string,\n\t\treadonly keys: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`The IAM user '${user}' already has two access keys (${keys.join(', ')}), ` +\n\t\t\t\t'the most IAM allows, and gkm needs to issue one. Delete the one the ' +\n\t\t\t\t`stage does not use (aws iam delete-access-key --user-name ${user} ` +\n\t\t\t\t'--access-key-id …), then run the provision again.',\n\t\t);\n\t\tthis.name = 'AccessKeyLimit';\n\t}\n}\n\n/** `--rotate-keys` while the last rotation's old key is still active. */\nexport class RotationInProgress extends GkmError {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly previous: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`The bucket '${id}' is mid-rotation: its old key ${previous} is still ` +\n\t\t\t\t`active until '${stage}' is deployed with the new one: deploy it ` +\n\t\t\t\t`(gkm deploy --stage ${stage}) — the next deploy after that deletes ` +\n\t\t\t\t'the old key — or pass --retire-old-keys to delete it now, before rotating again.',\n\t\t);\n\t\tthis.name = 'RotationInProgress';\n\t}\n}\n\n/** The stage's secrets point the bucket's key at a bucket gkm did not provision. */\nexport class BucketKeySetElsewhere extends GkmError {\n\tconstructor(\n\t\treadonly key: string,\n\t\treadonly bucket: string,\n\t\treadonly found: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`${key} in the stage '${stage}' points at the bucket '${found}', and ` +\n\t\t\t\t`the s3 provider manages '${bucket}' for it. Remove the key ` +\n\t\t\t\t`(gkm secrets:unset ${key} --stage ${stage}) to have the provider ` +\n\t\t\t\t`write its own, or set deploy.objects.${stage} to 'external' to keep yours.`,\n\t\t);\n\t\tthis.name = 'BucketKeySetElsewhere';\n\t}\n}\n\n/** `verify()`: a provisioned bucket the stage's key cannot reach. */\nexport class ProvisionedBucketUnreachable extends GkmError {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly bucket: string,\n\t\treadonly stage: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`The bucket '${bucket}' (${id}) cannot be reached with the key in the ` +\n\t\t\t\t`stage '${stage}''s secrets: ${reason}. Deploy '${stage}' with the ` +\n\t\t\t\t\"stage account's credentials (gkm deploy --stage \" +\n\t\t\t\t`${stage}), which creates or repairs it — a run with --skip-resources does not.`,\n\t\t);\n\t\tthis.name = 'ProvisionedBucketUnreachable';\n\t}\n}\n\n/**\n * `verify()`: the bucket answers from another region than the one its URL\n * names — S3 redirects (301) or refuses the signature (400) and says where\n * the bucket is.\n */\nexport class BucketRegionMismatch extends GkmError {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly bucket: string,\n\t\treadonly stage: string,\n\t\t/** The secret holding the bucket's URL: `UPLOADS_URL`. */\n\t\treadonly key: string,\n\t\treadonly bucketRegion: string,\n\t\t/** The URL's `region`; absent when it names none. */\n\t\treadonly urlRegion: string | undefined,\n\t\t/** The region asked: the URL's, else the default it fell back to. */\n\t\treadonly askedRegion: string,\n\t\t/** What S3 answered: status, error, request ids. */\n\t\treadonly answer: string,\n\t) {\n\t\tconst says = urlRegion\n\t\t\t? `says ${urlRegion}`\n\t\t\t: `names no region, so ${askedRegion} was asked`;\n\t\tsuper(\n\t\t\t`The bucket '${bucket}' (${id}) is in ${bucketRegion}, but ${key} in ` +\n\t\t\t\t`the stage '${stage}''s secrets ${says} (${answer}). Deploy ` +\n\t\t\t\t`'${stage}' with the stage account's credentials (gkm deploy --stage ` +\n\t\t\t\t`${stage}): the s3 provider reads the bucket's region and rewrites ` +\n\t\t\t\t`${key} with it. Set deploy.objects.${stage}.region to ` +\n\t\t\t\t`'${bucketRegion}' in gkm.config.ts so the stage's config says where ` +\n\t\t\t\t'its buckets are.',\n\t\t);\n\t\tthis.name = 'BucketRegionMismatch';\n\t}\n}\n\n/** Neither `HeadBucket` nor `GetBucketLocation` says where a bucket is. */\nexport class BucketRegionUnknown extends GkmError {\n\tconstructor(\n\t\treadonly bucket: string,\n\t\t/** What `HeadBucket` answered. */\n\t\treadonly head: string,\n\t\t/** What `GetBucketLocation` answered. */\n\t\treadonly location: string,\n\t) {\n\t\tsuper(\n\t\t\t`gkm cannot tell which region the bucket '${bucket}' is in: ` +\n\t\t\t\t`HeadBucket answered ${head}, and GetBucketLocation ${location}. ` +\n\t\t\t\t\"Check that the provisioning credentials are the stage account's \" +\n\t\t\t\t'and may call s3:GetBucketLocation on it, then run the deploy again.',\n\t\t);\n\t\tthis.name = 'BucketRegionUnknown';\n\t}\n}\n\n/** `HeadBucket` answered neither yes, no, nor \"another account's\". */\nexport class BucketProbeFailed extends GkmError {\n\tconstructor(\n\t\treadonly bucket: string,\n\t\t/** What S3 answered: status, error, request ids. */\n\t\treadonly answer: string,\n\t) {\n\t\tsuper(\n\t\t\t`gkm asked S3 whether the bucket '${bucket}' exists and got ${answer}. ` +\n\t\t\t\t\"Check the provisioning credentials and the stage's region, then run the deploy again.\",\n\t\t);\n\t\tthis.name = 'BucketProbeFailed';\n\t}\n}\n","/** `deploy.objects.<stage>` for the `s3` provider, checked. */\n\nimport type { S3ObjectsConfig } from '../../workspace/types.js';\nimport type { ProviderConfig } from '../types.js';\nimport { S3ProviderConfigInvalid } from './errors.js';\n\nconst FIELDS = ['provider', 'region', 'versioning'] as const;\n\n/** An AWS region code: `eu-west-1`, `us-gov-west-1`, `ap-southeast-4`. */\nconst REGION = /^[a-z]{2}(-[a-z]+)+-\\d+$/;\n\nexport function checkS3Config(\n\tstage: string,\n\tconfig: ProviderConfig,\n): S3ObjectsConfig {\n\tconst entry = config as unknown as Record<string, unknown>;\n\tfor (const field of Object.keys(entry)) {\n\t\tif (!(FIELDS as readonly string[]).includes(field)) {\n\t\t\tthrow new S3ProviderConfigInvalid(\n\t\t\t\tstage,\n\t\t\t\tfield,\n\t\t\t\tentry[field],\n\t\t\t\t`the s3 provider takes ${FIELDS.slice(1).join(' and ')} only`,\n\t\t\t);\n\t\t}\n\t}\n\tif (entry.region !== undefined) {\n\t\tif (typeof entry.region !== 'string' || !REGION.test(entry.region)) {\n\t\t\tthrow new S3ProviderConfigInvalid(\n\t\t\t\tstage,\n\t\t\t\t'region',\n\t\t\t\tentry.region,\n\t\t\t\t\"set it to an AWS region code, like 'eu-west-1'\",\n\t\t\t);\n\t\t}\n\t}\n\tif (entry.versioning !== undefined && typeof entry.versioning !== 'boolean') {\n\t\tthrow new S3ProviderConfigInvalid(\n\t\t\tstage,\n\t\t\t'versioning',\n\t\t\tentry.versioning,\n\t\t\t'set it to true to keep previous versions of every object, or leave it out',\n\t\t);\n\t}\n\treturn entry as unknown as S3ObjectsConfig;\n}\n\n/** How the s3 provider's provisioning credentials are supplied. */\nexport const S3_PROVISIONING = {\n\tenv: [\n\t\t'AWS_PROFILE',\n\t\t'AWS_ACCESS_KEY_ID',\n\t\t'AWS_SECRET_ACCESS_KEY',\n\t\t'AWS_SESSION_TOKEN',\n\t],\n\tdescribe:\n\t\t\"the stage's AWS account — AWS_PROFILE, or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY (in CI, what aws-actions/configure-aws-credentials exports)\",\n} as const;\n","/**\n * `deploy.<kind>.<stage>`, read: what backs one kind of construct on a stage.\n *\n * Kept free of the providers themselves — of the AWS SDK and the graph — so\n * the workspace schema can check an entry with the words a deploy would use,\n * the way `checkStageTelemetry` does for `deploy.telemetry`.\n */\n\nimport { GkmError } from '../errors';\nimport { checkS3Config, S3_PROVISIONING } from './s3/config.js';\nimport type {\n\tProviderConfig,\n\tProviderKind,\n\tResourceProvider,\n\tStageProviderEntry,\n} from './types.js';\n\n/** Each provider's config check, by kind and name. */\nconst CHECKS: {\n\treadonly [K in ProviderKind]: Readonly<\n\t\tRecord<string, (stage: string, config: ProviderConfig) => ProviderConfig>\n\t>;\n} = {\n\tobjects: { s3: checkS3Config },\n};\n\n/** How each provider's provisioning credentials are supplied, by kind and name. */\nconst PROVISIONING: {\n\treadonly [K in ProviderKind]: Readonly<\n\t\tRecord<string, ResourceProvider['provisioning']>\n\t>;\n} = {\n\tobjects: { s3: S3_PROVISIONING },\n};\n\n/** How `name`'s provisioning credentials are supplied, for messages. */\nexport function provisioningOf(\n\tkind: ProviderKind,\n\tname: string,\n): ResourceProvider['provisioning'] | undefined {\n\treturn Object.hasOwn(PROVISIONING[kind], name)\n\t\t? PROVISIONING[kind][name]\n\t\t: undefined;\n}\n\n/** The `provider:` names a kind accepts. */\nexport function providerNamesOf(kind: ProviderKind): string[] {\n\treturn Object.keys(CHECKS[kind]).sort();\n}\n\n/** What `deploy.<kind>.<stage>` may be, for messages. */\nfunction accepted(kind: ProviderKind): string {\n\treturn [\n\t\t\"'external'\",\n\t\t...providerNamesOf(kind).map((name) => `{ provider: '${name}' }`),\n\t\t'false',\n\t].join(', ');\n}\n\n/** An entry that names no provider gkm has, or is not an entry at all. */\nexport class UnknownStageProvider extends GkmError {\n\tconstructor(\n\t\treadonly kind: ProviderKind,\n\t\treadonly stage: string,\n\t\treadonly value: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.${kind}.${stage} is ${JSON.stringify(value)}, which is not a ` +\n\t\t\t\t`provider gkm has for ${kind}. It takes ${accepted(kind)}.`,\n\t\t);\n\t\tthis.name = 'UnknownStageProvider';\n\t}\n}\n\n/**\n * One stage's entry checked: `'external'`, `false`, or a provider's object\n * that its own check accepts.\n *\n * @throws {UnknownStageProvider} for anything else — `'minio'` included\n */\nexport function checkStageProvider(\n\tkind: ProviderKind,\n\tstage: string,\n\tvalue: unknown,\n): StageProviderEntry {\n\tif (value === 'external' || value === false) return value;\n\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\tconst name = (value as { provider?: unknown }).provider;\n\t\tconst check =\n\t\t\ttypeof name === 'string' && Object.hasOwn(CHECKS[kind], name)\n\t\t\t\t? CHECKS[kind][name]\n\t\t\t\t: undefined;\n\t\tif (check) return check(stage, value as ProviderConfig);\n\t}\n\tthrow new UnknownStageProvider(kind, stage, value);\n}\n\n/** What one stage resolves `deploy.<kind>` to. */\nexport type StageProviderChoice =\n\t| { mode: 'external' }\n\t| { mode: 'none' }\n\t| { mode: 'provider'; name: string; config: ProviderConfig };\n\n/** What a stage's `deploy.<kind>` is read from. */\nexport interface StageProviderSource {\n\tdeploy?: Partial<Record<ProviderKind, Record<string, unknown>>> | undefined;\n\tstages?: { local?: string };\n}\n\n/**\n * What backs `kind` on `stage`: the local stage is always `external` here —\n * `gkm dev` runs its own — and a deployed stage that names nothing is too.\n */\nexport function stageProvider(\n\tworkspace: StageProviderSource,\n\tkind: ProviderKind,\n\tstage: string,\n): StageProviderChoice {\n\tif (stage === workspace.stages?.local) return { mode: 'external' };\n\tconst value = workspace.deploy?.[kind]?.[stage];\n\tif (value === undefined) return { mode: 'external' };\n\tconst entry = checkStageProvider(kind, stage, value);\n\tif (entry === 'external') return { mode: 'external' };\n\tif (entry === false) return { mode: 'none' };\n\treturn { mode: 'provider', name: entry.provider, config: entry };\n}\n","/**\n * The self-hosted telemetry provider's options, read: how the stack's\n * OpenObserve is run and reached — `deploy.telemetry.<stage>` with\n * `provider: 'self-hosted'`.\n *\n * Kept apart from the stack so the workspace schema can check a config with\n * the same rules — and the same named errors — the stack applies.\n */\n\nimport { isIP } from 'node:net';\nimport { GkmError } from '../errors';\nimport type { SelfHostedTelemetryConfig } from '../workspace/types.js';\n\n/** The port OpenObserve listens on, and the one it is published on by default. */\nexport const LOGS_PORT = 5080;\n\n/** How many days of data OpenObserve keeps unless told otherwise. */\nexport const LOGS_RETENTION_DAYS = 30;\n\n/** The fewest days OpenObserve accepts: below it, it refuses to start. */\nexport const LOGS_MIN_RETENTION_DAYS = 3;\n\n/** The self-hosted provider's options, with their defaults applied. */\nexport interface ResolvedLogs {\n\t/** The loopback port it is published on. Not published when `public` is set. */\n\tport: number;\n\tretentionDays: number;\n\t/** Served on `logs.<stage domain>`, to these addresses only. */\n\tpublic?: { allow: string[] };\n}\n\n/** `public` with no address to allow: nobody could reach it. */\nexport class LogsAllowEmpty extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.public.allow is empty, so the logs site would ` +\n\t\t\t\t'answer every request with 403. List the addresses that may reach it ' +\n\t\t\t\t\"(public: { allow: ['203.0.113.7', '10.0.0.0/8'] }), or remove public \" +\n\t\t\t\t'and reach it through an SSH tunnel.',\n\t\t);\n\t\tthis.name = 'LogsAllowEmpty';\n\t}\n}\n\n/** An `allow` entry that is not an IP address or a CIDR range. */\nexport class LogsAllowEntryInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly entry: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.public.allow has '${entry}', which is not an IP ` +\n\t\t\t\t\"address or a CIDR range. Write one like '203.0.113.7', \" +\n\t\t\t\t\"'10.0.0.0/8' or '2001:db8::/32'.\",\n\t\t);\n\t\tthis.name = 'LogsAllowEntryInvalid';\n\t}\n}\n\n/** A retention OpenObserve would refuse to start with. */\nexport class LogsRetentionInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly retentionDays: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.retentionDays is ${String(retentionDays)}; it must ` +\n\t\t\t\t`be a whole number of days, at least ${LOGS_MIN_RETENTION_DAYS} — ` +\n\t\t\t\t'OpenObserve refuses to start with fewer. Leave it out for ' +\n\t\t\t\t`${LOGS_RETENTION_DAYS}.`,\n\t\t);\n\t\tthis.name = 'LogsRetentionInvalid';\n\t}\n}\n\n/** A port that is not one. */\nexport class LogsPortInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly port: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.port is ${String(port)}; set it to a number ` +\n\t\t\t\t`between 1 and 65535, or leave it out for ${LOGS_PORT}.`,\n\t\t);\n\t\tthis.name = 'LogsPortInvalid';\n\t}\n}\n\n/** Whether `entry` is an IP address, or an address and a prefix length. */\nfunction isAddressOrRange(entry: string): boolean {\n\tconst [address = '', prefix, ...rest] = entry.split('/');\n\tif (rest.length > 0) return false;\n\tconst family = isIP(address);\n\tif (family === 0) return false;\n\tif (prefix === undefined) return true;\n\tif (!/^\\d{1,3}$/.test(prefix)) return false;\n\treturn Number(prefix) <= (family === 4 ? 32 : 128);\n}\n\n/**\n * The self-hosted provider's options with their defaults — `{}` for all of\n * them. Throws the named error for the first thing wrong with them.\n */\nexport function resolveSelfHosted(\n\tconfig: Omit<SelfHostedTelemetryConfig, 'provider' | 'sampleRate'>,\n\tstage: string,\n): ResolvedLogs {\n\tconst port = config.port ?? LOGS_PORT;\n\tif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n\t\tthrow new LogsPortInvalid(stage, config.port);\n\t}\n\n\tconst retentionDays = config.retentionDays ?? LOGS_RETENTION_DAYS;\n\tif (\n\t\t!Number.isInteger(retentionDays) ||\n\t\tretentionDays < LOGS_MIN_RETENTION_DAYS\n\t) {\n\t\tthrow new LogsRetentionInvalid(stage, config.retentionDays);\n\t}\n\n\tif (config.public) {\n\t\tconst allow = config.public.allow ?? [];\n\t\tif (allow.length === 0) throw new LogsAllowEmpty(stage);\n\t\tfor (const entry of allow) {\n\t\t\tif (!isAddressOrRange(entry))\n\t\t\t\tthrow new LogsAllowEntryInvalid(stage, entry);\n\t\t}\n\t\treturn { port, retentionDays, public: { allow: [...allow] } };\n\t}\n\n\treturn { port, retentionDays };\n}\n","/**\n * `deploy.telemetry`, read: where one stage's telemetry goes, and how much.\n *\n * The application says what it emits (the `Telemetry` construct). This says\n * where it is sent, per stage, and is the only place that does:\n *\n * - **self-hosted** — the target runs OpenObserve beside the apps (#189's\n * stack service). A server target that can run it uses it when a stage\n * names nothing.\n * - **otlp** — any OTLP/HTTP endpoint, with its headers.\n * - **false** — nothing is sent.\n *\n * Vendor presets (a known endpoint and header shape, with the stage secret\n * `TELEMETRY_CREDENTIALS`) are one more entry in {@link PROVIDERS}: a\n * resolver from the stage's config to a {@link ResolvedTelemetry}, which\n * every target already consumes through {@link telemetryEnv}.\n *\n * The local stage ignores all of it: `gkm dev` and `gkm compose` on it run\n * OpenObserve and keep every trace.\n */\n\nimport { type ResolvedLogs, resolveSelfHosted } from '../compose/logsConfig.js';\nimport { GkmError } from '../errors';\nimport type { DeployRuntime } from '../target/types.js';\nimport type {\n\tOtlpTelemetryConfig,\n\tSelfHostedTelemetryConfig,\n\tStageTelemetryConfig,\n} from '../workspace/types.js';\n\n/** A stage's telemetry, its defaults applied and its config checked. */\nexport type ResolvedTelemetry =\n\t| {\n\t\t\tprovider: 'self-hosted';\n\t\t\t/** How the stack's OpenObserve is run and reached. */\n\t\t\tselfHosted: ResolvedLogs;\n\t\t\tsampleRate: number;\n\t }\n\t| {\n\t\t\tprovider: 'otlp';\n\t\t\tendpoint: string;\n\t\t\theaders: Readonly<Record<string, string>>;\n\t\t\tsampleRate: number;\n\t };\n\n/** The providers `deploy.telemetry` can name. */\nexport type TelemetryProviderName = Exclude<\n\tStageTelemetryConfig,\n\tfalse | 'self-hosted'\n>['provider'];\n\n/** A deployed stage uses telemetry and its target cannot choose for it. */\nexport class TelemetryProviderRequired extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' deploys through ${target}, which cannot run ` +\n\t\t\t\t'telemetry itself, and a process uses a Telemetry construct. Say ' +\n\t\t\t\t`where it goes in gkm.config.ts: deploy: { telemetry: { ${stage}: ` +\n\t\t\t\t\"{ provider: 'otlp', endpoint: 'https://…' } } } — or \" +\n\t\t\t\t`deploy: { telemetry: { ${stage}: false } } to send nothing.`,\n\t\t);\n\t\tthis.name = 'TelemetryProviderRequired';\n\t}\n}\n\n/** A stage asks for the self-hosted provider on a target that cannot run it. */\nexport class SelfHostedTelemetryUnavailable extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage} is 'self-hosted', and ${target} does not ` +\n\t\t\t\t'run OpenObserve beside the apps — the compose target does. Deploy ' +\n\t\t\t\t`'${stage}' through compose, or send its telemetry elsewhere: ` +\n\t\t\t\t`deploy: { telemetry: { ${stage}: { provider: 'otlp', endpoint: ` +\n\t\t\t\t\"'https://…' } } }.\",\n\t\t);\n\t\tthis.name = 'SelfHostedTelemetryUnavailable';\n\t}\n}\n\n/** A sample rate that is not a fraction. */\nexport class TelemetrySampleRateInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly sampleRate: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.sampleRate is ${String(sampleRate)}; set it ` +\n\t\t\t\t'to a number from 0 to 1 — the fraction of traces kept — or leave it ' +\n\t\t\t\t'out to keep every one.',\n\t\t);\n\t\tthis.name = 'TelemetrySampleRateInvalid';\n\t}\n}\n\n/** An OTLP endpoint that is not an http(s) URL. */\nexport class TelemetryEndpointInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly endpoint: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.telemetry.${stage}.endpoint is ${JSON.stringify(endpoint)}; set ` +\n\t\t\t\t\"it to the collector's OTLP/HTTP base URL, like \" +\n\t\t\t\t\"'https://otlp.example.com' — /v1/traces and /v1/logs are added to it.\",\n\t\t);\n\t\tthis.name = 'TelemetryEndpointInvalid';\n\t}\n}\n\n/** The sample rate a stage keeps, checked. */\nfunction sampleRateOf(stage: string, sampleRate: number | undefined): number {\n\tconst rate = sampleRate ?? 1;\n\tif (!Number.isFinite(rate) || rate < 0 || rate > 1) {\n\t\tthrow new TelemetrySampleRateInvalid(stage, sampleRate);\n\t}\n\treturn rate;\n}\n\n/**\n * Each provider's resolver: a stage's config to what the targets consume.\n * A vendor preset is one more entry here.\n */\nconst PROVIDERS: {\n\t[P in TelemetryProviderName]: (\n\t\tconfig: Extract<StageTelemetryConfig, { provider: P }>,\n\t\tstage: string,\n\t) => ResolvedTelemetry;\n} = {\n\t'self-hosted': (config: SelfHostedTelemetryConfig, stage) => {\n\t\tconst { provider: _, sampleRate, ...options } = config;\n\t\treturn {\n\t\t\tprovider: 'self-hosted',\n\t\t\tselfHosted: resolveSelfHosted(options, stage),\n\t\t\tsampleRate: sampleRateOf(stage, sampleRate),\n\t\t};\n\t},\n\totlp: (config: OtlpTelemetryConfig, stage) => {\n\t\tif (typeof config.endpoint !== 'string' || !isHttpUrl(config.endpoint)) {\n\t\t\tthrow new TelemetryEndpointInvalid(stage, config.endpoint);\n\t\t}\n\t\treturn {\n\t\t\tprovider: 'otlp',\n\t\t\tendpoint: config.endpoint.replace(/\\/+$/, ''),\n\t\t\theaders: { ...config.headers },\n\t\t\tsampleRate: sampleRateOf(stage, config.sampleRate),\n\t\t};\n\t},\n};\n\nfunction isHttpUrl(value: string): boolean {\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn url.protocol === 'http:' || url.protocol === 'https:';\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * One stage's entry, checked on its own — what the workspace schema runs, so\n * a bad config fails to load with the words a deploy would fail with.\n */\nexport function checkStageTelemetry(\n\tstage: string,\n\tconfig: StageTelemetryConfig,\n): ResolvedTelemetry | undefined {\n\tif (config === false) return undefined;\n\tconst entry: Exclude<StageTelemetryConfig, false | 'self-hosted'> =\n\t\tconfig === 'self-hosted' ? { provider: 'self-hosted' } : config;\n\tconst resolve = PROVIDERS[entry.provider] as (\n\t\tconfig: typeof entry,\n\t\tstage: string,\n\t) => ResolvedTelemetry;\n\treturn resolve(entry, stage);\n}\n\n/** What a stage's telemetry is resolved from. */\nexport interface StageTelemetryInput {\n\t/** `deploy.telemetry`. */\n\ttelemetry?: Readonly<Record<string, StageTelemetryConfig>>;\n\tstage: string;\n\t/** Whether this is the project's local stage, which ignores the config. */\n\tlocal: boolean;\n\t/** The target's name, for messages. */\n\ttarget: string;\n\truntime: DeployRuntime;\n\t/** Whether the target runs the self-hosted provider. */\n\tselfHosted: boolean;\n\t/** Whether any process uses a `Telemetry` node. */\n\tused: boolean;\n}\n\n/**\n * Where a stage's telemetry goes, or undefined when nothing is sent — no\n * process uses a `Telemetry` node, or the stage opted out with `false`.\n *\n * The local stage always runs the self-hosted provider with its defaults and\n * keeps every trace, whatever `deploy.telemetry` says. A deployed stage that\n * names nothing gets the self-hosted provider where its target runs one, and\n * {@link TelemetryProviderRequired} where it cannot — AWS has none.\n */\nexport function resolveStageTelemetry(\n\tinput: StageTelemetryInput,\n): ResolvedTelemetry | undefined {\n\tconst { stage } = input;\n\tif (!input.used) return undefined;\n\n\tif (input.local) {\n\t\treturn {\n\t\t\tprovider: 'self-hosted',\n\t\t\tselfHosted: resolveSelfHosted({}, stage),\n\t\t\tsampleRate: 1,\n\t\t};\n\t}\n\n\tconst config = input.telemetry?.[stage];\n\tif (config === undefined) {\n\t\tif (input.runtime === 'server' && input.selfHosted) {\n\t\t\treturn checkStageTelemetry(stage, 'self-hosted');\n\t\t}\n\t\tthrow new TelemetryProviderRequired(stage, input.target);\n\t}\n\n\tconst resolved = checkStageTelemetry(stage, config);\n\tif (resolved?.provider === 'self-hosted' && !input.selfHosted) {\n\t\tthrow new SelfHostedTelemetryUnavailable(stage, input.target);\n\t}\n\treturn resolved;\n}\n\n/** The sampler every process with the edge runs, per the stage's rate. */\nexport const TRACES_SAMPLER = 'parentbased_traceidratio';\n\n/**\n * `OTEL_EXPORTER_OTLP_HEADERS` for a set of headers: `key=value` pairs,\n * comma-separated, each value percent-encoded — the W3C baggage format the\n * SDK parses.\n */\nexport function otlpHeaderString(\n\theaders: Readonly<Record<string, string>>,\n): string {\n\treturn Object.entries(headers)\n\t\t.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n\t\t.join(',');\n}\n\n/**\n * The `OTEL_*` values a stage resolves for its `Telemetry` node, before any\n * one process is named: where to export, how to sign, and how much to keep.\n * `OTEL_SERVICE_NAME` is each process's own — see `scopeTelemetryEnv`.\n */\nexport function telemetryEnv(\n\tdestination: { endpoint: string; headers?: string },\n\tsampleRate: number,\n): Record<string, string> {\n\treturn {\n\t\tOTEL_EXPORTER_OTLP_ENDPOINT: destination.endpoint,\n\t\t...(destination.headers\n\t\t\t? { OTEL_EXPORTER_OTLP_HEADERS: destination.headers }\n\t\t\t: {}),\n\t\tOTEL_TRACES_SAMPLER: TRACES_SAMPLER,\n\t\tOTEL_TRACES_SAMPLER_ARG: String(sampleRate),\n\t};\n}\n\n/** What an `otlp` stage resolves, for every process with the edge. */\nexport function otlpTelemetryEnv(\n\tresolved: Extract<ResolvedTelemetry, { provider: 'otlp' }>,\n): Record<string, string> {\n\tconst headers = otlpHeaderString(resolved.headers);\n\treturn telemetryEnv(\n\t\t{ endpoint: resolved.endpoint, ...(headers ? { headers } : {}) },\n\t\tresolved.sampleRate,\n\t);\n}\n\n/**\n * The sample rate a stage's browsers trace page views at — a public value,\n * the same rate its servers sample at — or undefined when the stage sends no\n * telemetry. The local stage keeps every trace.\n *\n * Lenient where `resolveStageTelemetry` is strict: a site's client is built\n * before, and apart from, the deploy that refuses a stage with no provider.\n */\nexport function stageSampleRate(\n\ttelemetry: Readonly<Record<string, StageTelemetryConfig>> | undefined,\n\tstage: string,\n\tlocal: boolean,\n): number | undefined {\n\tif (local) return 1;\n\tconst config = telemetry?.[stage];\n\tif (config === false) return undefined;\n\tif (config === undefined || config === 'self-hosted') return 1;\n\treturn sampleRateOf(stage, config.sampleRate);\n}\n","import { GkmError } from '../errors';\nimport type { StagesConfig } from './types.js';\n\n/**\n * What `gkm test` runs as. The CLI's own, so no project stage may take it:\n * its containers are torn down and rebuilt between runs.\n */\nexport const TEST_STAGE = 'test';\n\n/** A stage becomes part of every physical name, so it has to fit in one. */\nconst STAGE_NAME = /^[a-z][a-z0-9-]*$/;\n\n/** Everything wrong with one stage name, or nothing. */\nfunction nameProblems(name: string): string[] {\n\tconst problems: string[] = [];\n\tif (!STAGE_NAME.test(name)) {\n\t\tproblems.push(\n\t\t\t`stage \"${name}\" must be lowercase letters, digits and hyphens, starting with a letter`,\n\t\t);\n\t}\n\tif (name === TEST_STAGE) {\n\t\tproblems.push(`stage \"${TEST_STAGE}\" is reserved for gkm test`);\n\t}\n\treturn problems;\n}\n\n/** Everything wrong with a list of deployed stages on its own. */\nexport function deployedProblems(deployed: readonly string[]): string[] {\n\tconst problems = deployed.flatMap(nameProblems);\n\tconst seen = new Set<string>();\n\tfor (const name of deployed) {\n\t\tif (seen.has(name)) problems.push(`stage \"${name}\" is listed twice`);\n\t\tseen.add(name);\n\t}\n\treturn problems;\n}\n\n/** Everything wrong with a stages block, or nothing. */\nexport function stageProblems(stages: StagesConfig | undefined): string[] {\n\tif (!stages) {\n\t\treturn [\n\t\t\t\"`stages` is required, e.g. stages: { local: 'dev', deployed: ['prod'] }\",\n\t\t];\n\t}\n\n\tconst { local, deployed, protected: kept = [] } = stages;\n\tconst problems = [...nameProblems(local), ...deployedProblems(deployed)];\n\n\tif (deployed.includes(local)) {\n\t\tproblems.push(\n\t\t\t`\"${local}\" is both the local stage and a deployed one; they would share secrets`,\n\t\t);\n\t}\n\n\tfor (const name of kept) {\n\t\tif (!deployed.includes(name)) {\n\t\t\tproblems.push(`protected stage \"${name}\" is not a deployed stage`);\n\t\t}\n\t}\n\n\treturn problems;\n}\n\n/** The stages block, or an error naming everything wrong with it. */\nexport function validateStages(stages: StagesConfig | undefined): StagesConfig {\n\tconst problems = stageProblems(stages);\n\tif (problems.length) {\n\t\tthrow new InvalidStages(problems);\n\t}\n\treturn stages!;\n}\n\n/** Refuses a stage the project does not deploy to. */\nexport function assertDeployedStage(stages: StagesConfig, stage: string): void {\n\tif (!stages.deployed.includes(stage)) {\n\t\tthrow new UndeclaredStage(stage, stages.deployed);\n\t}\n}\n\n/** A stages block — in gkm.config.ts or from `gkm init`'s flags — that breaks a rule. */\nexport class InvalidStages extends GkmError {\n\tconstructor(readonly problems: readonly string[]) {\n\t\tsuper(`Invalid stages:\\n ${problems.join('\\n ')}`);\n\t\tthis.name = 'InvalidStages';\n\t}\n}\n\n/**\n * A stage the project does not deploy to. Refused before anything is\n * provisioned, so a typo does not become a second environment.\n */\nexport class UndeclaredStage extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly deployed: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`\"${stage}\" is not a deployed stage. gkm.config.ts deploys to: ${deployed.join(', ') || 'nothing yet'}.`,\n\t\t);\n\t\tthis.name = 'UndeclaredStage';\n\t}\n}\n\n/**\n * A per-stage setting keyed by a stage the workspace does not deploy: a typo,\n * a stage since removed, or the local stage, which none of them apply to.\n */\nexport class UnknownStageKey extends GkmError {\n\tconstructor(\n\t\t/** Where it is: `domains`, `deploy.objects`, `dns['example.com'].records.target`. */\n\t\treadonly setting: string,\n\t\treadonly stage: string,\n\t\treadonly deployed: readonly string[],\n\t\treadonly local?: string,\n\t) {\n\t\tsuper(\n\t\t\t`${setting} names the stage '${stage}', ` +\n\t\t\t\t(stage === local\n\t\t\t\t\t? `the local stage — ${setting} is read for deployed stages only. `\n\t\t\t\t\t: \"which is not one of this workspace's deployed stages. \") +\n\t\t\t\t`It takes ${deployed.length > 0 ? deployed.map((s) => `'${s}'`).join(', ') : 'no stage: stages.deployed is empty'}` +\n\t\t\t\t' — the stages in stages.deployed.',\n\t\t);\n\t\tthis.name = 'UnknownStageKey';\n\t}\n}\n\n/**\n * The first key of a per-stage map that is not a deployed stage.\n *\n * @throws {UnknownStageKey}\n */\nexport function assertDeployedStageKeys(\n\tsetting: string,\n\tmap: Readonly<Record<string, unknown>> | undefined,\n\tstages: { local?: string; deployed?: readonly string[] } | undefined,\n): void {\n\tif (!map || !stages?.deployed) return;\n\tfor (const key of Object.keys(map)) {\n\t\tif (!stages.deployed.includes(key)) {\n\t\t\tthrow new UnknownStageKey(setting, key, stages.deployed, stages.local);\n\t\t}\n\t}\n}\n","import { z } from 'zod/v4';\nimport { checkDnsRecordsMode } from '../compose/dnsConfig.js';\nimport { checkComposeStages } from '../compose/proxy.js';\nimport { checkStageProvider } from '../providers/config.js';\nimport {\n\tBUILTIN_TARGETS,\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n} from '../target/builtins.js';\nimport { isDeployTarget } from '../target/define.js';\nimport { checkStageTelemetry } from '../telemetry/config.js';\nimport { assertDeployedStageKeys, stageProblems } from './stages.js';\n\n/** Routes are a glob, or a list of them. */\nconst RoutesSchema = z.union([z.string(), z.array(z.string())]);\n\n/**\n * Telescope configuration schema.\n */\nconst TelescopeConfigSchema = z.object({\n\tenabled: z.boolean().optional(),\n\tport: z.number().optional(),\n\tpath: z.string().optional(),\n\tignore: z.array(z.string()).optional(),\n\trecordBody: z.boolean().optional(),\n\tmaxEntries: z.number().optional(),\n\twebsocket: z.boolean().optional(),\n});\n\n/**\n * OpenAPI configuration schema.\n */\nconst OpenApiConfigSchema = z.object({\n\tenabled: z.boolean().optional(),\n\ttitle: z.string().optional(),\n\tversion: z.string().optional(),\n\tdescription: z.string().optional(),\n});\n\n/**\n * Hooks configuration schema.\n */\nconst HooksConfigSchema = z.object({\n\tserver: z.string().optional(),\n});\n\n/**\n * Backend framework schema for non-gkm apps.\n */\nexport const BackendFrameworkSchema = z.enum([\n\t'hono',\n\t'better-auth',\n\t'express',\n\t'fastify',\n]);\n\n/**\n * Backend framework types for apps that don't use gkm routes.\n * Derived from {@link BackendFrameworkSchema}.\n *\n * Used with `entry` to specify the framework for proper Docker builds.\n *\n * @example\n * ```ts\n * // Better Auth server\n * {\n * entry: './src/index.ts',\n * framework: 'better-auth',\n * port: 3001,\n * }\n *\n * // Hono app without gkm routes\n * {\n * entry: './src/server.ts',\n * framework: 'hono',\n * port: 3000,\n * }\n * ```\n */\nexport type BackendFramework = z.infer<typeof BackendFrameworkSchema>;\n\n/**\n * Frontend framework schema.\n */\nexport const FrontendFrameworkSchema = z.enum([\n\t'nextjs',\n\t'remix',\n\t'vite',\n\t'tanstack-start',\n]);\n\n/**\n * Frontend framework types. Derived from {@link FrontendFrameworkSchema}.\n *\n * @example\n * ```ts\n * // Next.js app\n * {\n * type: 'web',\n * framework: 'nextjs',\n * port: 3000,\n * }\n *\n * // Vite SPA\n * {\n * type: 'web',\n * framework: 'vite',\n * port: 5173,\n * }\n *\n * // TanStack Start (Vite-based, full-stack)\n * {\n * type: 'web',\n * framework: 'tanstack-start',\n * port: 3000,\n * }\n * ```\n */\nexport type FrontendFramework = z.infer<typeof FrontendFrameworkSchema>;\n\n/**\n * Mobile framework schema.\n */\nexport const MobileFrameworkSchema = z.enum(['expo']);\n\n/**\n * Mobile framework types. Derived from {@link MobileFrameworkSchema}.\n *\n * Mobile apps deploy via their own toolchain (e.g. EAS Build for Expo)\n * rather than Docker/Dokploy. Only build-time public env vars\n * (e.g. `EXPO_PUBLIC_*`) reach the device — server secrets are dropped.\n *\n * @example\n * ```ts\n * {\n * type: 'mobile',\n * framework: 'expo',\n * path: 'apps/mobile',\n * port: 8081,\n * dependencies: ['api'],\n * }\n * ```\n */\nexport type MobileFramework = z.infer<typeof MobileFrameworkSchema>;\n\n/**\n * Combined framework schema (backend, frontend, or mobile).\n */\nexport const FrameworkSchema = z.union([\n\tBackendFrameworkSchema,\n\tFrontendFrameworkSchema,\n\tMobileFrameworkSchema,\n]);\n\n/**\n * Any framework value across backend, frontend, or mobile.\n * Derived from {@link FrameworkSchema}.\n */\nexport type Framework = z.infer<typeof FrameworkSchema>;\n\n/** Frontend framework values, kept in sync with FrontendFrameworkSchema. */\nconst FRONTEND_FRAMEWORKS = [\n\t'nextjs',\n\t'remix',\n\t'vite',\n\t'tanstack-start',\n] as const;\n\n/** Mobile framework values, kept in sync with MobileFrameworkSchema. */\nconst MOBILE_FRAMEWORKS = ['expo'] as const;\n\n/**\n * A deploy target's name. Which names exist is the workspace's to say — the\n * built-ins and its own `deploy.targets` — so it is checked against both\n * once the whole config is read.\n */\nconst DeployTargetSchema = z.string().min(1);\n\n/**\n * The built-in targets a config may name, both deployed by `gkm deploy`:\n * `dokploy`, and `sst`, which runs `sst deploy` on the manifest `gkm build`\n * writes.\n */\nconst SUPPORTED_DEPLOY_TARGETS = configurableBuiltins();\n\n/** Built-in names reserved for targets that do not exist yet. */\nconst PHASE_2_DEPLOY_TARGETS = Object.entries(BUILTIN_TARGETS)\n\t.filter(([, target]) => target.status === 'planned')\n\t.map(([name]) => name);\n\n/**\n * Whether a config may name `target`: a usable built-in, or one of its own\n * `deploy.targets`.\n */\nexport function isDeployTargetSupported(\n\ttarget: string,\n\ttargets: Record<string, unknown> = {},\n): boolean {\n\treturn (\n\t\tSUPPORTED_DEPLOY_TARGETS.includes(target) || Object.hasOwn(targets, target)\n\t);\n}\n\n/**\n * Check if a deploy target is planned for Phase 2.\n */\nexport function isPhase2DeployTarget(target: string): boolean {\n\treturn PHASE_2_DEPLOY_TARGETS.includes(target);\n}\n\n/**\n * Get error message for unsupported deploy targets.\n */\nexport function getDeployTargetError(target: string, appName?: string): string {\n\tif (isPhase2DeployTarget(target)) {\n\t\tconst context = appName ? ` for app \"${appName}\"` : '';\n\t\treturn `Deploy target \"${target}\"${context} is coming in Phase 2. Currently \"dokploy\" and \"sst\" are supported.`;\n\t}\n\treturn `Unknown deploy target: ${target}. Built in: ${SUPPORTED_DEPLOY_TARGETS.join(', ')}; any other is named in deploy.targets with the package that provides it. Coming in Phase 2: ${PHASE_2_DEPLOY_TARGETS.join(', ')}.`;\n}\n\n/**\n * One `deploy.targets` entry: a package name, a target object, or either\n * with options.\n */\nconst DeployTargetEntrySchema = z.union([\n\tz.string().min(1, 'A target package name cannot be empty'),\n\tz.custom((value) => isDeployTarget(value), {\n\t\tmessage:\n\t\t\t'Expected a package name, a target (defineTarget), or [package or target, options]',\n\t}),\n\tz.tuple([\n\t\tz.union([\n\t\t\tz.string().min(1),\n\t\t\tz.custom((value) => isDeployTarget(value), {\n\t\t\t\tmessage: 'Expected a package name or a target (defineTarget)',\n\t\t\t}),\n\t\t]),\n\t\tz.unknown(),\n\t]),\n]);\n\n/**\n * Dokploy workspace configuration schema.\n * Supports either a single endpoint or per-stage endpoints.\n */\nconst DokployWorkspaceConfigSchema = z\n\t.object({\n\t\t/** Single endpoint for all stages */\n\t\tendpoint: z.url('Dokploy endpoint must be a valid URL').optional(),\n\t\t/** Per-stage endpoints (stage name -> endpoint URL) */\n\t\tendpoints: z\n\t\t\t.record(z.string(), z.url('Endpoint must be a valid URL'))\n\t\t\t.optional(),\n\t\tregistryId: z.string().optional(),\n\t\tverify: z\n\t\t\t.object({\n\t\t\t\tdeploymentTimeoutMs: z.number().int().positive().optional(),\n\t\t\t\thealthCheckPath: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.startsWith('/', 'healthCheckPath must start with /')\n\t\t\t\t\t.optional(),\n\t\t\t\thealthyAfter: z.number().int().positive().optional(),\n\t\t\t\tintervalMs: z.number().int().positive().optional(),\n\t\t\t\thealthTimeoutMs: z.number().int().positive().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.refine((data) => data.endpoint || data.endpoints, {\n\t\tmessage: 'Either endpoint or endpoints must be provided',\n\t});\n\n// =============================================================================\n// AWS Regions (needed by DNS and State providers)\n// =============================================================================\n\n/**\n * Valid AWS regions.\n */\nconst AwsRegionSchema = z.enum([\n\t'us-east-1',\n\t'us-east-2',\n\t'us-west-1',\n\t'us-west-2',\n\t'af-south-1',\n\t'ap-east-1',\n\t'ap-south-1',\n\t'ap-south-2',\n\t'ap-southeast-1',\n\t'ap-southeast-2',\n\t'ap-southeast-3',\n\t'ap-southeast-4',\n\t'ap-northeast-1',\n\t'ap-northeast-2',\n\t'ap-northeast-3',\n\t'ca-central-1',\n\t'eu-central-1',\n\t'eu-central-2',\n\t'eu-west-1',\n\t'eu-west-2',\n\t'eu-west-3',\n\t'eu-south-1',\n\t'eu-south-2',\n\t'eu-north-1',\n\t'me-south-1',\n\t'me-central-1',\n\t'sa-east-1',\n]);\n\n// =============================================================================\n// DNS Record Types (used by DnsProvider interface)\n// =============================================================================\n\n/**\n * DNS record types supported across providers.\n */\nexport const DnsRecordTypeSchema = z.enum([\n\t'A',\n\t'AAAA',\n\t'CNAME',\n\t'MX',\n\t'TXT',\n\t'NS',\n\t'SRV',\n\t'CAA',\n]);\n\n/**\n * A DNS record as returned by the provider.\n */\nexport const DnsRecordSchema = z.object({\n\t/** Subdomain name (e.g., 'api' for api.example.com, '@' for root) */\n\tname: z.string(),\n\t/** Record type */\n\ttype: DnsRecordTypeSchema,\n\t/** TTL in seconds */\n\tttl: z.number().int().positive(),\n\t/** Record values */\n\tvalues: z.array(z.string()),\n});\n\n/**\n * A DNS record to create or update.\n */\nexport const UpsertDnsRecordSchema = z.object({\n\t/** Subdomain name (e.g., 'api' for api.example.com, '@' for root) */\n\tname: z.string(),\n\t/** Record type */\n\ttype: DnsRecordTypeSchema,\n\t/** TTL in seconds */\n\tttl: z.number().int().positive(),\n\t/** Record value (IP address, hostname, etc.) */\n\tvalue: z.string(),\n});\n\n/**\n * Result of an upsert operation.\n */\nexport const UpsertResultSchema = z.object({\n\t/** The record that was upserted */\n\trecord: UpsertDnsRecordSchema,\n\t/** Whether the record was created (true) or updated (false) */\n\tcreated: z.boolean(),\n\t/** Whether the record already existed with the same value */\n\tunchanged: z.boolean(),\n});\n\n// =============================================================================\n// DNS Provider Configuration\n// =============================================================================\n\n/**\n * How a domain's hosts point at a compose stage's server: an A (and AAAA)\n * record each (`'a'`, the default), or one A record for `target` and a CNAME\n * to it for every other host but the apex. `target` is one name, or one per\n * stage; it must be under the domain.\n */\nexport const DnsRecordsModeSchema = z.union([\n\tz.literal('a'),\n\tz\n\t\t.object({\n\t\t\tmode: z.literal('cname'),\n\t\t\ttarget: z.union([z.string(), z.record(z.string(), z.string())]),\n\t\t})\n\t\t.strict(),\n]);\n\n/**\n * Hostinger DNS provider config (without domain - domain is the record key).\n */\nexport const HostingerDnsProviderSchema = z.object({\n\tprovider: z.literal('hostinger'),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n\t/** TTL in seconds (default: 300) */\n\tttl: z.number().int().positive().optional(),\n});\n\n/**\n * Route53 DNS provider config (without domain - domain is the record key).\n */\nexport const Route53DnsProviderSchema = z.object({\n\tprovider: z.literal('route53'),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n\t/** AWS region (optional - uses AWS_REGION env var if not provided) */\n\tregion: AwsRegionSchema.optional(),\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile: z.string().optional(),\n\t/** Hosted zone ID (optional - auto-detected from domain if not provided) */\n\thostedZoneId: z.string().optional(),\n\t/** TTL in seconds (default: 300) */\n\tttl: z.number().int().positive().optional(),\n});\n\n/**\n * GoDaddy DNS provider config (without domain - domain is the record key).\n *\n * Credentials: `GODADDY_API_TOKEN` (a Personal Access Token scoped to\n * `domains.dns:update`), else `gkm login --provider godaddy`. GoDaddy refuses\n * a TTL under 600 seconds.\n */\nexport const GoDaddyDnsProviderSchema = z.object({\n\tprovider: z.literal('godaddy'),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n\t/** TTL in seconds (default and minimum: 600) */\n\tttl: z\n\t\t.number()\n\t\t.int()\n\t\t.min(600, \"GoDaddy's minimum TTL is 600 seconds\")\n\t\t.optional(),\n});\n\n/**\n * Cloudflare DNS provider config (placeholder for future).\n */\nexport const CloudflareDnsProviderSchema = z.object({\n\tprovider: z.literal('cloudflare'),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n\t/** TTL in seconds (default: 300) */\n\tttl: z.number().int().positive().optional(),\n});\n\n/**\n * Manual DNS configuration (user handles DNS themselves).\n */\nexport const ManualDnsProviderSchema = z.object({\n\tprovider: z.literal('manual'),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n});\n\n/**\n * Custom DNS provider config (user-provided implementation).\n */\nexport const CustomDnsProviderSchema = z.object({\n\t/** Custom DnsProvider implementation */\n\tprovider: z.custom<{\n\t\tname: string;\n\t\tgetRecords: Function;\n\t\tupsertRecords: Function;\n\t}>(\n\t\t(val) =>\n\t\t\ttypeof val === 'object' &&\n\t\t\tval !== null &&\n\t\t\ttypeof (val as any).name === 'string' &&\n\t\t\ttypeof (val as any).getRecords === 'function' &&\n\t\t\ttypeof (val as any).upsertRecords === 'function',\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'Custom DNS provider must implement name, getRecords(), and upsertRecords() methods',\n\t\t},\n\t),\n\t/** How the hosts point at a compose stage's server — see {@link DnsRecordsModeSchema}. */\n\trecords: DnsRecordsModeSchema.optional(),\n\t/** TTL in seconds (default: 300) */\n\tttl: z.number().int().positive().optional(),\n});\n\n/**\n * Built-in DNS provider config (discriminated union).\n */\nexport const BuiltInDnsProviderSchema = z.discriminatedUnion('provider', [\n\tHostingerDnsProviderSchema,\n\tRoute53DnsProviderSchema,\n\tGoDaddyDnsProviderSchema,\n\tCloudflareDnsProviderSchema,\n\tManualDnsProviderSchema,\n]);\n\n/**\n * Single DNS provider config (for one domain).\n */\nexport const DnsProviderSchema = z.union([\n\tBuiltInDnsProviderSchema,\n\tCustomDnsProviderSchema,\n]);\n\nexport type DnsProvider = z.infer<typeof DnsProviderSchema>;\n\n/**\n * DNS configuration schema.\n *\n * Maps root domains to their DNS provider configuration.\n * Example:\n * ```\n * dns: {\n * 'geekmidas.dev': { provider: 'hostinger' },\n * 'geekmidas.com': { provider: 'route53' },\n * }\n * ```\n *\n * Supported providers:\n * - 'hostinger': Use Hostinger DNS API\n * - 'route53': Use AWS Route53\n * - 'godaddy': Use GoDaddy's v1 DNS API\n * - 'cloudflare': Use Cloudflare DNS API (future)\n * - 'manual': Don't create records, just print required records\n * - Custom: Provide a DnsProvider implementation\n */\nexport const DnsConfigSchema = z.record(z.string(), DnsProviderSchema);\n\n// Legacy single-domain config schemas (for backwards compatibility)\nexport const HostingerDnsConfigSchema = HostingerDnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const Route53DnsConfigSchema = Route53DnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const GoDaddyDnsConfigSchema = GoDaddyDnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const CloudflareDnsConfigSchema = CloudflareDnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const ManualDnsConfigSchema = ManualDnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const CustomDnsConfigSchema = CustomDnsProviderSchema.extend({\n\tdomain: z.string().min(1, 'Domain is required'),\n});\nexport const BuiltInDnsConfigSchema = z.discriminatedUnion('provider', [\n\tHostingerDnsConfigSchema,\n\tRoute53DnsConfigSchema,\n\tGoDaddyDnsConfigSchema,\n\tCloudflareDnsConfigSchema,\n\tManualDnsConfigSchema,\n]);\nexport const LegacyDnsConfigSchema = z.union([\n\tBuiltInDnsConfigSchema,\n\tCustomDnsConfigSchema,\n]);\n\n/**\n * Combined DNS config that supports both new multi-domain and legacy single-domain formats.\n */\nexport const DnsConfigWithLegacySchema = z.union([\n\tDnsConfigSchema,\n\tLegacyDnsConfigSchema,\n]);\n\nexport type DnsConfig = z.infer<typeof DnsConfigWithLegacySchema>;\n\n/**\n * Backups configuration schema.\n *\n * Configures automatic backup destinations for database services.\n * On first deploy, creates S3 bucket with unique name and IAM credentials.\n */\nexport const BackupsConfigSchema = z.object({\n\t/** Backup storage type (currently only 's3' supported) */\n\ttype: z.literal('s3'),\n\t/** AWS profile name for creating bucket/IAM resources */\n\tprofile: z.string().optional(),\n\t/** AWS region for the backup bucket */\n\tregion: AwsRegionSchema,\n\t/** Cron schedule for backups (default: '0 2 * * *' = 2 AM daily) */\n\tschedule: z.string().optional(),\n\t/** Number of backups to retain (default: 30) */\n\tretention: z.number().optional(),\n});\n\nexport type BackupsConfig = z.infer<typeof BackupsConfigSchema>;\n\n/** `deploy.compose` — what the compose target runs beside the apps. */\nconst ComposeWorkspaceConfigSchema = z\n\t.object({\n\t\tproxy: z\n\t\t\t.union([\n\t\t\t\tz.enum(['caddy', 'traefik']),\n\t\t\t\tz.record(z.string(), z.enum(['caddy', 'traefik'])),\n\t\t\t])\n\t\t\t.optional(),\n\t\ttls: z\n\t\t\t.record(\n\t\t\t\tz.string(),\n\t\t\t\tz\n\t\t\t\t\t.object({ certFile: z.string().min(1), keyFile: z.string().min(1) })\n\t\t\t\t\t.strict(),\n\t\t\t)\n\t\t\t.optional(),\n\t})\n\t// Strict, so a key it no longer takes — `logs`, now a `Telemetry`\n\t// construct and `deploy.telemetry` — fails to load rather than being\n\t// dropped without a word.\n\t.strict();\n\nconst TelemetrySampleRate = z.number().optional();\n\n/**\n * `deploy.telemetry` — where each stage's telemetry goes. The rules past the\n * shape are `checkStageTelemetry`'s, so the schema and a deploy refuse the\n * same configs with the same words.\n */\nconst TelemetryConfigSchema = z\n\t.record(\n\t\tz.string(),\n\t\tz.union([\n\t\t\tz.literal(false),\n\t\t\tz.literal('self-hosted'),\n\t\t\tz\n\t\t\t\t.object({\n\t\t\t\t\tprovider: z.literal('self-hosted'),\n\t\t\t\t\tport: z.number().optional(),\n\t\t\t\t\tretentionDays: z.number().optional(),\n\t\t\t\t\tpublic: z.object({ allow: z.array(z.string()) }).optional(),\n\t\t\t\t\tsampleRate: TelemetrySampleRate,\n\t\t\t\t})\n\t\t\t\t.strict(),\n\t\t\tz\n\t\t\t\t.object({\n\t\t\t\t\tprovider: z.literal('otlp'),\n\t\t\t\t\tendpoint: z.string(),\n\t\t\t\t\theaders: z.record(z.string(), z.string()).optional(),\n\t\t\t\t\tsampleRate: TelemetrySampleRate,\n\t\t\t\t})\n\t\t\t\t.strict(),\n\t\t]),\n\t)\n\t.superRefine((telemetry, ctx) => {\n\t\tfor (const [stage, config] of Object.entries(telemetry)) {\n\t\t\ttry {\n\t\t\t\tcheckStageTelemetry(stage, config);\n\t\t\t} catch (error) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tpath: [stage],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n/**\n * `deploy.objects` — what backs each deployed stage's buckets. The rules are\n * `checkStageProvider`'s, so the schema and a provision run refuse the same\n * entries with the same words.\n */\nconst ObjectsConfigSchema = z\n\t.record(z.string(), z.unknown())\n\t.superRefine((entries, ctx) => {\n\t\tfor (const [stage, value] of Object.entries(entries)) {\n\t\t\ttry {\n\t\t\t\tcheckStageProvider('objects', stage, value);\n\t\t\t} catch (error) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tpath: [stage],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n/**\n * Deploy configuration schema.\n */\nconst DeployConfigSchema = z.object({\n\tdefault: DeployTargetSchema.optional(),\n\ttargets: z\n\t\t.record(z.string(), DeployTargetEntrySchema)\n\t\t.superRefine((targets, ctx) => {\n\t\t\tfor (const name of Object.keys(targets)) {\n\t\t\t\t// The built-ins resolve first, so an entry under one of their\n\t\t\t\t// names would never be used — say so rather than ignore it.\n\t\t\t\tif (builtinTarget(name)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `\"${name}\" is a built-in target; give this one a name of its own`,\n\t\t\t\t\t\tpath: [name],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\t.optional(),\n\t/** Whose deploy this is, on a target shared with other workspaces. */\n\tnamespace: z\n\t\t.string()\n\t\t.regex(\n\t\t\t/^[a-z0-9]+(?:-[a-z0-9]+)*$/,\n\t\t\t\"deploy.namespace must be lowercase letters and digits with single '-' between them\",\n\t\t)\n\t\t.optional(),\n\t/** Where every target pushes and pulls the apps' images. */\n\tregistry: z.string().min(1).optional(),\n\tdokploy: DokployWorkspaceConfigSchema.optional(),\n\tcompose: ComposeWorkspaceConfigSchema.optional(),\n\ttelemetry: TelemetryConfigSchema.optional(),\n\tobjects: ObjectsConfigSchema.optional(),\n\tbackups: BackupsConfigSchema.optional(),\n});\n\n/**\n * Models configuration schema.\n */\nconst ModelsConfigSchema = z.object({\n\tpath: z.string().optional(),\n\tschema: z.enum(['zod']).optional(),\n});\n\n/**\n * Shared configuration schema.\n */\nconst SharedConfigSchema = z.object({\n\tpackages: z.array(z.string()).optional(),\n\tmodels: ModelsConfigSchema.optional(),\n});\n\n/**\n * Secrets configuration schema.\n */\nconst StagesConfigSchema = z\n\t.object({\n\t\tlocal: z.string(),\n\t\tdeployed: z.array(z.string()),\n\t\tprotected: z.array(z.string()).optional(),\n\t})\n\t.superRefine((stages, ctx) => {\n\t\tfor (const message of stageProblems(stages)) {\n\t\t\tctx.addIssue({ code: 'custom', message });\n\t\t}\n\t});\n\nconst SecretsStoreSchema = z.union([\n\tz.literal('file'),\n\tz.object({ provider: z.literal('ssm'), region: AwsRegionSchema }).strict(),\n\tz\n\t\t.object({\n\t\t\tprovider: z.literal('secrets-manager'),\n\t\t\tregion: AwsRegionSchema,\n\t\t\tkmsKeyId: z.string().min(1).optional(),\n\t\t})\n\t\t.strict(),\n\tz.object({\n\t\t/** Any backend: an object implementing SecretsStore */\n\t\tprovider: z.custom<{ name: string; read: Function; write: Function }>(\n\t\t\t(val) =>\n\t\t\t\ttypeof val === 'object' &&\n\t\t\t\tval !== null &&\n\t\t\t\ttypeof (val as any).name === 'string' &&\n\t\t\t\ttypeof (val as any).read === 'function' &&\n\t\t\t\ttypeof (val as any).write === 'function',\n\t\t\t{ message: 'a secrets store has a name, read() and write()' },\n\t\t),\n\t}),\n]);\n\nconst SecretsConfigSchema = z.object({\n\tenabled: z.boolean().optional(),\n\tstore: SecretsStoreSchema.optional(),\n\talgorithm: z.string().optional(),\n\tkdf: z.enum(['scrypt', 'pbkdf2']).optional(),\n});\n\n// =============================================================================\n// State Provider Configuration\n// =============================================================================\n\n/**\n * Local state provider config.\n */\nconst LocalStateConfigSchema = z.object({\n\tprovider: z.literal('local'),\n});\n\n/**\n * SSM state provider config (requires region).\n */\nconst SSMStateConfigSchema = z.object({\n\tprovider: z.literal('ssm'),\n\t/** AWS region (required for SSM provider) */\n\tregion: AwsRegionSchema,\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile: z.string().optional(),\n});\n\n/**\n * S3 state provider config: conditional writes and a lock object in a bucket.\n */\nconst S3StateConfigSchema = z.object({\n\tprovider: z.literal('s3'),\n\t/** Bucket the state lives in (must already exist) */\n\tbucket: z.string().min(1),\n\t/** AWS region of the bucket */\n\tregion: AwsRegionSchema,\n\t/** Key prefix inside the bucket (default: 'gkm') */\n\tprefix: z.string().optional(),\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile: z.string().optional(),\n});\n\n/**\n * Custom state provider config (user-provided implementation).\n */\nconst CustomStateConfigSchema = z.object({\n\t/** Custom StateProvider implementation */\n\tprovider: z.custom<{ read: Function; write: Function }>(\n\t\t(val) =>\n\t\t\ttypeof val === 'object' &&\n\t\t\tval !== null &&\n\t\t\ttypeof (val as any).read === 'function' &&\n\t\t\ttypeof (val as any).write === 'function',\n\t\t{ message: 'Custom provider must implement read() and write() methods' },\n\t),\n});\n\n/**\n * Built-in state provider config (discriminated union).\n */\nconst BuiltInStateConfigSchema = z.discriminatedUnion('provider', [\n\tLocalStateConfigSchema,\n\tSSMStateConfigSchema,\n\tS3StateConfigSchema,\n]);\n\n/**\n * State configuration schema.\n *\n * Configures how deployment state is stored.\n * - 'local': Store in .gkm/deploy-{stage}.json (default)\n * - 'ssm': Store in AWS SSM Parameter Store (requires region)\n * - 's3': Store in an S3 bucket with conditional writes (requires bucket, region)\n * - Custom: Provide a StateStore, or a StateProvider with read/write methods\n */\nconst StateConfigSchema = z.union([\n\tBuiltInStateConfigSchema,\n\tCustomStateConfigSchema,\n]);\n\n/**\n * App configuration schema.\n */\nconst AppConfigSchema = z\n\t.object({\n\t\t// Core properties\n\t\ttype: z.enum(['backend', 'web', 'mobile']).optional().default('backend'),\n\t\tpath: z.string().min(1, 'App path is required'),\n\t\tport: z.number().int().positive('Port must be a positive integer'),\n\t\tdependencies: z.array(z.string()).optional(),\n\t\tdeploy: DeployTargetSchema.optional(),\n\n\t\t// Backend-specific (from GkmConfig)\n\t\tconstructs: RoutesSchema.optional(),\n\t\troutes: RoutesSchema.optional(),\n\t\tfunctions: RoutesSchema.optional(),\n\t\tcrons: RoutesSchema.optional(),\n\t\tqueues: RoutesSchema.optional(),\n\t\ttopics: RoutesSchema.optional(),\n\t\tsubscribers: RoutesSchema.optional(),\n\t\tenvParser: z.string().optional(),\n\t\tlogger: z.string().optional(),\n\t\thooks: HooksConfigSchema.optional(),\n\t\ttelescope: z\n\t\t\t.union([z.string(), z.boolean(), TelescopeConfigSchema])\n\t\t\t.optional(),\n\t\topenapi: z.union([z.boolean(), OpenApiConfigSchema]).optional(),\n\t\truntime: z.enum(['node', 'bun']).optional(),\n\t\tenv: z.union([z.string(), z.array(z.string())]).optional(),\n\n\t\t// Entry point for non-gkm apps (used by dev and docker build)\n\t\tentry: z.string().optional(),\n\n\t\t// Framework (backend, web, or mobile)\n\t\tframework: FrameworkSchema.optional(),\n\t\t// Web/mobile: config file paths for env sniffing (calls .parse() at import)\n\t\tconfig: z\n\t\t\t.object({\n\t\t\t\tclient: z.string().optional(),\n\t\t\t\tserver: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t// Note: routes is optional for backend apps - some backends like auth servers don't use routes\n\t.refine(\n\t\t(data) => {\n\t\t\t// Web apps must have a web framework\n\t\t\tif (data.type === 'web') {\n\t\t\t\tif (\n\t\t\t\t\t!data.framework ||\n\t\t\t\t\t!(FRONTEND_FRAMEWORKS as readonly string[]).includes(data.framework)\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage: `Web apps must have a valid web framework (${FRONTEND_FRAMEWORKS.join(', ')})`,\n\t\t\tpath: ['framework'],\n\t\t},\n\t)\n\t.refine(\n\t\t(data) => {\n\t\t\t// Mobile apps must have a mobile framework\n\t\t\tif (data.type === 'mobile') {\n\t\t\t\tif (\n\t\t\t\t\t!data.framework ||\n\t\t\t\t\t!(MOBILE_FRAMEWORKS as readonly string[]).includes(data.framework)\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage: `Mobile apps must have a valid mobile framework (${MOBILE_FRAMEWORKS.join(', ')})`,\n\t\t\tpath: ['framework'],\n\t\t},\n\t);\n\n/** What `gkm test` hands a feature test. */\nconst TestConfigSchema = z\n\t.object({\n\t\t/** The folder of per-database factories; `test/factories` by default. */\n\t\tfactories: z.string().optional(),\n\t})\n\t.strict();\n\n/** How `gkm dev` is reached from outside the apps it runs. */\nconst DevConfigSchema = z\n\t.object({\n\t\t/** Browser origins that may read the discovery endpoint. */\n\t\tallowedOrigins: z\n\t\t\t.array(\n\t\t\t\tz.url().refine(\n\t\t\t\t\t// Checked even when `z.url()` has already failed it.\n\t\t\t\t\t(value) => URL.canParse(value) && new URL(value).origin === value,\n\t\t\t\t\t{\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t'An origin is a scheme, host and port only, e.g. https://console.example.com — no path or trailing slash',\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\t.optional(),\n\t\t/** The discovery endpoint's loopback port; 4983 by default. */\n\t\tdiscoveryPort: z.number().int().min(0).max(65535).optional(),\n\t})\n\t.strict();\n\n/**\n * Workspace configuration schema.\n */\nexport const WorkspaceConfigSchema = z\n\t.object({\n\t\tname: z.string().optional(),\n\t\t/**\n\t\t * Where the workspace's own constructs live, relative to its root.\n\t\t *\n\t\t * Infrastructure is a fact about the product, not about the process that\n\t\t * happens to import it — so a database two apps share is declared once,\n\t\t * at the top, and both find it. An app-level glob still works and is\n\t\t * additive, for something only one app uses.\n\t\t */\n\t\tconstructs: RoutesSchema.optional(),\n\t\t/**\n\t\t * Apps that nothing declares.\n\t\t *\n\t\t * Optional, and normally absent: a `site` is an app and so is a\n\t\t * `rest-api` that named one, so the list is read off the graph. This is\n\t\t * the escape hatch for what no construct describes — a mobile app, a\n\t\t * process someone runs by hand — and for overriding one field of a\n\t\t * derived app without restating it.\n\t\t */\n\t\tapps: z.record(z.string(), AppConfigSchema).optional(),\n\t\tshared: SharedConfigSchema.optional(),\n\t\t/** Each deployed stage's base domain (stage name -> domain). */\n\t\tdomains: z.record(z.string(), z.string()).optional(),\n\t\t/** Each root domain's DNS provider, and how its hosts are pointed. */\n\t\tdns: DnsConfigSchema.optional(),\n\t\tdeploy: DeployConfigSchema.optional(),\n\t\tstages: StagesConfigSchema,\n\t\tsecrets: SecretsConfigSchema.optional(),\n\t\tstate: StateConfigSchema.optional(),\n\t\ttest: TestConfigSchema.optional(),\n\t\tdev: DevConfigSchema.optional(),\n\t})\n\t// Strict, so a key this schema no longer has fails instead of being\n\t// dropped: a leftover `services:` block is a question the config used to\n\t// answer, and silently ignoring it would hide that the answer moved.\n\t.strict()\n\t.refine(\n\t\t(data) => {\n\t\t\t// Validate dependencies reference existing apps\n\t\t\tconst appNames = Object.keys(data.apps ?? {});\n\t\t\tfor (const [appName, app] of Object.entries(data.apps ?? {})) {\n\t\t\t\tfor (const dep of app.dependencies ?? []) {\n\t\t\t\t\tif (!appNames.includes(dep)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Prevent self-dependency\n\t\t\t\t\tif (dep === appName) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage:\n\t\t\t\t'App dependencies must reference existing apps and cannot be self-referential',\n\t\t},\n\t)\n\t.refine(\n\t\t(data) => {\n\t\t\t// Check for circular dependencies\n\t\t\tconst appNames = Object.keys(data.apps ?? {});\n\t\t\tconst visited = new Set<string>();\n\t\t\tconst recStack = new Set<string>();\n\n\t\t\tfunction hasCycle(app: string): boolean {\n\t\t\t\tif (recStack.has(app)) return true;\n\t\t\t\tif (visited.has(app)) return false;\n\n\t\t\t\tvisited.add(app);\n\t\t\t\trecStack.add(app);\n\n\t\t\t\tconst deps = data.apps?.[app]?.dependencies ?? [];\n\t\t\t\tfor (const dep of deps) {\n\t\t\t\t\tif (hasCycle(dep)) return true;\n\t\t\t\t}\n\n\t\t\t\trecStack.delete(app);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor (const app of appNames) {\n\t\t\t\tvisited.clear();\n\t\t\t\trecStack.clear();\n\t\t\t\tif (hasCycle(app)) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t{\n\t\t\tmessage: 'Circular dependencies detected between apps',\n\t\t},\n\t)\n\t.superRefine((data, ctx) => {\n\t\t// Validate deploy targets are supported\n\t\tconst defaultTarget = data.deploy?.default;\n\t\tconst ownTargets = data.deploy?.targets ?? {};\n\t\tif (defaultTarget && !isDeployTargetSupported(defaultTarget, ownTargets)) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: 'custom',\n\t\t\t\tmessage: getDeployTargetError(defaultTarget),\n\t\t\t\tpath: ['deploy', 'default'],\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const [appName, app] of Object.entries(data.apps ?? {})) {\n\t\t\tif (app.deploy && !isDeployTargetSupported(app.deploy, ownTargets)) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: getDeployTargetError(app.deploy, appName),\n\t\t\t\t\tpath: ['apps', appName, 'deploy'],\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// The compose target's per-stage settings name stages this workspace has.\n\t\ttry {\n\t\t\tcheckComposeStages(data.deploy?.compose, data.stages);\n\t\t} catch (error) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: 'custom',\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\tpath: ['deploy', 'compose'],\n\t\t\t});\n\t\t}\n\n\t\t// Every other per-stage map names deployed stages only.\n\t\tconst perStage: [string, (string | number)[], unknown][] = [\n\t\t\t['domains', ['domains'], data.domains],\n\t\t\t['deploy.objects', ['deploy', 'objects'], data.deploy?.objects],\n\t\t\t['deploy.telemetry', ['deploy', 'telemetry'], data.deploy?.telemetry],\n\t\t\t...Object.entries(data.dns ?? {}).map(\n\t\t\t\t([domain, entry]): [string, (string | number)[], unknown] => {\n\t\t\t\t\tconst records = (entry as { records?: unknown }).records;\n\t\t\t\t\tconst target =\n\t\t\t\t\t\trecords && typeof records === 'object'\n\t\t\t\t\t\t\t? (records as { target?: unknown }).target\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\treturn [\n\t\t\t\t\t\t`dns['${domain}'].records.target`,\n\t\t\t\t\t\t['dns', domain, 'records', 'target'],\n\t\t\t\t\t\ttarget && typeof target === 'object' ? target : undefined,\n\t\t\t\t\t];\n\t\t\t\t},\n\t\t\t),\n\t\t];\n\t\tfor (const [setting, path, map] of perStage) {\n\t\t\ttry {\n\t\t\t\tassertDeployedStageKeys(\n\t\t\t\t\tsetting,\n\t\t\t\t\tmap as Record<string, unknown> | undefined,\n\t\t\t\t\tdata.stages,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tpath,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// A CNAME target is a hostname under its own domain.\n\t\tfor (const [domain, entry] of Object.entries(data.dns ?? {})) {\n\t\t\ttry {\n\t\t\t\tcheckDnsRecordsMode(domain, (entry as { records?: unknown }).records);\n\t\t\t} catch (error) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\tpath: ['dns', domain, 'records'],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Validate workspace name is required for SSM state provider\n\t\tif (data.state?.provider === 'ssm' && !data.name) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: 'custom',\n\t\t\t\tmessage:\n\t\t\t\t\t'Workspace name is required when using SSM state provider. Add \"name\" to your gkm.config.ts.',\n\t\t\t\tpath: ['name'],\n\t\t\t});\n\t\t}\n\t});\n\n/**\n * Validate workspace configuration.\n * Throws ZodError with detailed messages on validation failure.\n */\nexport function validateWorkspaceConfig(\n\tconfig: unknown,\n): z.infer<typeof WorkspaceConfigSchema> {\n\treturn WorkspaceConfigSchema.parse(config);\n}\n\n/**\n * Safe validation that returns result instead of throwing.\n */\nexport function safeValidateWorkspaceConfig(config: unknown): {\n\tsuccess: boolean;\n\tdata?: z.infer<typeof WorkspaceConfigSchema>;\n\terror?: z.ZodError;\n} {\n\tconst result = WorkspaceConfigSchema.safeParse(config);\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\treturn { success: false, error: result.error };\n}\n\n/**\n * Format Zod errors into user-friendly messages.\n */\nexport function formatValidationErrors(error: z.ZodError): string {\n\tconst messages = error.issues.map((issue: z.core.$ZodIssue) => {\n\t\tconst path = issue.path.join('.');\n\t\treturn path ? ` - ${path}: ${issue.message}` : ` - ${issue.message}`;\n\t});\n\n\treturn `Workspace configuration validation failed:\\n${messages.join('\\n')}`;\n}\n\nexport type ValidatedWorkspaceConfig = z.infer<typeof WorkspaceConfigSchema>;\n\nexport { SUPPORTED_DEPLOY_TARGETS, PHASE_2_DEPLOY_TARGETS };\n","import type { ConstructManifest } from '@geekmidas/manifest';\nimport type { DnsRecordsMode } from '../compose/dnsConfig.js';\nimport type { AwsRegion, StateConfig } from '../deploy/StateProvider.js';\nimport type { DeployTargetEntry } from '../target/types';\n\nexport type { AwsRegion };\n\nimport type {\n\tGkmConfig,\n\tHooksConfig,\n\tOpenApiConfig,\n\tRoutes,\n\tRuntime,\n\tTelescopeConfig,\n} from '../types.js';\nimport type {\n\tBackendFramework,\n\tBackupsConfig,\n\tDnsConfig,\n\tDnsProvider,\n\tFramework,\n\tFrontendFramework,\n\tMobileFramework,\n} from './schema.js';\n\nexport type {\n\tBackendFramework,\n\tBackupsConfig,\n\tDnsConfig,\n\tDnsProvider,\n\tFramework,\n\tFrontendFramework,\n\tMobileFramework,\n};\n\n/**\n * Where a stage — or one app — deploys, by target name: a built-in\n * (`dokploy`, `sst`) or a key of `deploy.targets`.\n *\n * @example\n * ```ts\n * deploy: 'dokploy'\n * deploy: 'acme' // deploy: { targets: { acme: '@acme/gkm-target' } }\n * ```\n */\nexport type DeployTargetName = 'dokploy' | 'compose' | 'sst' | (string & {});\n\n/**\n * A per-stage map, typed from the workspace's deployed stages: a key that is\n * not one is a type error. Untyped (`string`) stages accept any key, which the\n * schema then checks at load.\n */\nexport type StageMap<S extends string, V> = string extends S\n\t? Record<string, V>\n\t: Partial<Record<S, V>>;\n\n/**\n * `domains: { <stage>: '<domain>' }` at the root of `defineWorkspace`, typed from\n * the deployed stages.\n */\nexport type DomainsInput<S extends string = string> = StageMap<S, string>;\n\n/** How one root domain's hosts point at a compose stage's server. */\nexport type DnsRecordsModeInput<S extends string = string> =\n\t| 'a'\n\t| { mode: 'cname'; target: string | StageMap<S, string> };\n\n/** One root domain's DNS provider, its records mode typed from the stages. */\nexport type DnsDomainInput<S extends string = string> =\n\tDnsProvider extends infer P\n\t\t? P extends unknown\n\t\t\t? Omit<P, 'records'> & { records?: DnsRecordsModeInput<S> }\n\t\t\t: never\n\t\t: never;\n\n/** `dns: { '<root domain>': { provider, … } }` at the root of `defineWorkspace`. */\nexport type DnsInput<S extends string = string> = Record<\n\tstring,\n\tDnsDomainInput<S>\n>;\n\n/** Each root domain's DNS provider — `dns` at the root of the config. */\nexport type WorkspaceDnsConfig = Record<string, DnsProvider>;\n\nexport type { DnsRecordsMode };\n\n/**\n * Each deployed stage's base domain — `domains` at the root of the config.\n *\n * A fact about the deployment rather than the platform, so every target reads\n * it. The root site answers on the base domain; every other surface on\n * `{subdomain}.{domain}`, where the subdomain is the construct's own\n * `subdomain`, or its id kebab-cased.\n *\n * @example\n * ```ts\n * domains: { production: 'myapp.com', staging: 'staging.myapp.com' },\n *\n * // production:\n * // - new StaticSite('Web', { root: true }) → myapp.com\n * // - new RestApi('Api', { subdomain: 'api' }) → api.myapp.com\n * // - new RestApi('Webhooks', { … }) → webhooks.myapp.com\n * ```\n */\nexport type DomainsConfig = Record<string, string>;\n\n/**\n * Per-app domain override configuration.\n *\n * Can be a single domain string (used for all stages) or\n * stage-specific domains.\n *\n * @example\n * ```ts\n * // Single domain for all stages\n * domain: 'api.custom.com'\n *\n * // Stage-specific domains\n * domain: {\n * development: 'api.dev.custom.com',\n * staging: 'api.staging.custom.com',\n * production: 'api.custom.com',\n * }\n * ```\n */\nexport type AppDomainConfig = string | Record<string, string>;\n\n/**\n * Dokploy workspace deployment configuration.\n *\n * Configures how the workspace is deployed to a Dokploy server.\n * One workspace maps to one Dokploy project with stage-based environments.\n * Project IDs are stored in deploy state (not config) and created on first deploy.\n *\n * @example Single endpoint for all stages:\n * ```ts\n * deploy: {\n * default: 'dokploy',\n * registry: 'ghcr.io/myorg',\n * dokploy: {\n * endpoint: 'https://dokploy.myserver.com',\n * },\n * }\n * ```\n *\n * @example Per-stage endpoints (different Dokploy servers):\n * ```ts\n * deploy: {\n * default: 'dokploy',\n * registry: 'ghcr.io/myorg',\n * dokploy: {\n * endpoints: {\n * development: 'https://dev-dokploy.myserver.com',\n * production: 'https://dokploy.myserver.com',\n * },\n * },\n * }\n * ```\n */\nexport interface DokployWorkspaceConfig {\n\t/** Dokploy API endpoint for all stages */\n\tendpoint?: string;\n\t/** Per-stage Dokploy API endpoints (overrides endpoint) */\n\tendpoints?: Record<string, string>;\n\t/** Registry ID in Dokploy (auto-configured) */\n\tregistryId?: string;\n\t/** How a release is waited for and checked before it counts as live. */\n\tverify?: DokployVerifyConfig;\n}\n\n/**\n * How a Dokploy release is waited for and checked.\n *\n * A release counts once Dokploy's deployment has finished and the app has\n * answered its health route `healthyAfter` times in a row. One that does not\n * is rolled back.\n */\nexport interface DokployVerifyConfig {\n\t/** How long Dokploy may take to finish a deployment. Default 10 minutes. */\n\tdeploymentTimeoutMs?: number;\n\t/**\n\t * The path each backend is checked on, under its domain. Default\n\t * `/health`, which every production server build serves. A site is\n\t * checked at `/`.\n\t */\n\thealthCheckPath?: string;\n\t/** Consecutive 2xx answers that make an app healthy. Default 3. */\n\thealthyAfter?: number;\n\t/** Between health checks, and the first wait between polls. Default 2s. */\n\tintervalMs?: number;\n\t/** How long an app may take to become healthy. Default 5 minutes. */\n\thealthTimeoutMs?: number;\n}\n\n/**\n * The `compose` target's own settings — `deploy.compose`. Read by `gkm\n * compose` and `gkm deploy --target compose` only; the Dokploy target never\n * consults it.\n *\n * @example\n * ```ts\n * deploy: { compose: { proxy: 'traefik' } }\n * ```\n */\nexport interface ComposeWorkspaceConfig<S extends string = string> {\n\t/**\n\t * What serves a deployed stage's stack: `'caddy'` (the default) — the\n\t * stack's own Caddy on 80/443 — or `'traefik'`, the server's shared\n\t * Traefik edge, which every stack registers its routes with. One value\n\t * for every deployed stage, or one per stage. The local stage is always\n\t * Caddy.\n\t *\n\t * ```ts\n\t * proxy: 'traefik'\n\t * proxy: { staging: 'traefik', production: 'caddy' }\n\t * ```\n\t */\n\tproxy?: ComposeProxy | StageMap<S, ComposeProxy>;\n\t/**\n\t * A deployed stage's own certificate, by stage, instead of one from\n\t * Let's Encrypt: a PEM certificate (with its chain) and its key, relative\n\t * to the workspace root or absolute. Either proxy serves it.\n\t *\n\t * ```ts\n\t * tls: { production: { certFile: 'certs/origin.pem', keyFile: 'certs/origin.key' } }\n\t * ```\n\t */\n\ttls?: StageMap<S, ComposeTlsConfig>;\n}\n\n/** The proxies a compose stack can be served by — `deploy.compose.proxy`. */\nexport type ComposeProxy = 'caddy' | 'traefik';\n\n/** A stage's own certificate — `deploy.compose.tls.<stage>`. */\nexport interface ComposeTlsConfig {\n\tcertFile: string;\n\tkeyFile: string;\n}\n\n/**\n * Where one stage's telemetry goes, and how much of it — `deploy.telemetry`,\n * by stage.\n *\n * What is emitted is the application's (the `Telemetry` construct); where it\n * goes is this. A server target runs the self-hosted provider when a stage\n * names nothing; AWS has none, so a deployed AWS stage that uses telemetry\n * names a provider. `false` sends nothing. The local stage ignores this: `gkm\n * dev` and `gkm compose` on it always run OpenObserve, at 100%.\n *\n * @example\n * ```ts\n * telemetry: {\n * staging: 'self-hosted',\n * production: { provider: 'self-hosted', retentionDays: 14, sampleRate: 0.1 },\n * preview: { provider: 'otlp', endpoint: 'https://otlp.example.com', sampleRate: 0.5 },\n * scratch: false,\n * }\n * ```\n */\nexport type StageTelemetryConfig =\n\t| 'self-hosted'\n\t| SelfHostedTelemetryConfig\n\t| OtlpTelemetryConfig\n\t| false;\n\n/**\n * What backs one deployed stage's buckets — `deploy.objects`, by stage.\n *\n * - `'external'` (the default) — the stage's secrets hold each bucket's URL,\n * set by you: S3, R2, any S3-compatible store.\n * - `{ provider: 's3' }` — every deploy of the stage creates (or repairs)\n * each bucket, its IAM user and key in the stage's AWS account, and writes\n * the bucket's URL into the stage's secrets, before its checks.\n * - `false` — the stage has no object storage; a bucket on it is refused.\n *\n * The local stage ignores this: `gkm dev` runs MinIO for every bucket.\n *\n * @example\n * ```ts\n * objects: {\n * production: { provider: 's3', region: 'eu-west-1', versioning: true },\n * staging: 'external',\n * }\n * ```\n */\nexport type StageObjectsConfig = 'external' | S3ObjectsConfig | false;\n\n/** `objects: { provider: 's3' }` — a bucket per construct in the stage's account. */\nexport interface S3ObjectsConfig {\n\tprovider: 's3';\n\t/**\n\t * Where the buckets are created. Defaults to the secrets store's region,\n\t * then `AWS_REGION`.\n\t */\n\tregion?: string;\n\t/** Keep previous versions of every object. Defaults to the construct's own `versioned`. */\n\tversioning?: boolean;\n}\n\n/** Shared by every provider. */\ninterface TelemetryProviderConfig {\n\t/**\n\t * The fraction of traces kept, decided where a trace starts and followed\n\t * by every service it reaches (`parentbased_traceidratio`). Logs are not\n\t * sampled. 0 to 1; default 1.\n\t */\n\tsampleRate?: number;\n}\n\n/**\n * The target runs the collector and its UI: OpenObserve, in a compose stack,\n * reached through an SSH tunnel by default.\n */\nexport interface SelfHostedTelemetryConfig extends TelemetryProviderConfig {\n\tprovider: 'self-hosted';\n\t/**\n\t * The port it is published on, on 127.0.0.1 only — reached from another\n\t * machine through an SSH tunnel. Default 5080.\n\t */\n\tport?: number;\n\t/**\n\t * How many days of data it keeps (OpenObserve's\n\t * `ZO_COMPACT_DATA_RETENTION_DAYS`). At least 3; default 30.\n\t */\n\tretentionDays?: number;\n\t/**\n\t * Serve it on `logs.<stage domain>` through the stack's proxy, to these\n\t * addresses only (IPs or CIDRs), instead of on a loopback port. Every\n\t * other address is answered 403.\n\t */\n\tpublic?: { allow: string[] };\n}\n\n/** Any OTLP/HTTP endpoint — a collector, a vendor's ingest. */\nexport interface OtlpTelemetryConfig extends TelemetryProviderConfig {\n\tprovider: 'otlp';\n\t/** The OTLP/HTTP base URL; `/v1/traces` and `/v1/logs` are added to it. */\n\tendpoint: string;\n\t/** Headers sent with every export — `{ 'x-team': 'shop' }`. */\n\theaders?: Record<string, string>;\n}\n\n/**\n * DNS provider types for automatic DNS record creation.\n */\nexport type DnsProviderType =\n\t| 'hostinger'\n\t| 'route53'\n\t| 'godaddy'\n\t| 'cloudflare'\n\t| 'manual';\n\n/**\n * Deployment configuration for the workspace.\n *\n * @example\n * ```ts\n * // Minimal - just set default target\n * deploy: {\n * default: 'dokploy',\n * }\n *\n * // Full configuration with backups (domains and dns are at the root)\n * deploy: {\n * default: 'dokploy',\n * registry: 'ghcr.io/myorg',\n * dokploy: {\n * endpoint: 'https://dokploy.myserver.com',\n * projectId: 'proj_abc123',\n * },\n * backups: {\n * type: 's3',\n * region: 'us-east-1',\n * },\n * }\n * ```\n */\nexport interface DeployConfig<S extends string = string> {\n\t/** Default deploy target for all apps (default: 'dokploy') */\n\tdefault?: DeployTargetName;\n\t/**\n\t * Targets that do not ship with the CLI, by the name `default` (or an\n\t * app's `deploy`) uses: a package whose default export is the target, a\n\t * target object, or either with its options.\n\t *\n\t * ```ts\n\t * targets: {\n\t * acme: '@acme/gkm-target',\n\t * fly: ['@acme/gkm-fly', { org: 'acme' }],\n\t * local: defineTarget({ … }),\n\t * }\n\t * ```\n\t *\n\t * A package is never guessed from a name: it is installed and listed here.\n\t * A built-in's name cannot be taken.\n\t */\n\ttargets?: Record<string, DeployTargetEntry>;\n\t/**\n\t * Whose deploy this is, on a target shared with other workspaces — an\n\t * organisation or a team, lowercase `[a-z0-9-]`. Two workspaces with the\n\t * same name deploying to one Dokploy are kept apart by it: it is in the\n\t * project's ownership marker, the image path\n\t * (`<registry>/<namespace>/<project>-<app>`) and every resource name.\n\t *\n\t * Defaults to the kebab-cased workspace name, which adds nothing to the\n\t * names a workspace was already deployed under.\n\t */\n\tnamespace?: string;\n\t/**\n\t * The container registry the apps' images are pushed to and pulled from,\n\t * whatever the target — `ghcr.io/myorg`. An image is\n\t * `<registry>/<namespace>/<project>-<app>:<tag>`.\n\t */\n\tregistry?: string;\n\t/** Dokploy-specific configuration */\n\tdokploy?: DokployWorkspaceConfig;\n\t/** What the `compose` target runs beside the apps — see {@link ComposeWorkspaceConfig}. */\n\tcompose?: ComposeWorkspaceConfig<S>;\n\t/**\n\t * Where each deployed stage's telemetry goes — see\n\t * {@link StageTelemetryConfig}.\n\t */\n\ttelemetry?: StageMap<S, StageTelemetryConfig>;\n\t/**\n\t * What backs each deployed stage's buckets — the `objects` kind that\n\t * `ObjectStorage` and `FileServer` produce. See {@link StageObjectsConfig}.\n\t */\n\tobjects?: StageMap<S, StageObjectsConfig>;\n\t/** Backup destination configuration for database services */\n\tbackups?: BackupsConfig;\n}\n\n/**\n * Models package configuration for shared schemas.\n *\n * Configures a shared models package containing Zod schemas\n * that can be used across backend and frontend apps.\n *\n * @example\n * ```ts\n * shared: {\n * models: {\n * path: 'packages/models',\n * schema: 'zod',\n * },\n * }\n * ```\n */\nexport interface ModelsConfig {\n\t/** Path to models package relative to workspace root (default: 'packages/models') */\n\tpath?: string;\n\t/**\n\t * Schema library to use (default: 'zod').\n\t * Currently only 'zod' is supported.\n\t * Future: any StandardSchema-compatible library\n\t */\n\tschema?: 'zod';\n}\n\n/**\n * Shared packages configuration.\n *\n * Configures shared packages in the monorepo that are\n * used by multiple apps.\n *\n * @example\n * ```ts\n * shared: {\n * packages: ['packages/*', 'libs/*'],\n * models: {\n * path: 'packages/models',\n * schema: 'zod',\n * },\n * }\n * ```\n */\nexport interface SharedConfig {\n\t/** Glob patterns for shared packages (default: ['packages/*']) */\n\tpackages?: string[];\n\t/** Models package configuration */\n\tmodels?: ModelsConfig;\n}\n\n/**\n * The project's stages, named by the project.\n *\n * Stage names were literals scattered through the CLI — `gkm dev` ran as\n * `development` and looked for `dev` secrets first, a deploy script said\n * `production` — so a team that called its stages anything else was\n * working against the tool. They are declared once, here, and read.\n *\n * @example\n * ```ts\n * stages: { local: 'dev', deployed: ['staging', 'prod'], protected: ['prod'] }\n * ```\n */\nexport interface StagesConfig {\n\t/**\n\t * What `gkm dev`, `exec`, `setup` and `test` run as: the stage whose\n\t * secrets are read locally, and whose containers carry no suffix.\n\t *\n\t * Never also a deployed stage. Secrets are stored per stage name, so a\n\t * deployed stage sharing it would share its secrets with every laptop.\n\t */\n\tlocal: string;\n\t/** The stages `gkm deploy --stage` accepts. */\n\tdeployed: string[];\n\t/**\n\t * Deployed stages whose resources outlive the stack that made them —\n\t * retained on removal and protected, e.g. the stage users are on.\n\t */\n\tprotected?: string[];\n}\n\n/**\n * Secrets encryption configuration.\n *\n * Configures how secrets are encrypted for deployment.\n * Secrets are stored encrypted in `.gkm/secrets/{stage}.json`\n * with keys stored separately in `~/.gkm/keys/{namespace}/{project}/{stage}.key`.\n *\n * @example\n * ```ts\n * secrets: {\n * enabled: true,\n * algorithm: 'aes-256-gcm',\n * kdf: 'scrypt',\n * }\n * ```\n */\nexport interface SecretsConfig {\n\t/** Enable encrypted secrets (default: true) */\n\tenabled?: boolean;\n\t/**\n\t * Where deployed stages' secrets live, so a deploy can reach them from\n\t * anywhere: `'file'` (default — the encrypted `.gkm/secrets/<stage>.json`,\n\t * which cannot serve CI while `.gkm/` is gitignored), `{ provider: 'ssm',\n\t * region }` (each stage's secrets in an SSM parameter in its own AWS\n\t * account, up to 8 KB), `{ provider: 'secrets-manager', region, kmsKeyId? }`\n\t * (a Secrets Manager secret in its own account, up to 64 KB), or any object\n\t * implementing `SecretsStore`. The local stage always uses the file.\n\t */\n\tstore?: import('../secrets/store.js').SecretsStoreConfig;\n\t/** Encryption algorithm (default: 'aes-256-gcm') */\n\talgorithm?: string;\n\t/** Key derivation function (default: 'scrypt') */\n\tkdf?: 'scrypt' | 'pbkdf2';\n}\n\n/**\n * Base app configuration properties (shared between input and normalized).\n *\n * @example\n * ```ts\n * // Backend app with gkm routes\n * api: {\n * type: 'backend',\n * path: 'apps/api',\n * port: 3000,\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * }\n *\n * // Backend app with entry point (e.g., Better Auth)\n * auth: {\n * type: 'backend',\n * path: 'apps/auth',\n * port: 3001,\n * entry: './src/index.ts',\n * framework: 'better-auth',\n * requiredEnv: ['DATABASE_URL', 'BETTER_AUTH_SECRET'],\n * }\n *\n * // Frontend app\n * web: {\n * type: 'web',\n * path: 'apps/web',\n * port: 3002,\n * framework: 'nextjs',\n * dependencies: ['api', 'auth'],\n * }\n * ```\n */\ninterface AppConfigBase {\n\t/**\n\t * App type.\n\t * - 'backend': Server-side app (API, auth service, etc.)\n\t * - 'web': Client-side web app (Next.js, Vite, TanStack Start, etc.)\n\t * - 'mobile': Native mobile app (Expo). Built/deployed via its own\n\t * toolchain (e.g. EAS Build) — Docker/Dokploy steps are skipped.\n\t * @default 'backend'\n\t */\n\ttype?: 'backend' | 'web' | 'mobile';\n\n\t/**\n\t * Path to the app relative to workspace root.\n\t * @example 'apps/api', 'apps/web', 'services/auth'\n\t */\n\tpath: string;\n\n\t/**\n\t * Development server port.\n\t * Must be unique across all apps in the workspace.\n\t * @example 3000, 3001, 3002\n\t */\n\tport: number;\n\n\t/**\n\t * Per-app deploy target override.\n\t * Overrides `deploy.default` for this specific app.\n\t * @example 'dokploy', 'vercel'\n\t */\n\tdeploy?: DeployTargetName;\n\n\t// ─────────────────────────────────────────────────────────────────\n\t// Backend-specific (gkm routes mode)\n\t// ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Constructs glob pattern — one glob, every kind.\n\t *\n\t * A glob per kind cannot find a resource, because a declared `ObjectStorage`\n\t * has no kind to be listed under. This one is what reconcile reads to derive\n\t * the containers a stage needs, and it replaces the per-kind globs below.\n\t *\n\t * @example './src/**\\/*.ts'\n\t */\n\tconstructs?: Routes;\n\n\t/**\n\t * Routes glob pattern for gkm endpoints.\n\t * @example './src/endpoints/**\\/*.ts'\n\t */\n\troutes?: Routes;\n\n\t/**\n\t * Functions glob pattern for Lambda functions.\n\t * @example './src/functions/**\\/*.ts'\n\t */\n\tfunctions?: Routes;\n\n\t/**\n\t * Crons glob pattern for scheduled tasks.\n\t * @example './src/crons/**\\/*.ts'\n\t */\n\tcrons?: Routes;\n\n\t/**\n\t * Queues glob pattern for point-to-point workers.\n\t * @example './src/queues/**\\/*.ts'\n\t */\n\tqueues?: Routes;\n\n\t/**\n\t * Topics glob pattern for the topics subscribers bind to.\n\t * @example './src/topics/**\\/*.ts'\n\t */\n\ttopics?: Routes;\n\n\t/**\n\t * Subscribers glob pattern for event handlers.\n\t * @example './src/subscribers/**\\/*.ts'\n\t */\n\tsubscribers?: Routes;\n\n\t/**\n\t * Path to environment parser module.\n\t * @example './src/config/env'\n\t */\n\tenvParser?: string;\n\n\t/**\n\t * Path to logger module.\n\t * @example './src/config/logger'\n\t */\n\tlogger?: string;\n\n\t/**\n\t * Server lifecycle hooks.\n\t * @example { beforeSetup: './src/hooks/setup.ts' }\n\t */\n\thooks?: HooksConfig;\n\n\t/**\n\t * Telescope request recording configuration.\n\t * @example true, './src/config/telescope', { enabled: true, path: '/__telescope' }\n\t */\n\ttelescope?: string | boolean | TelescopeConfig;\n\n\t/**\n\t * OpenAPI documentation configuration.\n\t * @example true, { output: './src/openapi.ts' }\n\t */\n\topenapi?: boolean | OpenApiConfig;\n\n\t/**\n\t * Runtime environment.\n\t * @default 'node'\n\t */\n\truntime?: Runtime;\n\n\t/**\n\t * Environment file(s) to load during development.\n\t * @example '.env', ['.env', '.env.local']\n\t */\n\tenv?: string | string[];\n\n\t// ─────────────────────────────────────────────────────────────────\n\t// Entry point mode (non-gkm apps)\n\t// ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Entry file path for apps that don't use gkm routes.\n\t *\n\t * When specified, the app is run directly with tsx in development\n\t * and bundled with esbuild for production Docker builds.\n\t *\n\t * Use this for:\n\t * - Better Auth servers\n\t * - Custom Hono/Express apps\n\t * - Any backend that doesn't use gkm's endpoint builder\n\t *\n\t * @example './src/index.ts', './src/server.ts'\n\t */\n\tentry?: string;\n\n\t// ─────────────────────────────────────────────────────────────────\n\t// Frontend-specific\n\t// ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Framework for the app.\n\t *\n\t * Backend frameworks: 'hono', 'better-auth', 'express', 'fastify'\n\t * Frontend frameworks: 'nextjs', 'remix', 'vite', 'tanstack-start'\n\t * Mobile frameworks: 'expo'\n\t *\n\t * @example 'nextjs', 'better-auth', 'hono', 'expo'\n\t */\n\tframework?: Framework;\n\n\t/**\n\t * Config file paths for frontend environment sniffing.\n\t *\n\t * Points to file(s) that call EnvironmentParser.parse() at import time.\n\t * The sniffer imports these files and captures all env vars accessed.\n\t *\n\t * Dependencies are auto-generated as public-prefixed URL vars based on\n\t * the app's framework (e.g. `NEXT_PUBLIC_{DEP}_URL` for Next.js,\n\t * `VITE_{DEP}_URL` for Vite/TanStack Start, `EXPO_PUBLIC_{DEP}_URL`\n\t * for Expo).\n\t *\n\t * @example\n\t * ```ts\n\t * config: {\n\t * client: './src/config/client.ts', // public-prefixed vars for browser\n\t * server: './src/config/server.ts', // server-only vars for SSR\n\t * }\n\t * ```\n\t */\n\tconfig?: {\n\t\t/** Client-side config (public-prefixed vars, available in browser/device) */\n\t\tclient?: string;\n\t\t/** Server-side config (all env vars, for SSR/API routes) */\n\t\tserver?: string;\n\t};\n\n\t// ─────────────────────────────────────────────────────────────────\n\t// Deployment\n\t// ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Override domain for this app.\n\t *\n\t * By default, apps get `{appName}.{baseDomain}` (or just `{baseDomain}`\n\t * for the main frontend). Use this to specify a custom domain.\n\t *\n\t * @example\n\t * ```ts\n\t * // Single domain for all stages\n\t * domain: 'api.custom.com'\n\t *\n\t * // Stage-specific domains\n\t * domain: {\n\t * production: 'api.custom.com',\n\t * staging: 'api.staging.custom.com',\n\t * }\n\t * ```\n\t */\n\tdomain?: AppDomainConfig;\n\n\t/**\n\t * Required environment variables for entry-based apps.\n\t *\n\t * Use this instead of envParser for apps that don't use gkm routes.\n\t * The deploy command uses this list to filter which secrets to embed\n\t * in the Docker image.\n\t *\n\t * @example ['DATABASE_URL', 'BETTER_AUTH_SECRET', 'REDIS_URL']\n\t */\n\trequiredEnv?: string[];\n}\n\n/**\n * App configuration input with type-safe dependencies.\n *\n * @template TAppNames - Union of valid app names in the workspace (auto-inferred)\n *\n * @example\n * ```ts\n * // Dependencies are type-checked against app names\n * apps: {\n * api: { path: 'apps/api', port: 3000 },\n * auth: { path: 'apps/auth', port: 3001 },\n * web: {\n * path: 'apps/web',\n * port: 3002,\n * type: 'web',\n * dependencies: ['api', 'auth'], // ✓ Valid\n * // dependencies: ['invalid'], // ✗ Type error\n * },\n * }\n * ```\n */\nexport interface AppConfigInput<TAppNames extends string = string>\n\textends AppConfigBase {\n\t/** Dependencies on other apps in the workspace (type-safe) */\n\tdependencies?: TAppNames[];\n}\n\n/**\n * App configuration (legacy, for backwards compatibility).\n * @deprecated Use AppConfigInput for new code\n */\nexport interface AppConfig extends AppConfigBase {\n\t/** Dependencies on other apps in the workspace */\n\tdependencies?: string[];\n}\n\n/**\n * Base app input type for type inference.\n */\nexport type AppInput = AppConfigBase & {\n\tdependencies?: readonly string[];\n};\n\n/**\n * Apps record type for workspace configuration.\n */\nexport type AppsRecord = Record<string, AppInput>;\n\n/**\n * Constrain apps so dependencies only reference valid app names.\n * Dependencies must be an array of valid app names from the workspace.\n */\nexport type ConstrainedApps<TApps extends AppsRecord> = {\n\t[K in keyof TApps]: Omit<TApps[K], 'dependencies'> & {\n\t\tdependencies?: readonly (keyof TApps & string)[];\n\t};\n};\n\n/**\n * Full workspace input type with constrained dependencies.\n *\n * @example\n * ```ts\n * import { defineWorkspace } from '@geekmidas/cli';\n *\n * export default defineWorkspace({\n * name: 'my-app',\n * apps: {\n * api: {\n * path: 'apps/api',\n * port: 3000,\n * routes: './src/endpoints/**\\/*.ts',\n * },\n * web: {\n * type: 'web',\n * path: 'apps/web',\n * port: 3001,\n * framework: 'nextjs',\n * dependencies: ['api'],\n * },\n * },\n * deploy: {\n * default: 'dokploy',\n * },\n * });\n * ```\n */\nexport type WorkspaceInput<\n\tTApps extends AppsRecord,\n\tTDeployed extends string = string,\n> = {\n\t/**\n\t * Where the workspace's own constructs live, relative to its root.\n\t *\n\t * The product's infrastructure, declared once for every app that consumes\n\t * it. Additive with an app's own glob rather than replacing it.\n\t */\n\tconstructs?: Routes;\n\t/** Workspace name (defaults to root package.json name) */\n\tname?: string;\n\t/**\n\t * Apps that nothing declares.\n\t *\n\t * Normally absent: a `site` is an app and so is a `rest-api` that named\n\t * one, so the list is read off the graph. This is the escape hatch for what\n\t * no construct describes.\n\t */\n\tapps?: ConstrainedApps<TApps>;\n\t/** Shared packages configuration */\n\tshared?: SharedConfig;\n\t/**\n\t * Each deployed stage's base domain — see {@link DomainsConfig}. A key that\n\t * is not a deployed stage is a type error.\n\t */\n\tdomains?: DomainsInput<NoInfer<TDeployed>>;\n\t/**\n\t * Each root domain's DNS provider, and how its hosts are pointed at a\n\t * compose stage's server (`records`).\n\t */\n\tdns?: DnsInput<NoInfer<TDeployed>>;\n\t/** Deployment configuration */\n\tdeploy?: DeployConfig<NoInfer<TDeployed>>;\n\t/**\n\t * The project's stages: which one is local, which deploy. The deployed\n\t * stages type every per-stage map — `domains`, `deploy.objects`,\n\t * `deploy.telemetry`, `deploy.compose.proxy`/`tls`.\n\t */\n\tstages: StagesInput<TDeployed>;\n\t/** Encrypted secrets configuration */\n\tsecrets?: SecretsConfig;\n\t/** State provider configuration (local filesystem by default, or SSM for team collaboration) */\n\tstate?: StateConfig;\n\t/** How `gkm dev` is reached: the discovery endpoint's port and origins */\n\tdev?: DevConfig;\n};\n\n/** `stages`, as `defineWorkspace` infers it: each deployed stage literally. */\nexport interface StagesInput<TDeployed extends string = string> {\n\tlocal: string;\n\tdeployed: readonly TDeployed[];\n\tprotected?: readonly NoInfer<TDeployed>[];\n}\n\n/**\n * How `gkm dev` is reached from outside the apps it runs.\n */\nexport interface DevConfig {\n\t/**\n\t * Browser origins allowed to read the discovery endpoint — and this\n\t * workspace in it — e.g. `['https://console.example.com']`.\n\t *\n\t * Empty by default: any page the developer visits can send requests to a\n\t * loopback port, so none is answered unless it is listed here. A request\n\t * with no `Origin` (curl, a local process) still needs the session token.\n\t */\n\tallowedOrigins?: string[];\n\t/**\n\t * The loopback port the discovery endpoint listens on. Defaults to 4983;\n\t * `GKM_DISCOVERY_PORT` overrides it.\n\t */\n\tdiscoveryPort?: number;\n}\n\n/**\n * How `gkm test` builds what a feature test is handed.\n */\nexport interface TestConfig {\n\t/**\n\t * The folder of test factories, relative to the root.\n\t *\n\t * Defaults to `test/factories`. A factory belongs to a database, not to an\n\t * app, so each file is named after one — `database.ts` for `Database`,\n\t * `auth-database.ts` for `AuthDatabase` — and exports `createFactory(db)`.\n\t * Every app's harness builds them on each test's transactions, and a test is\n\t * handed them as `factories`, keyed by service name.\n\t */\n\tfactories?: string;\n}\n\n/**\n * Extract app names from apps record.\n */\nexport type InferAppNames<TApps extends AppsRecord> = keyof TApps & string;\n\n/**\n * Inferred workspace config with proper app name types.\n */\nexport type InferredWorkspaceConfig<TApps extends AppsRecord> = {\n\t/**\n\t * Where the workspace's own constructs live, relative to its root.\n\t *\n\t * The product's infrastructure, declared once for every app that consumes\n\t * it. Additive with an app's own glob rather than replacing it.\n\t */\n\tconstructs?: Routes;\n\tname?: string;\n\tapps?: {\n\t\t[K in keyof TApps]: Omit<TApps[K], 'dependencies'> & {\n\t\t\tdependencies?: InferAppNames<TApps>[];\n\t\t};\n\t};\n\tshared?: SharedConfig;\n\tdomains?: DomainsConfig;\n\tdns?: WorkspaceDnsConfig;\n\tdeploy?: DeployConfig;\n\tstages: StagesConfig;\n\tsecrets?: SecretsConfig;\n\tstate?: StateConfig;\n\ttest?: TestConfig;\n\tdev?: DevConfig;\n};\n\n// Legacy types for backwards compatibility\n/** @deprecated Use WorkspaceInput */\nexport type RawWorkspaceInput = {\n\tname?: string;\n\tapps: AppsRecord;\n\tshared?: SharedConfig;\n\tdeploy?: DeployConfig;\n\tsecrets?: SecretsConfig;\n\tstate?: StateConfig;\n};\n\n/** @deprecated Use WorkspaceInput */\nexport type WorkspaceConfigInput<\n\tT extends RawWorkspaceInput = RawWorkspaceInput,\n> = WorkspaceInput<T['apps']>;\n\n/**\n * Workspace configuration for multi-app monorepos.\n *\n * Use `defineWorkspace()` helper for type-safe configuration with\n * auto-completion and dependency validation.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineWorkspace } from '@geekmidas/cli';\n *\n * export default defineWorkspace({\n * name: 'my-saas',\n *\n * // App definitions\n * apps: {\n * // Backend API with gkm routes\n * api: {\n * path: 'apps/api',\n * port: 3000,\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * },\n *\n * // Better Auth service\n * auth: {\n * path: 'apps/auth',\n * port: 3001,\n * entry: './src/index.ts',\n * framework: 'better-auth',\n * requiredEnv: ['DATABASE_URL', 'BETTER_AUTH_SECRET'],\n * },\n *\n * // Next.js frontend\n * web: {\n * type: 'web',\n * path: 'apps/web',\n * port: 3002,\n * framework: 'nextjs',\n * dependencies: ['api', 'auth'],\n * },\n * },\n *\n * // Each deployed stage's base domain, and who hosts its DNS\n * domains: {\n * production: 'myapp.com',\n * staging: 'staging.myapp.com',\n * },\n * dns: { 'myapp.com': { provider: 'godaddy' } },\n *\n * // Deployment configuration\n * deploy: {\n * default: 'dokploy',\n * registry: 'ghcr.io/myorg',\n * dokploy: {\n * endpoint: 'https://dokploy.myserver.com',\n * projectId: 'proj_abc123',\n * },\n * },\n *\n * // Shared packages\n * shared: {\n * packages: ['packages/*'],\n * models: { path: 'packages/models' },\n * },\n * });\n * ```\n *\n * @deprecated Use WorkspaceInput with defineWorkspace for type inference\n */\nexport interface WorkspaceConfig {\n\t/**\n\t * Where the workspace's own constructs live, relative to its root.\n\t *\n\t * The product's infrastructure, declared once for every app that consumes\n\t * it. Additive with an app's own glob rather than replacing it.\n\t */\n\tconstructs?: Routes;\n\t/** Workspace name (defaults to root package.json name) */\n\tname?: string;\n\n\t/** Apps that nothing declares. Normally absent — see `WorkspaceInput`. */\n\tapps?: Record<string, AppConfig>;\n\n\t/** Shared packages configuration */\n\tshared?: SharedConfig;\n\n\t/** Each deployed stage's base domain — see {@link DomainsConfig}. */\n\tdomains?: DomainsConfig;\n\n\t/** Each root domain's DNS provider — see {@link WorkspaceDnsConfig}. */\n\tdns?: WorkspaceDnsConfig;\n\n\t/** Default deployment configuration */\n\tdeploy?: DeployConfig;\n\n\t/** The project's stages: which one is local, which deploy */\n\tstages: StagesConfig;\n\n\t/** Encrypted secrets configuration */\n\tsecrets?: SecretsConfig;\n\n\t/** State provider configuration (local filesystem by default, or SSM for team collaboration) */\n\tstate?: StateConfig;\n\n\t/** What `gkm test` hands a feature test: where the factories are. */\n\ttest?: TestConfig;\n\n\t/** How `gkm dev` is reached: the discovery endpoint's port and origins. */\n\tdev?: DevConfig;\n}\n\n/**\n * Normalized app configuration with resolved defaults.\n *\n * This is the internal representation after processing user input.\n * All optional fields have been resolved to their defaults.\n */\nexport interface NormalizedAppConfig extends Omit<AppConfigBase, 'type'> {\n\t/**\n\t * Whether the base domain points at this site.\n\t *\n\t * Carried from the `site` declaration rather than configured, because which\n\t * site is primary is structural — its *hostname* is what varies by stage,\n\t * and that is `domain`.\n\t */\n\troot?: boolean;\n\n\t/**\n\t * The label this app answers on under a stage's domain, carried from its\n\t * declaration — `api` for `api.myapp.com`. Absent, the app's own name.\n\t */\n\tsubdomain?: string;\n\n\t/** App type (always defined after normalization) */\n\ttype: 'backend' | 'web' | 'mobile';\n\t/** Path to the app */\n\tpath: string;\n\t/** Development server port */\n\tport: number;\n\t/** Resolved dependencies array (empty array if none) */\n\tdependencies: string[];\n\t/** Resolved deploy target (app.deploy > deploy.default > 'dokploy') */\n\tresolvedDeployTarget: DeployTargetName;\n\t/** Entry file path for non-gkm apps */\n\tentry?: string;\n\t/** Framework for the app */\n\tframework?: Framework;\n\t/** Override domain for this app */\n\tdomain?: AppDomainConfig;\n\t/** Required environment variables for entry-based apps */\n\trequiredEnv?: string[];\n}\n\n/**\n * Normalized workspace configuration with resolved defaults.\n *\n * This is the internal representation after processing user input.\n * All optional fields have been resolved to their defaults.\n */\nexport interface NormalizedWorkspace {\n\t/** Workspace name (resolved from package.json if not specified) */\n\tname: string;\n\t/** Absolute path to workspace root */\n\troot: string;\n\t/**\n\t * The workspace's own constructs glob, relative to `root`.\n\t *\n\t * Where the product's shared infrastructure is declared. Additive with each\n\t * app's glob, so an app can still declare something only it uses.\n\t */\n\tconstructs?: Routes;\n\t/** Normalized app configurations */\n\tapps: Record<string, NormalizedAppConfig>;\n\t/** Each deployed stage's base domain */\n\tdomains?: DomainsConfig;\n\t/** Each root domain's DNS provider */\n\tdns?: WorkspaceDnsConfig;\n\t/** Deploy configuration (empty object if not specified) */\n\tdeploy: DeployConfig;\n\t/** Shared packages configuration (empty object if not specified) */\n\tshared: SharedConfig;\n\t/** The project's stages, as declared */\n\tstages: StagesConfig;\n\t/** Secrets configuration (empty object if not specified) */\n\tsecrets: SecretsConfig;\n\t/** State provider configuration (undefined = local filesystem) */\n\tstate?: StateConfig;\n\t/** What `gkm test` hands a feature test (empty object if not specified) */\n\ttest: TestConfig;\n\t/** How `gkm dev` is reached, when configured */\n\tdev?: DevConfig;\n}\n\n/**\n * Result of loading and processing a configuration.\n */\nexport interface LoadedConfig {\n\t/** Whether this is a single-app or workspace config */\n\ttype: 'single' | 'workspace';\n\t/** The raw configuration as loaded */\n\traw: GkmConfig | WorkspaceConfig;\n\t/** Normalized workspace (always available) */\n\tworkspace: NormalizedWorkspace;\n\t/**\n\t * What the workspace's constructs declared, when it has any.\n\t *\n\t * Read once at load, because the apps above are derived from it and a\n\t * caller that re-discovers would be answering the same question twice with\n\t * two chances to disagree. Absent when the workspace declares no constructs.\n\t */\n\tmanifest?: ConstructManifest;\n\t/**\n\t * The files each Worker's crons, queues and subscribers are declared in,\n\t * read in the same discovery — what says which app a worker is built from.\n\t */\n\tbackground?: Record<string, string[]>;\n}\n\n/**\n * Type guard to check if a config is a WorkspaceConfig.\n *\n * @example\n * ```ts\n * const config = await loadConfig();\n * if (isWorkspaceConfig(config)) {\n * // config.apps is available\n * console.log(Object.keys(config.apps));\n * }\n * ```\n */\nexport function isWorkspaceConfig(\n\tconfig: GkmConfig | WorkspaceConfig,\n): config is WorkspaceConfig {\n\tif (typeof config !== 'object' || config === null) return false;\n\n\t// `apps` used to be the only tell, and it stopped being one when apps\n\t// became derived: a workspace that declares its apps through constructs has\n\t// none. `constructs` at the top level is the other tell — a single-app\n\t// `defineConfig` has no notion of a workspace-wide glob — and either alone\n\t// is enough.\n\tif ('apps' in config && typeof config.apps === 'object') return true;\n\n\t// Only when nothing else says it is one app. `openapi`, `telescope`,\n\t// `hooks` and the rest configure a single process, so a config that\n\t// sets any of them is that process's — the workspace schema is strict,\n\t// and reading one of these as a workspace would reject what it was never\n\t// meant to accept.\n\treturn (\n\t\t'constructs' in config &&\n\t\tObject.keys(config).every((key) => WORKSPACE_KEYS.has(key))\n\t);\n}\n\n/** Every top-level key a workspace config has — see `WorkspaceConfigSchema`. */\nconst WORKSPACE_KEYS: ReadonlySet<string> = new Set([\n\t'name',\n\t'constructs',\n\t'apps',\n\t'shared',\n\t'domains',\n\t'dns',\n\t'deploy',\n\t'stages',\n\t'secrets',\n\t'state',\n]);\n","import type { Framework } from './types.js';\n\n/**\n * All public env-var prefixes the toolbox understands.\n *\n * Used when resolving incoming var names back to a dependency\n * (e.g. `VITE_AUTH_URL` → `auth`). A var matching any of these\n * is considered safe to inline into a client bundle.\n */\nexport const PUBLIC_ENV_PREFIXES = [\n\t'NEXT_PUBLIC_',\n\t'VITE_',\n\t'EXPO_PUBLIC_',\n] as const;\n\n/**\n * Resolve the public env-var prefix that a frontend framework's bundler\n * inlines into client code at build time:\n *\n * - `nextjs` → `NEXT_PUBLIC_`\n * - `vite` → `VITE_`\n * - `tanstack-start` → `VITE_` (uses Vite under the hood)\n * - `expo` → `EXPO_PUBLIC_`\n * - `remix` → `''` (Remix exposes via loaders, no prefix convention)\n *\n * For backend frameworks or unspecified, falls back to `NEXT_PUBLIC_` to\n * preserve the historical default. Backend apps never read these vars\n * from a bundle, so the prefix only affects scaffolding/symmetry.\n */\nexport function getPublicEnvPrefix(framework?: Framework): string {\n\tswitch (framework) {\n\t\tcase 'vite':\n\t\tcase 'tanstack-start':\n\t\t\treturn 'VITE_';\n\t\tcase 'expo':\n\t\t\treturn 'EXPO_PUBLIC_';\n\t\tcase 'remix':\n\t\t\treturn '';\n\t\tcase 'nextjs':\n\t\t\treturn 'NEXT_PUBLIC_';\n\t\tdefault:\n\t\t\treturn 'NEXT_PUBLIC_';\n\t}\n}\n\n/**\n * Strip a known public prefix from a var name.\n * Returns the un-prefixed name, or `null` if no prefix matched.\n */\nexport function stripPublicPrefix(name: string): string | null {\n\tfor (const prefix of PUBLIC_ENV_PREFIXES) {\n\t\tif (prefix && name.startsWith(prefix)) {\n\t\t\treturn name.slice(prefix.length);\n\t\t}\n\t}\n\treturn null;\n}\n","import { basename, isAbsolute, join } from 'node:path';\nimport { GkmError } from '../errors';\nimport { assertKnownSecretsStore } from '../secrets/providers.js';\nimport type { GkmConfig, Routes } from '../types.js';\nimport {\n\tformatValidationErrors,\n\tsafeValidateWorkspaceConfig,\n} from './schema.js';\nimport { InvalidStages, stageProblems, validateStages } from './stages.js';\nimport type {\n\tAppConfig,\n\tAppsRecord,\n\tDeployTargetName,\n\tInferredWorkspaceConfig,\n\tLoadedConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n\tWorkspaceConfig,\n\tWorkspaceInput,\n} from './types.js';\nimport { isWorkspaceConfig } from './types.js';\n\nexport {\n\tgetPublicEnvPrefix,\n\tPUBLIC_ENV_PREFIXES,\n\tstripPublicPrefix,\n} from './publicEnv.js';\nexport {\n\tformatValidationErrors,\n\tgetDeployTargetError,\n\tisDeployTargetSupported,\n\tisPhase2DeployTarget,\n\tPHASE_2_DEPLOY_TARGETS,\n\tSUPPORTED_DEPLOY_TARGETS,\n\tsafeValidateWorkspaceConfig,\n\tvalidateWorkspaceConfig,\n\tWorkspaceConfigSchema,\n} from './schema.js';\n// Re-export types\nexport type {\n\tAppConfig,\n\tAppConfigInput,\n\tAppInput,\n\tAppsRecord,\n\tBackendFramework,\n\tComposeWorkspaceConfig,\n\tConstrainedApps,\n\tDeployConfig,\n\tDeployTargetName,\n\tDokployWorkspaceConfig,\n\tFrontendFramework,\n\tInferAppNames,\n\tInferredWorkspaceConfig,\n\tLoadedConfig,\n\tMobileFramework,\n\tModelsConfig,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n\tOtlpTelemetryConfig,\n\tSecretsConfig,\n\tSelfHostedTelemetryConfig,\n\tSharedConfig,\n\tStageTelemetryConfig,\n\tWorkspaceConfig,\n\tWorkspaceInput,\n} from './types.js';\nexport { isWorkspaceConfig } from './types.js';\n\n/**\n * Validate that all dependencies reference existing apps.\n * Returns the config if valid, throws otherwise.\n */\nfunction validateDependencies<TApps extends AppsRecord>(apps: TApps): void {\n\tconst appNames = new Set(Object.keys(apps));\n\n\tfor (const [appName, app] of Object.entries(apps)) {\n\t\tfor (const dep of app.dependencies ?? []) {\n\t\t\tif (!appNames.has(dep)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid dependency: App \"${appName}\" depends on \"${dep}\" which does not exist. ` +\n\t\t\t\t\t\t`Valid apps are: ${[...appNames].join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (dep === appName) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid dependency: App \"${appName}\" cannot depend on itself.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Define workspace configuration with full TypeScript support and type inference.\n *\n * Uses `const` type parameter to infer literal app names, providing:\n * - Autocomplete for app names in dependencies\n * - Type errors for invalid dependency references\n * - Full type inference for the returned config\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineWorkspace } from '@geekmidas/cli';\n *\n * export default defineWorkspace({\n * name: 'my-saas',\n * apps: {\n * api: {\n * type: 'backend',\n * path: 'apps/api',\n * port: 3000,\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/logger',\n * },\n * web: {\n * type: 'web',\n * framework: 'nextjs',\n * path: 'apps/web',\n * port: 3001,\n * dependencies: ['api'], // <- autocomplete shows 'api' | 'web'\n * },\n * },\n * });\n *\n * // config.apps.api <- full type inference\n * // config.apps.foo <- TypeScript error\n * ```\n */\nexport function defineWorkspace<\n\tconst TApps extends AppsRecord,\n\tconst TDeployed extends string = string,\n>(config: WorkspaceInput<TApps, TDeployed>): InferredWorkspaceConfig<TApps> {\n\tassertNoMovedDeployKeys(config.deploy);\n\tassertKnownSecretsStore(config.secrets?.store);\n\n\t// Validate dependencies at runtime\n\tif (config.apps) validateDependencies(config.apps as unknown as TApps);\n\n\t// Validate with Zod schema\n\tconst result = safeValidateWorkspaceConfig(config);\n\tif (!result.success && result.error) {\n\t\tthrow new Error(formatValidationErrors(result.error));\n\t}\n\n\treturn config as unknown as InferredWorkspaceConfig<TApps>;\n}\n\n/**\n * Get the package name from package.json in the given directory.\n */\nfunction getPackageName(cwd: string): string | undefined {\n\ttry {\n\t\t// Dynamic import would be async, so we use require for sync operation\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst pkg = require(`${cwd}/package.json`);\n\t\treturn pkg.name?.replace(/^@[^/]+\\//, ''); // Remove scope\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Normalize a workspace configuration with resolved defaults.\n */\nexport function normalizeWorkspace(\n\tconfig: WorkspaceConfig,\n\tcwd: string,\n): NormalizedWorkspace {\n\tconst name = config.name ?? getPackageName(cwd) ?? basename(cwd);\n\tconst defaultTarget = config.deploy?.default ?? 'dokploy';\n\n\tconst normalizedApps: Record<string, NormalizedAppConfig> = {};\n\n\tfor (const [appName, app] of Object.entries(config.apps ?? {})) {\n\t\tnormalizedApps[appName] = normalizeAppConfig(app, defaultTarget);\n\t}\n\n\treturn {\n\t\tname,\n\t\troot: cwd,\n\t\t...(config.constructs ? { constructs: config.constructs } : {}),\n\t\tapps: normalizedApps,\n\t\t...(config.domains ? { domains: config.domains } : {}),\n\t\t...(config.dns ? { dns: config.dns } : {}),\n\t\tdeploy: config.deploy ?? { default: 'dokploy' },\n\t\tshared: config.shared ?? { packages: ['packages/*'] },\n\t\tstages: validateStages(config.stages),\n\t\tsecrets: config.secrets ?? {},\n\t\tstate: config.state,\n\t\ttest: config.test ?? {},\n\t\t...(config.dev ? { dev: config.dev } : {}),\n\t};\n}\n\n/**\n * Normalize an app configuration with resolved defaults.\n * @param app - App configuration\n * @param defaultTarget - Default deploy target from workspace config\n */\nfunction normalizeAppConfig(\n\tapp: AppConfig,\n\tdefaultTarget: DeployTargetName,\n): NormalizedAppConfig {\n\treturn {\n\t\t...app,\n\t\ttype: app.type ?? 'backend',\n\t\tport: app.port,\n\t\tpath: app.path,\n\t\tdependencies: app.dependencies ?? [],\n\t\tresolvedDeployTarget: app.deploy ?? defaultTarget,\n\t};\n}\n\n/**\n * Wrap a single-app GkmConfig as a workspace.\n * This allows existing single-app configs to work seamlessly.\n */\nexport function wrapSingleAppAsWorkspace(\n\tconfig: GkmConfig,\n\tcwd: string,\n): NormalizedWorkspace {\n\t// `config.name` first, the way `defineWorkspace` already reads it. It was\n\t// only honoured on the workspace path, so the same field decided the scope\n\t// in a monorepo and was ignored in a single-app project.\n\tconst name = config.name ?? getPackageName(cwd) ?? basename(cwd);\n\n\t// A projection, not a default-filled stand-in.\n\t//\n\t// Every hardcoded value here was a field the config could already state and\n\t// this quietly dropped: the port it serves on, and the target it deploys to.\n\t// `resolvedDeployTarget` was the worse of the two — a project deploying to\n\t// Vercel was normalised into one that deploys to Dokploy, and nothing said\n\t// so.\n\tconst app: NormalizedAppConfig = {\n\t\ttype: 'backend',\n\t\tpath: '.',\n\t\tport: 3000,\n\t\tdependencies: [],\n\t\tresolvedDeployTarget: config.deploy?.default ?? 'dokploy',\n\t\tconstructs: config.constructs,\n\t\thooks: config.hooks,\n\t\ttelescope: config.telescope,\n\t\topenapi: config.openapi,\n\t\truntime: config.runtime,\n\t\tenv: config.env,\n\t};\n\n\treturn {\n\t\tname,\n\t\troot: cwd,\n\t\t// Keyed `api` because that is what a single-app backend is, and because\n\t\t// the key is what names the application: `applicationName(stage, name,\n\t\t// 'api')` is `production-<name>-api`, beside the\n\t\t// `production-<name>-database` its constructs get. One model, so the\n\t\t// deploy asks the workspace what its apps are called rather than asking\n\t\t// the filesystem.\n\t\tapps: { api: app },\n\t\t// Carried rather than replaced. A single-app project configures its\n\t\t// deploy in the same shape a workspace does — endpoint, registry,\n\t\t// domains — and hardcoding the default here silently discarded all of it,\n\t\t// which surfaced as `resolveHost` refusing to name a host for a stage the\n\t\t// config had no way to describe.\n\t\t...(config.domains ? { domains: config.domains } : {}),\n\t\t...(config.dns ? { dns: config.dns } : {}),\n\t\tdeploy: { default: 'dokploy', ...config.deploy },\n\t\tshared: { packages: [] },\n\t\tstages: validateStages(config.stages),\n\t\tsecrets: config.secrets ?? {},\n\t\ttest: config.test ?? {},\n\t\t...(config.dev ? { dev: config.dev } : {}),\n\t};\n}\n\n/**\n * Process a loaded configuration (either single-app or workspace).\n * Returns a normalized workspace in both cases.\n */\n/**\n * `deploy.dokploy.registry`, which became `deploy.registry`: every target\n * pushes and pulls through the one registry, so it is not Dokploy's to hold.\n *\n * Refused by name rather than dropped: the schema strips keys it does not\n * know, and a registry silently gone would deploy images under no registry.\n */\nexport class DokployRegistryMoved extends GkmError {\n\tconstructor(readonly registry: unknown) {\n\t\tsuper(\n\t\t\t`deploy.dokploy.registry is now deploy.registry, read by every deploy target. ` +\n\t\t\t\t`In gkm.config.ts, move it up one level: deploy: { registry: ${JSON.stringify(registry)}, dokploy: { … } }.`,\n\t\t);\n\t\tthis.name = 'DokployRegistryMoved';\n\t}\n}\n\n/**\n * `deploy.domains`, which became `domains` at the root of the config: a stage's\n * domain is a fact about the product every target and every command reads,\n * not a deploy setting.\n */\nexport class DomainsMoved extends GkmError {\n\tconstructor(readonly domains: unknown) {\n\t\tsuper(\n\t\t\t'deploy.domains is now domains, at the root of gkm.config.ts. Move it ' +\n\t\t\t\t`out of deploy: defineWorkspace({ …, domains: ${JSON.stringify(domains)}, deploy: { … } }).`,\n\t\t);\n\t\tthis.name = 'DomainsMoved';\n\t}\n}\n\n/**\n * `deploy.dns`, which became `dns` at the root of the config, keyed by root\n * domain.\n */\nexport class DnsMoved extends GkmError {\n\tconstructor(readonly dns: unknown) {\n\t\tconst legacy =\n\t\t\tdns && typeof dns === 'object' && 'domain' in dns && 'provider' in dns;\n\t\tconst { domain, ...rest } = (legacy ? dns : {}) as Record<string, unknown>;\n\t\tconst moved = legacy ? { [String(domain)]: rest } : dns;\n\t\tsuper(\n\t\t\t'deploy.dns is now dns, at the root of gkm.config.ts, keyed by root ' +\n\t\t\t\t`domain. Move it out of deploy: defineWorkspace({ …, dns: ${JSON.stringify(moved)}, deploy: { … } }).`,\n\t\t);\n\t\tthis.name = 'DnsMoved';\n\t}\n}\n\n/** Refuse a deploy key that has moved, naming where it lives now. */\nexport function assertNoMovedDeployKeys(deploy: unknown): void {\n\tconst dokploy = (deploy as { dokploy?: unknown } | undefined)?.dokploy;\n\tif (dokploy && typeof dokploy === 'object' && 'registry' in dokploy) {\n\t\tthrow new DokployRegistryMoved((dokploy as { registry: unknown }).registry);\n\t}\n\tif (deploy && typeof deploy === 'object') {\n\t\tif ('domains' in deploy) {\n\t\t\tthrow new DomainsMoved((deploy as { domains: unknown }).domains);\n\t\t}\n\t\tif ('dns' in deploy) throw new DnsMoved((deploy as { dns: unknown }).dns);\n\t}\n}\n\nexport function processConfig(\n\tconfig: GkmConfig | WorkspaceConfig,\n\tcwd: string,\n): LoadedConfig {\n\tassertNoMovedDeployKeys(config.deploy);\n\n\tif (isWorkspaceConfig(config)) {\n\t\tassertKnownSecretsStore(config.secrets?.store);\n\t\t// Every command needs the stages, so a config without them is refused\n\t\t// by the error that says so and shows the shape, not as one schema\n\t\t// issue among others.\n\t\tif (config.stages === undefined) {\n\t\t\tthrow new InvalidStages(stageProblems(undefined));\n\t\t}\n\t\t// Validate workspace config\n\t\tconst result = safeValidateWorkspaceConfig(config);\n\t\tif (!result.success && result.error) {\n\t\t\tthrow new InvalidWorkspaceConfig(formatValidationErrors(result.error));\n\t\t}\n\n\t\treturn {\n\t\t\ttype: 'workspace',\n\t\t\traw: config,\n\t\t\tworkspace: normalizeWorkspace(config, cwd),\n\t\t};\n\t}\n\n\t// Single-app config - wrap as workspace\n\treturn {\n\t\ttype: 'single',\n\t\traw: config,\n\t\tworkspace: wrapSingleAppAsWorkspace(config, cwd),\n\t};\n}\n\n/** A workspace config the schema refuses; the message lists every issue. */\nexport class InvalidWorkspaceConfig extends GkmError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'InvalidWorkspaceConfig';\n\t}\n}\n\n/**\n * The workspace's own constructs globs, absolute.\n *\n * Infrastructure two apps share is a fact about the product, and declaring it\n * inside one of them makes moving that app a change to the other's database.\n */\nexport function workspaceConstructGlobs(\n\tworkspace: NormalizedWorkspace,\n): string[] {\n\treturn constructPatterns(workspace.constructs).map((pattern) =>\n\t\tisAbsolute(pattern) ? pattern : join(workspace.root, pattern),\n\t);\n}\n\n/**\n * Every constructs glob an app can see, absolute.\n *\n * The workspace's own first, then the app's. Absolute because the app builds\n * from its own directory while the workspace's constructs live above it —\n * a relative glob resolved from the app would look for the product's\n * infrastructure inside one of its consumers and find nothing.\n *\n * Additive, not overriding: an app that declares its own constructs still sees\n * the ones the workspace declared for everybody.\n */\nexport function appConstructGlobs(\n\tworkspace: NormalizedWorkspace,\n\tappName: string,\n): string[] {\n\tconst globs: string[] = workspaceConstructGlobs(workspace);\n\n\tconst app = workspace.apps[appName];\n\tif (app) {\n\t\tconst root = isAbsolute(app.path)\n\t\t\t? app.path\n\t\t\t: join(workspace.root, app.path);\n\t\tfor (const pattern of constructPatterns(app.constructs)) {\n\t\t\tglobs.push(isAbsolute(pattern) ? pattern : join(root, pattern));\n\t\t}\n\t}\n\n\treturn globs;\n}\n/**\n * Every constructs glob in the workspace: its own, plus each app's.\n *\n * One list, so what a deploy provisions and what an app's entry point\n * registers drivers for are read off the same globs.\n */\nexport function allConstructGlobs(workspace: NormalizedWorkspace): string[] {\n\tconst globs = [\n\t\t...workspaceConstructGlobs(workspace),\n\t\t...Object.keys(workspace.apps).flatMap((appName) =>\n\t\t\tappConstructGlobs(workspace, appName),\n\t\t),\n\t];\n\n\t// Every app's list starts with the workspace's, so they repeat.\n\treturn [...new Set(globs)];\n}\n\n/** A `Routes` in any of its accepted shapes, as a flat list of patterns. */\nexport function constructPatterns(routes: Routes | undefined): string[] {\n\tif (!routes) return [];\n\treturn typeof routes === 'string' ? [routes] : routes;\n}\n\n/**\n * Get the GkmConfig for a specific app in a workspace.\n * Useful for running existing single-app commands on a specific app.\n */\nexport function getAppGkmConfig(\n\tworkspace: NormalizedWorkspace,\n\tappName: string,\n): GkmConfig | undefined {\n\tconst app = workspace.apps[appName];\n\tif (!app || app.type !== 'backend') {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\t// Workspace-level, and carried here deliberately. The deploy target is\n\t\t// what decides the backend a cache resolves to, which the *entry point*\n\t\t// reads when it decides which drivers to register — and the local target\n\t\t// reads from the workspace when it composes the URLs those drivers\n\t\t// receive. The two have to answer from the same target, or a project on\n\t\t// a server is handed a `postgres://` cache URL by an entry that\n\t\t// registered only the Upstash driver (`UnregisteredCacheScheme`).\n\t\t...(workspace.deploy ? { deploy: workspace.deploy } : {}),\n\t\tstages: workspace.stages,\n\t\t// One glob, every kind, and the root's covers every app's code as well\n\t\t// as the constructs. Which surface an endpoint belongs to is the\n\t\t// endpoint's to say, not its file's, so the build sorts them there.\n\t\tconstructs: appConstructGlobs(workspace, appName),\n\t\thooks: app.hooks,\n\t\ttelescope: app.telescope,\n\t\topenapi: app.openapi,\n\t\truntime: app.runtime,\n\t\tenv: app.env,\n\t};\n}\n\n/**\n * Get topologically sorted app names based on dependencies.\n * Apps with no dependencies come first, then apps that depend on them.\n */\nexport function getAppBuildOrder(workspace: NormalizedWorkspace): string[] {\n\tconst appNames = Object.keys(workspace.apps);\n\tconst visited = new Set<string>();\n\tconst result: string[] = [];\n\n\tfunction visit(name: string) {\n\t\tif (visited.has(name)) return;\n\t\tvisited.add(name);\n\n\t\tconst app = workspace.apps[name];\n\t\tif (app) {\n\t\t\tfor (const dep of app.dependencies) {\n\t\t\t\tvisit(dep);\n\t\t\t}\n\t\t}\n\n\t\tresult.push(name);\n\t}\n\n\tfor (const name of appNames) {\n\t\tvisit(name);\n\t}\n\n\treturn result;\n}\n\n/**\n * Resolve the Dokploy endpoint for a specific stage.\n *\n * Uses per-stage endpoint from `endpoints` if available,\n * otherwise falls back to the global `endpoint`.\n *\n * @param dokployConfig - Dokploy workspace configuration\n * @param stage - Deployment stage (e.g., 'development', 'production')\n * @returns The endpoint URL for the stage, or undefined if not configured\n *\n * @example\n * ```ts\n * // With per-stage endpoints\n * const config = {\n * endpoints: {\n * development: 'https://dev.dokploy.example.com:3000',\n * production: 'https://prod.dokploy.example.com:3000',\n * },\n * };\n * getEndpointForStage(config, 'production'); // => 'https://prod.dokploy.example.com:3000'\n *\n * // With single endpoint\n * const config = { endpoint: 'https://dokploy.example.com:3000' };\n * getEndpointForStage(config, 'production'); // => 'https://dokploy.example.com:3000'\n * ```\n */\nexport function getEndpointForStage(\n\tdokployConfig:\n\t\t| { endpoint?: string; endpoints?: Record<string, string> }\n\t\t| undefined,\n\tstage: string,\n): string | undefined {\n\tif (!dokployConfig) return undefined;\n\n\t// Check per-stage endpoint first\n\tif (dokployConfig.endpoints?.[stage]) {\n\t\treturn dokployConfig.endpoints[stage];\n\t}\n\n\t// Fall back to global endpoint\n\treturn dokployConfig.endpoint;\n}\n"],"mappings":"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"}
|