@geekmidas/cli 10.0.0-alpha.76 → 10.0.0-alpha.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{LegacyStateStore-dyq07_Ir.mjs → LegacyStateStore-Ceq7A_75.mjs} +2 -2
- package/dist/{LegacyStateStore-dyq07_Ir.mjs.map → LegacyStateStore-Ceq7A_75.mjs.map} +1 -1
- package/dist/{LegacyStateStore-DwngfJxr.cjs → LegacyStateStore-Z-EKUGSX.cjs} +2 -2
- package/dist/{LegacyStateStore-DwngfJxr.cjs.map → LegacyStateStore-Z-EKUGSX.cjs.map} +1 -1
- package/dist/{LocalStateStore-B0NCde8Z.cjs → LocalStateStore-Bocb8dmZ.cjs} +2 -2
- package/dist/{LocalStateStore-B0NCde8Z.cjs.map → LocalStateStore-Bocb8dmZ.cjs.map} +1 -1
- package/dist/{LocalStateStore-DLxCCatI.mjs → LocalStateStore-C72bwpG2.mjs} +2 -2
- package/dist/{LocalStateStore-DLxCCatI.mjs.map → LocalStateStore-C72bwpG2.mjs.map} +1 -1
- package/dist/{S3StateStore-BOenb-3o.cjs → S3StateStore-35YfcdL_.cjs} +2 -2
- package/dist/{S3StateStore-BOenb-3o.cjs.map → S3StateStore-35YfcdL_.cjs.map} +1 -1
- package/dist/{S3StateStore-CGK_4hlo.mjs → S3StateStore-C9upSW5o.mjs} +2 -2
- package/dist/{S3StateStore-CGK_4hlo.mjs.map → S3StateStore-C9upSW5o.mjs.map} +1 -1
- package/dist/{SSMStateStore-DYeD__7p.cjs → SSMStateStore-W-Ps22AQ.cjs} +2 -2
- package/dist/{SSMStateStore-DYeD__7p.cjs.map → SSMStateStore-W-Ps22AQ.cjs.map} +1 -1
- package/dist/{SSMStateStore-B_5_RqY-.mjs → SSMStateStore-dOmFO6g1.mjs} +2 -2
- package/dist/{SSMStateStore-B_5_RqY-.mjs.map → SSMStateStore-dOmFO6g1.mjs.map} +1 -1
- package/dist/{add-j2yI3cbS.cjs → add-BvOICikp.cjs} +8 -8
- package/dist/{add-j2yI3cbS.cjs.map → add-BvOICikp.cjs.map} +1 -1
- package/dist/{add-B7IMXzou.mjs → add-D2XKszYP.mjs} +3 -3
- package/dist/{add-B7IMXzou.mjs.map → add-D2XKszYP.mjs.map} +1 -1
- package/dist/{bundler-Cf6OgaOe.cjs → bundler-C6T-1OLT.cjs} +5 -5
- package/dist/{bundler-Cf6OgaOe.cjs.map → bundler-C6T-1OLT.cjs.map} +1 -1
- package/dist/{bundler-DO6bHhnb.mjs → bundler-CtHzKqnZ.mjs} +5 -5
- package/dist/{bundler-DO6bHhnb.mjs.map → bundler-CtHzKqnZ.mjs.map} +1 -1
- package/dist/{cli-BCPOHmg9.mjs → cli-BgPyhx1i.mjs} +3 -3
- package/dist/{cli-BCPOHmg9.mjs.map → cli-BgPyhx1i.mjs.map} +1 -1
- package/dist/{cli-CNanUB7a.cjs → cli-K6Vj_pPW.cjs} +4 -4
- package/dist/{cli-CNanUB7a.cjs.map → cli-K6Vj_pPW.cjs.map} +1 -1
- package/dist/{compose-h_6oNnHC.cjs → compose-B7MC19eC.cjs} +668 -110
- package/dist/compose-B7MC19eC.cjs.map +1 -0
- package/dist/{compose-Dq4VCtu5.mjs → compose-DByK353T.mjs} +606 -66
- package/dist/compose-DByK353T.mjs.map +1 -0
- package/dist/{config-CqAvPP-f.d.mts → config-Bql0AmJt.d.mts} +3 -3
- package/dist/{config-CWyhLSY1.d.cts.map → config-Bql0AmJt.d.mts.map} +1 -1
- package/dist/{config-CWyhLSY1.d.cts → config-DlNpHK8p.d.cts} +3 -3
- package/dist/{config-CqAvPP-f.d.mts.map → config-DlNpHK8p.d.cts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/deploy/public.cjs +12 -12
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-CVXEx7Nm.mjs → deploy-BerP7ppB.mjs} +5 -5
- package/dist/{deploy-CVXEx7Nm.mjs.map → deploy-BerP7ppB.mjs.map} +1 -1
- package/dist/{deploy-CT3R9de9.cjs → deploy-Dt42xiQA.cjs} +11 -11
- package/dist/{deploy-CT3R9de9.cjs.map → deploy-Dt42xiQA.cjs.map} +1 -1
- package/dist/{dokploy-eSGmlhhj.cjs → dokploy-NG9UrVrP.cjs} +2 -2
- package/dist/{dokploy-eSGmlhhj.cjs.map → dokploy-NG9UrVrP.cjs.map} +1 -1
- package/dist/{dokploy-CYm2ozFs.mjs → dokploy-ssZQRK2C.mjs} +2 -2
- package/dist/{dokploy-CYm2ozFs.mjs.map → dokploy-ssZQRK2C.mjs.map} +1 -1
- package/dist/{encryption-vS3Qzw73.cjs → encryption-CbMI24fI.cjs} +6 -6
- package/dist/{encryption-vS3Qzw73.cjs.map → encryption-CbMI24fI.cjs.map} +1 -1
- package/dist/{encryption-DC0rsR1W.mjs → encryption-De6MN0O5.mjs} +3 -3
- package/dist/{encryption-DC0rsR1W.mjs.map → encryption-De6MN0O5.mjs.map} +1 -1
- package/dist/{engine-C0N2d1i5.cjs → engine-CoCsNoW_.cjs} +73 -68
- package/dist/{engine-C0N2d1i5.cjs.map → engine-CoCsNoW_.cjs.map} +1 -1
- package/dist/{engine-BOO5TWZd.mjs → engine-DOjGIgl4.mjs} +9 -4
- package/dist/{engine-BOO5TWZd.mjs.map → engine-DOjGIgl4.mjs.map} +1 -1
- package/dist/{github-CEaFDL6t.mjs → github-CwX9z89E.mjs} +3 -3
- package/dist/{github-CEaFDL6t.mjs.map → github-CwX9z89E.mjs.map} +1 -1
- package/dist/{github-ClkdCOL9.cjs → github-D9vGqdLk.cjs} +7 -7
- package/dist/{github-ClkdCOL9.cjs.map → github-D9vGqdLk.cjs.map} +1 -1
- package/dist/{index-DOxmDKqv.d.mts → index-BXO0vlme.d.mts} +2 -2
- package/dist/{index-Ccu0f_2m.d.cts.map → index-BXO0vlme.d.mts.map} +1 -1
- package/dist/{index-Ccu0f_2m.d.cts → index-Rs0Fua-q.d.cts} +2 -2
- package/dist/{index-DOxmDKqv.d.mts.map → index-Rs0Fua-q.d.cts.map} +1 -1
- package/dist/index.cjs +180 -219
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +108 -147
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-BRbYtFXG.cjs → migrate-B4GBvCNY.cjs} +5 -5
- package/dist/{migrate-BRbYtFXG.cjs.map → migrate-B4GBvCNY.cjs.map} +1 -1
- package/dist/{migrate-D3NAT7Ns.mjs → migrate-BQ4wVKq_.mjs} +3 -3
- package/dist/{migrate-D3NAT7Ns.mjs.map → migrate-BQ4wVKq_.mjs.map} +1 -1
- package/dist/{migrate-DrO2p9Rl.mjs → migrate-CNKaQl3K.mjs} +3 -3
- package/dist/{migrate-DrO2p9Rl.mjs.map → migrate-CNKaQl3K.mjs.map} +1 -1
- package/dist/{migrate-D5_-ylI1.cjs → migrate-Cgoy58Sh.cjs} +8 -8
- package/dist/{migrate-D5_-ylI1.cjs.map → migrate-Cgoy58Sh.cjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-Fa1Ii0BK.cjs → resolve-CEaqRBzY.cjs} +3 -3
- package/dist/{resolve-Fa1Ii0BK.cjs.map → resolve-CEaqRBzY.cjs.map} +1 -1
- package/dist/{resolve-C1muFos5.mjs → resolve-mvaystiE.mjs} +3 -3
- package/dist/{resolve-C1muFos5.mjs.map → resolve-mvaystiE.mjs.map} +1 -1
- package/dist/{rollback-C9N5lKVf.cjs → rollback-F3P-rA-r.cjs} +7 -7
- package/dist/{rollback-C9N5lKVf.cjs.map → rollback-F3P-rA-r.cjs.map} +1 -1
- package/dist/{rollback-DeQzbRqM.mjs → rollback-S2C-Y9pB.mjs} +5 -5
- package/dist/{rollback-DeQzbRqM.mjs.map → rollback-S2C-Y9pB.mjs.map} +1 -1
- package/dist/{runtime-Cm7QA53H.d.cts → runtime-D9AxGzrw.d.cts} +2 -2
- package/dist/{runtime-BSvzPqXW.d.mts.map → runtime-D9AxGzrw.d.cts.map} +1 -1
- package/dist/{runtime-BSvzPqXW.d.mts → runtime-Dflki3Vs.d.mts} +2 -2
- package/dist/{runtime-Cm7QA53H.d.cts.map → runtime-Dflki3Vs.d.mts.map} +1 -1
- package/dist/{sniffer-Y6GQOCXB.cjs → sniffer-BjG-1mlD.cjs} +6 -6
- package/dist/{sniffer-Y6GQOCXB.cjs.map → sniffer-BjG-1mlD.cjs.map} +1 -1
- package/dist/{sniffer-DR8AlRCk.mjs → sniffer-ByWtH28i.mjs} +6 -6
- package/dist/{sniffer-DR8AlRCk.mjs.map → sniffer-ByWtH28i.mjs.map} +1 -1
- package/dist/{state-C2qi0iQw.cjs → stale-BsiPJI7Y.cjs} +111 -25
- package/dist/stale-BsiPJI7Y.cjs.map +1 -0
- package/dist/{state-CUecOCNJ.mjs → stale-C5FqIVc8.mjs} +106 -26
- package/dist/stale-C5FqIVc8.mjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-BdptGBFS.d.cts → types-ByY0zi3n.d.cts} +42 -3
- package/dist/types-ByY0zi3n.d.cts.map +1 -0
- package/dist/{types-OxE0OAn2.d.mts → types-DKxkXsKC.d.mts} +42 -3
- package/dist/types-DKxkXsKC.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-QUTqYmVy.mjs → workspace-BBdqmkch.mjs} +114 -17
- package/dist/workspace-BBdqmkch.mjs.map +1 -0
- package/dist/{workspace-DOm81oUo.cjs → workspace-Bp8FEkF-.cjs} +130 -15
- package/dist/workspace-Bp8FEkF-.cjs.map +1 -0
- package/package.json +15 -15
- package/dist/compose-Dq4VCtu5.mjs.map +0 -1
- package/dist/compose-h_6oNnHC.cjs.map +0 -1
- package/dist/state-C2qi0iQw.cjs.map +0 -1
- package/dist/state-CUecOCNJ.mjs.map +0 -1
- package/dist/types-BdptGBFS.d.cts.map +0 -1
- package/dist/types-OxE0OAn2.d.mts.map +0 -1
- package/dist/workspace-DOm81oUo.cjs.map +0 -1
- package/dist/workspace-QUTqYmVy.mjs.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["logger","ask","logger","createServer","Readable","Http2ServerRequest2","createServerHTTP","logger","logger","logger","deploy","logger","require","detectPackageManager","logger","logger","backendsOf","parse","detectPackageManager","pkg.version"],"sources":["../package.json","../src/prompt.ts","../src/auth/index.ts","../src/trust/index.ts","../src/dev/discovery.ts","../../../node_modules/.pnpm/@hono+node-server@1.19.5_hono@4.13.8/node_modules/@hono/node-server/dist/index.mjs","../src/dev/fakes.ts","../src/exec/index.ts","../src/dev/index.ts","../src/generators/FunctionGenerator.ts","../src/generators/TopicGenerator.ts","../src/build/types.ts","../src/build/owners.ts","../src/build/surfaceEntry.ts","../src/build/index.ts","../src/compose/index.ts","../src/debug.ts","../src/deploy/init.ts","../src/deploy/state-commands.ts","../src/secrets/generator.ts","../src/migrate/names.ts","../src/init/constructs.ts","../src/init/generators/agents.ts","../src/init/dependencies.ts","../src/init/versions.ts","../src/init/generators/auth.ts","../src/init/generators/stages.ts","../src/init/generators/config.ts","../src/init/generators/env.ts","../src/init/generators/github.ts","../src/init/generators/mobile-expo.ts","../src/init/generators/models.ts","../src/init/generators/deploy.ts","../src/init/generators/monorepo.ts","../src/init/generators/package.ts","../src/init/generators/source.ts","../src/init/generators/test.ts","../src/init/generators/shadcn.ts","../src/init/generators/web.ts","../src/init/generators/web-tanstack.ts","../src/init/templates/api.ts","../src/init/templates/minimal.ts","../src/init/templates/serverless.ts","../src/init/templates/worker.ts","../src/init/templates/index.ts","../src/init/index.ts","../src/setup/fullstack-secrets.ts","../src/secrets/index.ts","../src/setup/index.ts","../src/test/teardown.ts","../src/test/index.ts","../src/upgrade/version.ts","../src/upgrade/index.ts","../src/index.ts"],"sourcesContent":["","/**\n * Asking the person at the terminal.\n *\n * CLI layer only: a command's action may prompt, nothing it calls may. A\n * library call (`deploy()`) that needs something it was not given raises a\n * named error instead, and the command decides whether to ask.\n */\n\nimport { stdin as input, stdout as output } from 'node:process';\nimport * as readline from 'node:readline/promises';\n\n/** A prompt was needed with no terminal to ask at. */\nexport class PromptNeedsTerminal extends Error {\n\tconstructor(\n\t\treadonly question: string,\n\t\t/** What to do instead — the flag or variable that answers it. */\n\t\treadonly instead: string,\n\t) {\n\t\tsuper(`Interactive input required. ${instead}`);\n\t\tthis.name = 'PromptNeedsTerminal';\n\t}\n}\n\n/** Whether there is a person at a terminal to ask. */\nexport function canPrompt(): boolean {\n\treturn process.stdin.isTTY === true;\n}\n\n/**\n * Ask `message` and resolve with the line typed — without echoing it when\n * `hidden`. Ctrl+C at a hidden prompt exits, as it would anywhere else in a\n * terminal program: raw mode has taken the signal away from the shell.\n */\nexport async function prompt(\n\tmessage: string,\n\toptions: { hidden?: boolean; instead: string },\n): Promise<string> {\n\tif (!canPrompt()) {\n\t\tthrow new PromptNeedsTerminal(message, options.instead);\n\t}\n\n\tif (options.hidden) {\n\t\t// For hidden input, use raw mode directly without readline\n\t\tprocess.stdout.write(message);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet value = '';\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\tprocess.stdin.pause();\n\t\t\t\tprocess.stdin.removeListener('data', onData);\n\t\t\t\tprocess.stdin.removeListener('error', onError);\n\t\t\t};\n\n\t\t\tconst onError = (err: Error) => {\n\t\t\t\tcleanup();\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tconst onData = (char: Buffer) => {\n\t\t\t\tconst c = char.toString();\n\n\t\t\t\tif (c === '\\n' || c === '\\r') {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tresolve(value);\n\t\t\t\t} else if (c === '\\u0003') {\n\t\t\t\t\t// Ctrl+C\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t} else if (c === '\\u007F' || c === '\\b') {\n\t\t\t\t\t// Backspace\n\t\t\t\t\tif (value.length > 0) {\n\t\t\t\t\t\tvalue = value.slice(0, -1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue += c;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t\tprocess.stdin.resume();\n\t\t\tprocess.stdin.on('data', onData);\n\t\t\tprocess.stdin.on('error', onError);\n\t\t});\n\t}\n\n\t// For visible input, use readline\n\tconst rl = readline.createInterface({ input, output });\n\ttry {\n\t\treturn await rl.question(message);\n\t} finally {\n\t\trl.close();\n\t}\n}\n","import { prompt as ask } from '../prompt';\nimport {\n\tgetCredentialsPath,\n\tgetDokployCredentials,\n\tremoveDokployCredentials,\n\tstoreDokployCredentials,\n\tstoreHostingerToken,\n} from './credentials';\n\nconst logger = console;\n\nexport interface LoginOptions {\n\t/** Which provider's credentials to store — the same word `gkm deploy` uses. */\n\tprovider: 'dokploy' | 'hostinger';\n\t/** API token (if not provided, will prompt) */\n\ttoken?: string;\n\t/** Endpoint URL */\n\tendpoint?: string;\n}\n\nexport interface LogoutOptions {\n\t/** Whose credentials to remove — `all` clears every stored provider. */\n\tprovider?: 'dokploy' | 'all';\n}\n\n/**\n * Validate Dokploy token by making a test API call\n */\nexport async function validateDokployToken(\n\tendpoint: string,\n\ttoken: string,\n): Promise<boolean> {\n\tconst { DokployApi } = await import('../target/dokploy/dokploy-api');\n\tconst api = new DokployApi({ baseUrl: endpoint, token });\n\treturn api.validateToken();\n}\n\n/** What answers a login prompt without a terminal. */\nconst LOGIN_INSTEAD = 'Please provide --token option.';\n\n/**\n * Login to a service\n */\nexport async function loginCommand(options: LoginOptions): Promise<void> {\n\tconst {\n\t\tprovider,\n\t\ttoken: providedToken,\n\t\tendpoint: providedEndpoint,\n\t} = options;\n\n\tif (provider === 'dokploy') {\n\t\tlogger.log('\\n🔐 Logging in to Dokploy...\\n');\n\n\t\t// Get endpoint\n\t\tlet endpoint = providedEndpoint;\n\t\tif (!endpoint) {\n\t\t\tendpoint = await ask(\n\t\t\t\t'Dokploy URL (e.g., https://dokploy.example.com): ',\n\t\t\t\t{\n\t\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Normalize endpoint (remove trailing slash)\n\t\tendpoint = endpoint.replace(/\\/$/, '');\n\n\t\t// Validate endpoint format\n\t\ttry {\n\t\t\tnew URL(endpoint);\n\t\t} catch {\n\t\t\tlogger.error('Invalid URL format');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Get token\n\t\tlet token = providedToken;\n\t\tif (!token) {\n\t\t\tlogger.log(`\\nGenerate a token at: ${endpoint}/settings/profile\\n`);\n\t\t\ttoken = await ask('API Token: ', {\n\t\t\t\thidden: true,\n\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t});\n\t\t}\n\n\t\tif (!token) {\n\t\t\tlogger.error('Token is required');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Validate token\n\t\tlogger.log('\\nValidating credentials...');\n\t\tconst isValid = await validateDokployToken(endpoint, token);\n\n\t\tif (!isValid) {\n\t\t\tlogger.error(\n\t\t\t\t'\\n✗ Invalid credentials. Please check your token and try again.',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Store credentials\n\t\tawait storeDokployCredentials(token, endpoint);\n\n\t\tlogger.log('\\n✓ Successfully logged in to Dokploy!');\n\t\tlogger.log(` Endpoint: ${endpoint}`);\n\t\tlogger.log(` Credentials stored in: ${getCredentialsPath()}`);\n\t\tlogger.log(\n\t\t\t'\\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\n\tif (provider === 'hostinger') {\n\t\t// The DNS provider has told people to run this since it was written, and\n\t\t// this branch did not exist — so the only way to supply the token was the\n\t\t// environment variable, which the message does not mention.\n\t\tlogger.log('\\n🔐 Logging in to Hostinger...\\n');\n\n\t\tlet token = providedToken;\n\t\tif (!token) {\n\t\t\tlogger.log(\n\t\t\t\t'\\nGenerate a token at: https://hpanel.hostinger.com/profile/api\\n',\n\t\t\t);\n\t\t\ttoken = await ask('API Token: ', {\n\t\t\t\thidden: true,\n\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t});\n\t\t}\n\n\t\tif (!token) {\n\t\t\tlogger.error('Token is required');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Stored without validating, and that is worth saying rather than hiding.\n\t\t// Hostinger's DNS API is zone-scoped — every endpoint takes a domain — so\n\t\t// there is nothing to call that means \"is this token good\" without\n\t\t// already knowing a domain this account owns. A check against a guessed\n\t\t// one would fail for two different reasons and report one.\n\t\tawait storeHostingerToken(token);\n\n\t\tlogger.log('\\n✓ Hostinger token stored.');\n\t\tlogger.log(` Credentials stored in: ${getCredentialsPath()}`);\n\t\tlogger.log(\n\t\t\t' Not validated here: every DNS endpoint is scoped to a domain, so the\\n' +\n\t\t\t\t' first deploy that touches DNS is where a bad token reports itself.',\n\t\t);\n\t\tlogger.log(\n\t\t\t'\\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.',\n\t\t);\n\t}\n}\n\n/**\n * Logout from a service\n */\nexport async function logoutCommand(options: LogoutOptions): Promise<void> {\n\tconst { provider = 'dokploy' } = options;\n\n\tif (provider === 'all') {\n\t\tconst dokployRemoved = await removeDokployCredentials();\n\n\t\tif (dokployRemoved) {\n\t\t\tlogger.log('\\n✓ Logged out from all services');\n\t\t} else {\n\t\t\tlogger.log('\\nNo stored credentials found');\n\t\t}\n\t\treturn;\n\t}\n\n\tif (provider === 'dokploy') {\n\t\tconst removed = await removeDokployCredentials();\n\n\t\tif (removed) {\n\t\t\tlogger.log('\\n✓ Logged out from Dokploy');\n\t\t} else {\n\t\t\tlogger.log('\\nNo Dokploy credentials found');\n\t\t}\n\t}\n}\n\n/**\n * Show current login status\n */\nexport async function whoamiCommand(): Promise<void> {\n\tlogger.log('\\n📋 Current credentials:\\n');\n\n\tconst dokploy = await getDokployCredentials();\n\n\tif (dokploy) {\n\t\tlogger.log(' Dokploy:');\n\t\tlogger.log(` Endpoint: ${dokploy.endpoint}`);\n\t\tlogger.log(` Token: ${maskToken(dokploy.token)}`);\n\t} else {\n\t\tlogger.log(' Dokploy: Not logged in');\n\t}\n\n\tlogger.log(`\\n Credentials file: ${getCredentialsPath()}`);\n}\n\n/**\n * Mask a token for display\n */\nexport function maskToken(token: string): string {\n\tif (token.length <= 8) {\n\t\treturn '****';\n\t}\n\treturn `${token.slice(0, 4)}...${token.slice(-4)}`;\n}\n\n// Re-export credentials utilities for use in other modules\nexport {\n\tgetDokployCredentials,\n\tgetDokployEndpoint,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployCredentials,\n\tstoreDokployRegistryId,\n} from './credentials';\n","/**\n * Installing the local edge's certificate authority into the OS trust store.\n *\n * `NODE_EXTRA_CA_CERTS` covers everything gkm starts — the dev server, the test\n * suite, anything under `gkm exec` — because reconcile injects it. A browser\n * reads none of that: it asks the operating system, so until the root is in the\n * system store a local `https://` address is \"not secure\", which is true and\n * unhelpful.\n *\n * A separate command rather than part of `gkm setup`, for one reason: this\n * asks for a password, and a setup that silently escalates on every run is a\n * worse trade than one that tells you what to type. Caddy's own `caddy trust`\n * draws the line in the same place.\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport prompts from 'prompts';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { LOCAL_CA_PATH } from '../reconcile/index.js';\n\nconst logger = console;\n\nconst run = promisify(execFile);\n\nexport interface TrustOptions {\n\t/** Print the commands rather than running them. */\n\tdryRun?: boolean;\n}\n\n/**\n * How each platform is told about a new authority.\n *\n * Separate rather than shelled through one script because the failure modes\n * differ and the message should name the real one: macOS refuses without an\n * admin password, Debian needs the file in a specific directory before its\n * updater will look at it.\n */\nfunction installation(\n\tplatform: NodeJS.Platform,\n\tcertificate: string,\n): { describe: string; asks: string; steps: [string, string[]][] } {\n\tif (platform === 'darwin') {\n\t\t// The login keychain, trusted for this user, and no sudo. The System\n\t\t// keychain needs both: sudo to write the file, then macOS's own\n\t\t// authorization to change trust settings, which sudo does not cover — so\n\t\t// it asked for the password twice. A local CA is one developer's\n\t\t// business anyway, and browsers and Node's system store honour a\n\t\t// user's trust settings.\n\t\treturn {\n\t\t\tdescribe: 'your login keychain',\n\t\t\tasks: 'macOS asks once — your password or Touch ID — to change trust settings.',\n\t\t\tsteps: [\n\t\t\t\t[\n\t\t\t\t\t'security',\n\t\t\t\t\t[\n\t\t\t\t\t\t'add-trusted-cert',\n\t\t\t\t\t\t'-r',\n\t\t\t\t\t\t'trustRoot',\n\t\t\t\t\t\t'-k',\n\t\t\t\t\t\tjoin(homedir(), 'Library/Keychains/login.keychain-db'),\n\t\t\t\t\t\tcertificate,\n\t\t\t\t\t],\n\t\t\t\t],\n\t\t\t],\n\t\t};\n\t}\n\n\tif (platform === 'linux') {\n\t\t// Debian and Fedora keep anchors in different places and run different\n\t\t// updaters. Whichever directory exists is the one this system uses.\n\t\tconst debian = existsSync('/usr/local/share/ca-certificates');\n\n\t\treturn {\n\t\t\tdescribe: debian ? 'the system CA bundle' : 'the system trust anchors',\n\t\t\tasks: 'This needs sudo: the system trust store is the only one.',\n\t\t\tsteps: debian\n\t\t\t\t? [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t'sudo',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'cp',\n\t\t\t\t\t\t\t\tcertificate,\n\t\t\t\t\t\t\t\t'/usr/local/share/ca-certificates/gkm-local-ca.crt',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t],\n\t\t\t\t\t\t['sudo', ['update-ca-certificates']],\n\t\t\t\t\t]\n\t\t\t\t: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t'sudo',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'cp',\n\t\t\t\t\t\t\t\tcertificate,\n\t\t\t\t\t\t\t\t'/etc/pki/ca-trust/source/anchors/gkm-local-ca.crt',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t],\n\t\t\t\t\t\t['sudo', ['update-ca-trust']],\n\t\t\t\t\t],\n\t\t};\n\t}\n\n\tthrow new UnsupportedPlatform(platform, certificate);\n}\n\n/**\n * Trust the certificate authority this project's edge issues from.\n *\n * Idempotent in effect: installing a root that is already trusted replaces the\n * same entry, so running it twice is not an error.\n */\nexport async function trustCommand(options: TrustOptions = {}): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst certificate = join(workspace.root, LOCAL_CA_PATH);\n\n\tif (!existsSync(certificate)) {\n\t\tthrow new NoLocalAuthority(certificate);\n\t}\n\n\tconst { describe, asks, steps } = installation(process.platform, certificate);\n\n\tlogger.log(`\\n🔐 Trusting the local authority in ${describe}`);\n\tlogger.log(` ${certificate}\\n`);\n\n\tif (options.dryRun) {\n\t\tfor (const [command, args] of steps) {\n\t\t\tlogger.log(` ${command} ${args.join(' ')}`);\n\t\t}\n\t\treturn;\n\t}\n\n\tlogger.log(` ${asks}\\n`);\n\n\tfor (const [command, args] of steps) {\n\t\t// Inherited stdio, because sudo prompts on the terminal and a captured\n\t\t// prompt is a command that appears to hang.\n\t\tawait run(command, args, { stdio: 'inherit' } as never);\n\t}\n\n\tlogger.log('\\n✅ Local https addresses are trusted. Restart your browser.\\n');\n}\n\n/**\n * Trust the authority if this machine lacks it and its owner agrees.\n *\n * A machine's answer, not the project's: whether a laptop installs a root\n * certificate is its owner's call, so the decision is `--yes`, then what this\n * machine previously answered, then a prompt. Never a silent escalation — that is\n * the one thing a setup command should not do on somebody's behalf.\n *\n * Silent and free when the machine already trusts it, which is what makes it\n * acceptable to call on every `gkm setup`.\n */\nexport async function ensureTrusted(\n\troot: string,\n\turl: string,\n\toptions: { assumeYes?: boolean } = {},\n): Promise<void> {\n\tif (await isTrusted(url)) return;\n\n\tif (!options.assumeYes) {\n\t\t// Nothing to answer a prompt in CI, a hook, or a piped shell — and a\n\t\t// setup that stops there waiting is worse than one that leaves the\n\t\t// authority untrusted. Not recorded as declined, because nobody\n\t\t// declined: the next interactive run should still ask.\n\t\tif (!process.stdin.isTTY) {\n\t\t\tlogger.log(\n\t\t\t\t' Local https addresses are not trusted here. Run \"gkm trust\", ' +\n\t\t\t\t\t'or \"gkm setup --yes\".',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// A recorded \"no\" is why this asks once rather than every start. There is\n\t\t// no recorded \"yes\": trusting is checked directly above, so a yes that\n\t\t// worked answers itself and a yes that did not should ask again.\n\t\tif (await declined(root)) return;\n\n\t\tconst { install } = await prompts({\n\t\t\ttype: 'confirm',\n\t\t\tname: 'install',\n\t\t\tmessage:\n\t\t\t\t\"Trust this project's local certificate authority, so a browser \" +\n\t\t\t\t'accepts its https addresses? (asks for your password)',\n\t\t\tinitial: false,\n\t\t});\n\n\t\tif (!install) {\n\t\t\tawait recordDeclined(root);\n\t\t\tlogger.log(' Skipped. Run \"gkm trust\" later.');\n\t\t\treturn;\n\t\t}\n\t}\n\n\tawait trustCommand();\n}\n\n/** Where a declined answer is remembered, so setup asks once and not again. */\nconst TRUST_STATE = '.gkm/trust.json';\n\nasync function declined(root: string): Promise<boolean> {\n\ttry {\n\t\tconst raw = await readFile(join(root, TRUST_STATE), 'utf-8');\n\n\t\treturn (JSON.parse(raw) as { declined?: boolean }).declined === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function recordDeclined(root: string): Promise<void> {\n\tconst path = join(root, TRUST_STATE);\n\n\tawait mkdir(dirname(path), { recursive: true });\n\tawait writeFile(path, `${JSON.stringify({ declined: true }, null, 2)}\\n`);\n}\n\n/**\n * Whether this machine already trusts the local authority.\n *\n * Asked by connecting rather than by reading a keychain: what matters is\n * whether a client with no special configuration verifies the edge, and that is\n * one platform-neutral question instead of three platform-specific ones. It is\n * also the exact thing a browser is about to do.\n *\n * A child process, because `NODE_EXTRA_CA_CERTS` is read once at startup and\n * this process almost certainly has it set — asking in-process would answer\n * \"yes\" for everyone.\n */\nexport async function isTrusted(url: string): Promise<boolean> {\n\tconst { NODE_EXTRA_CA_CERTS: _ignored, ...env } = process.env;\n\n\ttry {\n\t\tawait run(\n\t\t\tprocess.execPath,\n\t\t\t[\n\t\t\t\t// The operating system's store — where `gkm trust` installs the root,\n\t\t\t\t// and what a browser reads. Without it Node checks only its own\n\t\t\t\t// bundled authorities, so an installed root still read as untrusted\n\t\t\t\t// and every run asked again.\n\t\t\t\t'--use-system-ca',\n\t\t\t\t'-e',\n\t\t\t\t`fetch(${JSON.stringify(url)}).then(()=>0,()=>process.exit(1))`,\n\t\t\t],\n\t\t\t{ env, timeout: 15_000 },\n\t\t);\n\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Copy the root somewhere a tool that wants a file can read it.\n *\n * For anything that takes a CA bundle rather than reading the system store —\n * another language's HTTP client, a container, a CI job.\n */\nexport async function exportLocalAuthority(to: string): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst certificate = join(workspace.root, LOCAL_CA_PATH);\n\n\tif (!existsSync(certificate)) throw new NoLocalAuthority(certificate);\n\n\tawait copyFile(certificate, to);\n}\n\n/** The edge has not run, so there is no authority to trust yet. */\nexport class NoLocalAuthority extends Error {\n\tconstructor(readonly path: string) {\n\t\tsuper(\n\t\t\t`No local certificate authority at ${path}. It is generated the first ` +\n\t\t\t\t`time the edge starts, so run \"gkm setup\" (or \"gkm dev\") once — and ` +\n\t\t\t\t`if this project declares no file server, nothing needs one.`,\n\t\t);\n\t\tthis.name = 'NoLocalAuthority';\n\t}\n}\n\n/** A platform with no trust store this knows how to write to. */\nexport class UnsupportedPlatform extends Error {\n\tconstructor(\n\t\treadonly platform: string,\n\t\treadonly certificate: string,\n\t) {\n\t\tsuper(\n\t\t\t`gkm does not know how to install a certificate authority on ` +\n\t\t\t\t`${platform}. The root is at ${certificate} — add it to the trust ` +\n\t\t\t\t`store by hand, or point a client at it with NODE_EXTRA_CA_CERTS.`,\n\t\t);\n\t\tthis.name = 'UnsupportedPlatform';\n\t}\n}\n","/**\n * How a tool finds what `gkm dev` is running on this machine.\n *\n * Every app already serves its data as JSON — Telescope's requests, logs and\n * exceptions, the declared database at `/__gkm/db`, the OpenAPI document — but\n * each on its own port, and nothing said which ports those were. A console had\n * to be told. So `gkm dev` serves one more thing, on one well-known loopback\n * port: `GET /__gkm` lists the running workspaces, their apps and the data APIs\n * each app exposes, `GET /__gkm/events` streams the changes, and\n * `/__gkm/workspaces/<id>/apps/<app>/…` forwards to an app's data APIs, so a\n * client talks to one origin.\n *\n * **Many sessions, one endpoint.** A developer runs several `gkm dev`s at once\n * — a workspace's own, the one per app turbo starts under it, another\n * project's. Each writes what it runs to a registry directory shared by the\n * machine (`~/.gkm/dev/sessions/<id>.json`) and removes it when it stops. The\n * endpoint is served by whichever of them bound the port first, and it reads\n * the registry rather than being told — so nothing has to be handed over when\n * that process exits. Every other session keeps trying to bind the port, and\n * the first to manage it after the host is gone is the new host. A session that\n * died without cleaning up is recognised by its pid and pruned.\n *\n * **Security.** Any web page the developer visits can send requests to a\n * loopback port, so nothing here trusts being on loopback:\n * - it binds `127.0.0.1` only;\n * - the `Host` header must be `127.0.0.1` or `localhost` with this port, which\n * defeats DNS rebinding (an attacker's hostname resolving to 127.0.0.1);\n * - a browser's `Origin` must be in a workspace's `dev.allowedOrigins`, empty\n * by default; CORS replies only to those, and a workspace is only visible to\n * the origins it listed;\n * - every request carries the session token (`Authorization: Bearer …` or\n * `?token=…`, since `EventSource` cannot set headers), which `gkm dev` prints\n * in a connect URL the way Jupyter does;\n * - it is read-only: `GET` and `HEAD`, and the forwarder reaches an app's data\n * APIs and nothing else of it.\n */\n\nimport { createHash, randomBytes, timingSafeEqual } from 'node:crypto';\nimport {\n\tlinkSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from 'node:fs';\nimport {\n\tcreateServer,\n\ttype IncomingMessage,\n\ttype Server,\n\ttype ServerResponse,\n} from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { connect } from 'node:net';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport type { DevConfig } from '../workspace/types.js';\n\n/** Where the endpoint listens unless configured otherwise. */\nexport const DEFAULT_DISCOVERY_PORT = 4983;\n\n/** Overrides `dev.discoveryPort` — `0` serves on a port of its own. */\nexport const DISCOVERY_PORT_ENV = 'GKM_DISCOVERY_PORT';\n\n/** Overrides where the sessions register — `~/.gkm/dev` by default. */\nexport const DISCOVERY_REGISTRY_ENV = 'GKM_DEV_REGISTRY';\n\n/**\n * Set by a workspace's `gkm dev` for the app sessions turbo starts under it:\n * the workspace has printed the connect URL, so they do not repeat it.\n */\nexport const DISCOVERY_QUIET_ENV = 'GKM_DISCOVERY_QUIET';\n\n/** The route everything is served under. */\nconst BASE = '/__gkm';\n\n// ---------------------------------------------------------------------------\n// What a session registers\n// ---------------------------------------------------------------------------\n\n/** Where an app is in its life. `stopped` is a server that exited on its own. */\nexport type AppStatus = 'starting' | 'ready' | 'reloading' | 'stopped';\n\n/** A JSON API an app serves about itself. */\nexport type DataApiKind = 'telescope' | 'database' | 'openapi';\n\nexport interface SessionDataApi {\n\tkind: DataApiKind;\n\t/** Where the app serves it, e.g. `/__gkm/db`. */\n\tpath: string;\n}\n\nexport interface SessionApp {\n\tname: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tport: number;\n\t/** Its address behind the edge, when it has one. */\n\tpublicUrl?: string;\n\tstatus: AppStatus;\n\t/** How many times it has been rebuilt and restarted since it started. */\n\treloads: number;\n\tdataApis: SessionDataApi[];\n}\n\n/**\n * One `gkm dev` process, as it registers itself.\n *\n * A `workspace` session is the workspace's own `gkm dev`: it lists every app\n * turbo starts, but runs none of them itself. An `app` session runs one app's\n * server, and knows its status and data APIs — so where both describe an app,\n * the `app` session's word is taken.\n */\nexport interface DevSessionRecord {\n\tid: string;\n\tpid: number;\n\trole: 'workspace' | 'app';\n\tstartedAt: string;\n\tupdatedAt: string;\n\tworkspace: { name: string; root: string; stage: string };\n\t/** `dev.allowedOrigins`: the browser origins this workspace is shown to. */\n\tallowedOrigins: string[];\n\tmanifest?: ConstructManifest;\n\tapps: SessionApp[];\n}\n\n// ---------------------------------------------------------------------------\n// What `GET /__gkm` answers\n// ---------------------------------------------------------------------------\n\nexport interface DiscoveredDataApi {\n\tkind: DataApiKind;\n\t/** Where the app serves it. */\n\tpath: string;\n\t/** The app's own address for it — `http://localhost:<port><path>`. */\n\turl: string;\n\t/** The same API through this endpoint, relative to its origin. */\n\tproxy: string;\n}\n\nexport interface DiscoveredApp {\n\tname: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tport: number;\n\t/** `http://localhost:<port>`. */\n\turl: string;\n\tpublicUrl: string | null;\n\tstatus: AppStatus;\n\treloads: number;\n\t/** The `gkm dev` running it, when it runs in one of its own. */\n\tpid: number | null;\n\tdataApis: DiscoveredDataApi[];\n}\n\nexport interface DiscoveredWorkspace {\n\t/** Stable for a workspace's root: its name, and a hash of where it is. */\n\tid: string;\n\tname: string;\n\troot: string;\n\tstage: string;\n\tmanifest: ConstructManifest | null;\n\tapps: DiscoveredApp[];\n}\n\n/** The body of `GET /__gkm`. */\nexport interface DiscoveryResponse {\n\tversion: 1;\n\t/** The `gkm dev` serving this endpoint, which may change while you watch. */\n\thost: { pid: number; port: number };\n\t/** Where the changes stream, as server-sent events. */\n\tevents: string;\n\tworkspaces: DiscoveredWorkspace[];\n}\n\n/** One message on `GET /__gkm/events`; its SSE `event:` is its `type`. */\nexport type DiscoveryEvent =\n\t| { type: 'snapshot'; snapshot: DiscoveryResponse }\n\t| { type: 'workspace.started' | 'workspace.stopped'; workspace: string }\n\t| {\n\t\t\ttype: 'app.started' | 'app.stopped' | 'app.reloaded' | 'app.status';\n\t\t\tworkspace: string;\n\t\t\tapp: DiscoveredApp;\n\t };\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/** `GKM_DISCOVERY_PORT` is set to something that is not a port. */\nexport class InvalidDiscoveryPort extends Error {\n\tconstructor(readonly value: string) {\n\t\tsuper(\n\t\t\t`${DISCOVERY_PORT_ENV}=${value} is not a port. Set it to a number from 0 ` +\n\t\t\t\t'to 65535 (0 serves discovery on a free port of its own), or unset ' +\n\t\t\t\t'it to use dev.discoveryPort.',\n\t\t);\n\t\tthis.name = 'InvalidDiscoveryPort';\n\t}\n}\n\n/** The port the endpoint uses: the env, then `dev.discoveryPort`, then 4983. */\nexport function discoveryPort(\n\tconfig: DevConfig | undefined,\n\tenv: NodeJS.ProcessEnv = process.env,\n): number {\n\tconst raw = env[DISCOVERY_PORT_ENV];\n\tif (raw !== undefined && raw !== '') {\n\t\tconst port = Number(raw);\n\t\tif (!Number.isInteger(port) || port < 0 || port > 65535) {\n\t\t\tthrow new InvalidDiscoveryPort(raw);\n\t\t}\n\t\treturn port;\n\t}\n\treturn config?.discoveryPort ?? DEFAULT_DISCOVERY_PORT;\n}\n\n/** The machine's registry, shared by every `gkm dev`. */\nexport function discoveryRegistry(env: NodeJS.ProcessEnv = process.env) {\n\treturn env[DISCOVERY_REGISTRY_ENV] || join(homedir(), '.gkm', 'dev');\n}\n\n// ---------------------------------------------------------------------------\n// The registry\n// ---------------------------------------------------------------------------\n\nfunction sessionsDir(registry: string): string {\n\treturn join(registry, 'sessions');\n}\n\n/** Whether a process is alive. `EPERM` is someone else's — alive. */\nfunction alive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === 'EPERM';\n\t}\n}\n\n/**\n * Every live session, pruning the ones whose process is gone — a `gkm dev`\n * killed outright never got to remove its own.\n */\nexport function liveSessions(registry: string): DevSessionRecord[] {\n\tconst dir = sessionsDir(registry);\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(dir).filter((file) => file.endsWith('.json'));\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst records: DevSessionRecord[] = [];\n\tfor (const file of files) {\n\t\tconst path = join(dir, file);\n\t\tlet record: DevSessionRecord;\n\t\ttry {\n\t\t\trecord = JSON.parse(readFileSync(path, 'utf8'));\n\t\t} catch {\n\t\t\t// Removed between the listing and the read.\n\t\t\tcontinue;\n\t\t}\n\t\tif (alive(record.pid)) {\n\t\t\trecords.push(record);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tunlinkSync(path);\n\t\t} catch {\n\t\t\t// Another session pruned it first.\n\t\t}\n\t}\n\treturn records;\n}\n\n/** Written whole, then renamed into place, so a reader never sees half. */\nfunction writeRecord(registry: string, record: DevSessionRecord): void {\n\tconst path = join(sessionsDir(registry), `${record.id}.json`);\n\tconst partial = `${path}.${process.pid}.tmp`;\n\twriteFileSync(partial, JSON.stringify(record), { mode: 0o600 });\n\trenameSync(partial, path);\n}\n\nfunction removeRecord(registry: string, id: string): void {\n\ttry {\n\t\tunlinkSync(join(sessionsDir(registry), `${id}.json`));\n\t} catch {\n\t\t// Already gone.\n\t}\n}\n\n/**\n * The token every session prints and every host checks.\n *\n * Shared through the registry, so a URL printed by one session still works\n * after another has taken over hosting. It lives as long as some session does:\n * a session that finds none but itself starts a new one, so a token printed\n * yesterday stops working once everything it was printed by has stopped.\n */\nfunction sessionToken(registry: string, self: string): string {\n\tconst path = join(registry, 'token');\n\tconst others = liveSessions(registry).filter((r) => r.id !== self);\n\n\tif (others.length === 0) {\n\t\t// Left by a session that died without removing it. Renamed away rather\n\t\t// than deleted, so only one of two sessions starting at once does it.\n\t\tconst stale = `${path}.${self}.stale`;\n\t\ttry {\n\t\t\trenameSync(path, stale);\n\t\t\tunlinkSync(stale);\n\t\t} catch {\n\t\t\t// None there, or another session got to it first.\n\t\t}\n\t}\n\n\t// Linked into place, which fails if one is already there — so two sessions\n\t// starting together agree on whichever landed first, and neither reads a\n\t// half-written file.\n\tconst fresh = `${path}.${self}.new`;\n\twriteFileSync(fresh, randomBytes(32).toString('base64url'), {\n\t\tmode: 0o600,\n\t});\n\ttry {\n\t\tlinkSync(fresh, path);\n\t} catch {\n\t\t// Someone else's is already there; theirs is the token.\n\t}\n\tunlinkSync(fresh);\n\treturn readFileSync(path, 'utf8').trim();\n}\n\n// ---------------------------------------------------------------------------\n// The view: sessions merged into workspaces\n// ---------------------------------------------------------------------------\n\n/** A workspace as served, with who may see it. */\ninterface WorkspaceView extends DiscoveredWorkspace {\n\tallowedOrigins: readonly string[];\n}\n\n/** `<name>-<8 hex>`: readable, and two checkouts of a project stay apart. */\nexport function workspaceId(name: string, root: string): string {\n\tconst slug =\n\t\tname\n\t\t\t.toLowerCase()\n\t\t\t.replace(/^@/, '')\n\t\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t\t.replace(/^-|-$/g, '') || 'workspace';\n\tconst hash = createHash('sha256').update(root).digest('hex').slice(0, 8);\n\treturn `${slug}-${hash}`;\n}\n\n/** Whether anything accepts connections on a local port. */\nfunction listening(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\t// `localhost`, not 127.0.0.1: a Vite server listens on `::1` alone.\n\t\tconst socket = connect({ port, host: 'localhost' });\n\t\tconst done = (open: boolean) => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(open);\n\t\t};\n\t\tsocket.setTimeout(300, () => done(false));\n\t\tsocket.once('connect', () => done(true));\n\t\tsocket.once('error', () => done(false));\n\t});\n}\n\n/** Which data APIs the forwarder matches by prefix, rather than exactly. */\nconst PREFIXED: ReadonlySet<DataApiKind> = new Set(['telescope', 'database']);\n\n/** Whether `path` on an app is one of its data APIs. */\nfunction servesData(app: DiscoveredApp, path: string): boolean {\n\treturn app.dataApis.some((api) =>\n\t\tPREFIXED.has(api.kind)\n\t\t\t? path === api.path || path.startsWith(`${api.path}/`)\n\t\t\t: // The OpenAPI document is exactly `/__docs`; `/__docs/ui` is a page.\n\t\t\t\tpath === api.path,\n\t);\n}\n\n/**\n * Every workspace the sessions describe, one entry per root.\n *\n * An app listed only by its workspace's session — a web app turbo started, an\n * API whose own `gkm dev` has not registered yet — is `ready` when its port\n * answers and `starting` until then.\n */\nasync function collect(records: DevSessionRecord[]): Promise<WorkspaceView[]> {\n\tconst byRoot = new Map<string, DevSessionRecord[]>();\n\tfor (const record of records) {\n\t\tconst group = byRoot.get(record.workspace.root) ?? [];\n\t\tgroup.push(record);\n\t\tbyRoot.set(record.workspace.root, group);\n\t}\n\n\tconst views: WorkspaceView[] = [];\n\tfor (const [root, group] of byRoot) {\n\t\t// The workspace's own session first, then the oldest: what names the\n\t\t// workspace and carries its manifest.\n\t\tgroup.sort(\n\t\t\t(a, b) =>\n\t\t\t\tNumber(b.role === 'workspace') - Number(a.role === 'workspace') ||\n\t\t\t\ta.startedAt.localeCompare(b.startedAt),\n\t\t);\n\t\tconst lead = group[0]!;\n\t\tconst id = workspaceId(lead.workspace.name, root);\n\n\t\tconst apps = new Map<string, { app: SessionApp; pid: number | null }>();\n\t\tfor (const record of group) {\n\t\t\tfor (const app of record.apps) {\n\t\t\t\tconst own = record.role === 'app';\n\t\t\t\tif (!own && apps.has(app.name)) continue;\n\t\t\t\tapps.set(app.name, { app, pid: own ? record.pid : null });\n\t\t\t}\n\t\t}\n\n\t\tconst discovered = await Promise.all(\n\t\t\t[...apps.values()].map(async ({ app, pid }): Promise<DiscoveredApp> => {\n\t\t\t\tconst url = `http://localhost:${app.port}`;\n\t\t\t\tconst status =\n\t\t\t\t\tpid === null\n\t\t\t\t\t\t? (await listening(app.port))\n\t\t\t\t\t\t\t? 'ready'\n\t\t\t\t\t\t\t: 'starting'\n\t\t\t\t\t\t: app.status;\n\t\t\t\treturn {\n\t\t\t\t\tname: app.name,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tport: app.port,\n\t\t\t\t\turl,\n\t\t\t\t\tpublicUrl: app.publicUrl ?? null,\n\t\t\t\t\tstatus,\n\t\t\t\t\treloads: app.reloads,\n\t\t\t\t\tpid,\n\t\t\t\t\tdataApis: app.dataApis.map((api) => ({\n\t\t\t\t\t\tkind: api.kind,\n\t\t\t\t\t\tpath: api.path,\n\t\t\t\t\t\turl: `${url}${api.path}`,\n\t\t\t\t\t\tproxy: `${BASE}/workspaces/${id}/apps/${encodeURIComponent(app.name)}${api.path}`,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\t\tdiscovered.sort((a, b) => a.name.localeCompare(b.name));\n\n\t\tviews.push({\n\t\t\tid,\n\t\t\tname: lead.workspace.name,\n\t\t\troot,\n\t\t\tstage: lead.workspace.stage,\n\t\t\tmanifest: group.find((r) => r.manifest)?.manifest ?? null,\n\t\t\tapps: discovered,\n\t\t\tallowedOrigins: [...new Set(group.flatMap((r) => r.allowedOrigins))],\n\t\t});\n\t}\n\n\treturn views.sort(\n\t\t(a, b) => a.name.localeCompare(b.name) || a.root.localeCompare(b.root),\n\t);\n}\n\n/** What changed between two views, as events. */\nfunction changes(\n\tbefore: readonly WorkspaceView[],\n\tafter: readonly WorkspaceView[],\n): { workspace: WorkspaceView; event: DiscoveryEvent }[] {\n\tconst out: { workspace: WorkspaceView; event: DiscoveryEvent }[] = [];\n\tconst previous = new Map(before.map((w) => [w.id, w]));\n\tconst next = new Map(after.map((w) => [w.id, w]));\n\n\tfor (const workspace of after) {\n\t\tconst was = previous.get(workspace.id);\n\t\tif (!was) {\n\t\t\tout.push({\n\t\t\t\tworkspace,\n\t\t\t\tevent: { type: 'workspace.started', workspace: workspace.id },\n\t\t\t});\n\t\t}\n\t\tconst wasApps = new Map((was?.apps ?? []).map((a) => [a.name, a]));\n\t\tfor (const app of workspace.apps) {\n\t\t\tconst old = wasApps.get(app.name);\n\t\t\tconst type = !old\n\t\t\t\t? 'app.started'\n\t\t\t\t: app.reloads > old.reloads\n\t\t\t\t\t? 'app.reloaded'\n\t\t\t\t\t: app.status !== old.status ||\n\t\t\t\t\t\t\tapp.port !== old.port ||\n\t\t\t\t\t\t\tapp.dataApis.length !== old.dataApis.length\n\t\t\t\t\t\t? 'app.status'\n\t\t\t\t\t\t: undefined;\n\t\t\tif (type) {\n\t\t\t\tout.push({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tevent: { type, workspace: workspace.id, app },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tfor (const old of was?.apps ?? []) {\n\t\t\tif (!workspace.apps.some((a) => a.name === old.name)) {\n\t\t\t\tout.push({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tevent: { type: 'app.stopped', workspace: workspace.id, app: old },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const workspace of before) {\n\t\tif (next.has(workspace.id)) continue;\n\t\tfor (const app of workspace.apps) {\n\t\t\tout.push({\n\t\t\t\tworkspace,\n\t\t\t\tevent: { type: 'app.stopped', workspace: workspace.id, app },\n\t\t\t});\n\t\t}\n\t\tout.push({\n\t\t\tworkspace,\n\t\t\tevent: { type: 'workspace.stopped', workspace: workspace.id },\n\t\t});\n\t}\n\n\treturn out;\n}\n\n// ---------------------------------------------------------------------------\n// The endpoint\n// ---------------------------------------------------------------------------\n\n/** A browser with no `Origin` — curl, a local process — sees everything. */\nfunction visibleTo(workspace: WorkspaceView, origin: string | undefined) {\n\treturn origin === undefined || workspace.allowedOrigins.includes(origin);\n}\n\nfunction publicView({\n\tallowedOrigins: _,\n\t...workspace\n}: WorkspaceView): DiscoveredWorkspace {\n\treturn workspace;\n}\n\n/** Headers an app's response is passed on with; nothing that sets state. */\nconst FORWARDED_RESPONSE_HEADERS = [\n\t'content-type',\n\t'cache-control',\n\t'etag',\n\t'last-modified',\n];\n\ninterface EventStream {\n\torigin: string | undefined;\n\tresponse: ServerResponse;\n}\n\n/**\n * The HTTP side: serves the registry it reads, checking every request.\n * @internal Exported for testing\n */\nexport class DiscoveryHost {\n\tprivate server: Server | undefined;\n\tprivate view: WorkspaceView[] = [];\n\tprivate streams = new Set<EventStream>();\n\tprivate scanning: Promise<WorkspaceView[]> | undefined;\n\tprivate timers: NodeJS.Timeout[] = [];\n\tprivate sequence = 0;\n\n\tconstructor(\n\t\tprivate readonly registry: string,\n\t\tprivate readonly token: string,\n\t\tprivate readonly pollMs: number,\n\t) {}\n\n\t/** The port it is bound to, once it is. */\n\tget port(): number | undefined {\n\t\tconst address = this.server?.address() as AddressInfo | null | undefined;\n\t\treturn address?.port;\n\t}\n\n\t/** Binds the port; `false` when another process already has it. */\n\tasync listen(port: number): Promise<boolean> {\n\t\tconst server = createServer((request, response) => {\n\t\t\tthis.handle(request, response).catch(() => {\n\t\t\t\tif (!response.headersSent) {\n\t\t\t\t\treply(response, 500, { error: 'DiscoveryFailed' });\n\t\t\t\t} else {\n\t\t\t\t\tresponse.destroy();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tconst bound = await new Promise<boolean>((resolve) => {\n\t\t\tserver.once('error', () => resolve(false));\n\t\t\tserver.listen(port, '127.0.0.1', () => resolve(true));\n\t\t});\n\t\tif (!bound) return false;\n\n\t\t// Neither the server nor its timers hold `gkm dev` open; the dev server\n\t\t// and the watcher are what it runs for.\n\t\tserver.unref();\n\t\tthis.server = server;\n\t\tthis.view = await this.scan();\n\t\tthis.timers.push(\n\t\t\tsetInterval(() => void this.scan(), this.pollMs).unref(),\n\t\t\t// A comment line every 15s, so proxies and idle timeouts leave the\n\t\t\t// stream open.\n\t\t\tsetInterval(() => {\n\t\t\t\tfor (const { response } of this.streams) response.write(': ping\\n\\n');\n\t\t\t}, 15_000).unref(),\n\t\t);\n\t\treturn true;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tfor (const timer of this.timers) clearInterval(timer);\n\t\tthis.timers = [];\n\t\tfor (const { response } of this.streams) response.end();\n\t\tthis.streams.clear();\n\t\tconst server = this.server;\n\t\tthis.server = undefined;\n\t\tif (!server) return;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tserver.close(() => resolve());\n\t\t\tserver.closeAllConnections();\n\t\t});\n\t}\n\n\t/** Reads the registry, and tells every stream what changed. One at a time. */\n\tscan(): Promise<WorkspaceView[]> {\n\t\tconst run = (this.scanning ?? Promise.resolve()).then(async () => {\n\t\t\tconst next = await collect(liveSessions(this.registry));\n\t\t\tfor (const { workspace, event } of changes(this.view, next)) {\n\t\t\t\tthis.broadcast(workspace, event);\n\t\t\t}\n\t\t\tthis.view = next;\n\t\t\treturn next;\n\t\t});\n\t\tthis.scanning = run.catch(() => this.view);\n\t\treturn run;\n\t}\n\n\tprivate broadcast(workspace: WorkspaceView, event: DiscoveryEvent): void {\n\t\tthis.sequence += 1;\n\t\tfor (const stream of this.streams) {\n\t\t\tif (!visibleTo(workspace, stream.origin)) continue;\n\t\t\tsend(stream.response, event, this.sequence);\n\t\t}\n\t}\n\n\tprivate snapshot(origin: string | undefined): DiscoveryResponse {\n\t\treturn {\n\t\t\tversion: 1,\n\t\t\thost: { pid: process.pid, port: this.port ?? 0 },\n\t\t\tevents: `${BASE}/events`,\n\t\t\tworkspaces: this.view.filter((w) => visibleTo(w, origin)).map(publicView),\n\t\t};\n\t}\n\n\tprivate async handle(\n\t\trequest: IncomingMessage,\n\t\tresponse: ServerResponse,\n\t): Promise<void> {\n\t\t// Rebinding: a page on `evil.example` that resolves to 127.0.0.1 sends\n\t\t// `Host: evil.example`. Only our own names, with our own port.\n\t\tconst port = this.port;\n\t\tconst host = request.headers.host;\n\t\tif (host !== `127.0.0.1:${port}` && host !== `localhost:${port}`) {\n\t\t\treply(response, 403, {\n\t\t\t\terror: 'HostNotAllowed',\n\t\t\t\tmessage: `Reach discovery at http://127.0.0.1:${port}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst origin = request.headers.origin;\n\t\tconst allowed = this.view.flatMap((w) => w.allowedOrigins);\n\t\tif (origin !== undefined && !allowed.includes(origin)) {\n\t\t\t// No CORS headers: the browser hides even this answer from the page.\n\t\t\treply(response, 403, {\n\t\t\t\terror: 'OriginNotAllowed',\n\t\t\t\tmessage: `Add ${origin} to dev.allowedOrigins in gkm.config.ts to let it read gkm dev.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (origin !== undefined) {\n\t\t\tresponse.setHeader('access-control-allow-origin', origin);\n\t\t\tresponse.setHeader('vary', 'Origin');\n\t\t}\n\n\t\tif (request.method === 'OPTIONS') {\n\t\t\t// A preflight carries no credentials, so it is answered before the\n\t\t\t// token is asked for — only for an origin that was listed.\n\t\t\tresponse.setHeader('access-control-allow-methods', 'GET, HEAD');\n\t\t\tresponse.setHeader('access-control-allow-headers', 'Authorization');\n\t\t\tresponse.setHeader('access-control-max-age', '600');\n\t\t\tif (request.headers['access-control-request-private-network']) {\n\t\t\t\tresponse.setHeader('access-control-allow-private-network', 'true');\n\t\t\t}\n\t\t\tresponse.writeHead(204).end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(request.url ?? '/', `http://${host}`);\n\t\tif (!this.authorized(request, url)) {\n\t\t\treply(response, 401, {\n\t\t\t\terror: 'TokenRequired',\n\t\t\t\tmessage:\n\t\t\t\t\t'Use the connect URL gkm dev printed, or send its token as `Authorization: Bearer <token>`.',\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (request.method !== 'GET' && request.method !== 'HEAD') {\n\t\t\tresponse.setHeader('allow', 'GET, HEAD, OPTIONS');\n\t\t\treply(response, 405, {\n\t\t\t\terror: 'ReadOnly',\n\t\t\t\tmessage: 'Discovery is read-only: GET and HEAD.',\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst path = url.pathname.replace(/\\/+$/, '') || '/';\n\t\tif (path === BASE) {\n\t\t\tawait this.scan();\n\t\t\treply(response, 200, this.snapshot(origin));\n\t\t\treturn;\n\t\t}\n\t\tif (path === `${BASE}/events`) {\n\t\t\tawait this.scan();\n\t\t\tthis.stream(response, origin);\n\t\t\tresponse.once('close', () => {\n\t\t\t\tfor (const stream of this.streams) {\n\t\t\t\t\tif (stream.response === response) this.streams.delete(stream);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst forwarded = path.match(\n\t\t\t/^\\/__gkm\\/workspaces\\/([^/]+)\\/apps\\/([^/]+)(\\/.*)$/,\n\t\t);\n\t\tif (forwarded) {\n\t\t\tconst [, id, name, rest] = forwarded;\n\t\t\tawait this.forward(\n\t\t\t\trequest,\n\t\t\t\tresponse,\n\t\t\t\torigin,\n\t\t\t\tid!,\n\t\t\t\tdecodeURIComponent(name!),\n\t\t\t\trest!,\n\t\t\t\turl,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\treply(response, 404, { error: 'NotFound' });\n\t}\n\n\tprivate authorized(request: IncomingMessage, url: URL): boolean {\n\t\tconst header = request.headers.authorization;\n\t\tconst given = header?.startsWith('Bearer ')\n\t\t\t? header.slice('Bearer '.length).trim()\n\t\t\t: url.searchParams.get('token');\n\t\tif (!given) return false;\n\t\tconst a = Buffer.from(given);\n\t\tconst b = Buffer.from(this.token);\n\t\treturn a.length === b.length && timingSafeEqual(a, b);\n\t}\n\n\tprivate stream(response: ServerResponse, origin: string | undefined): void {\n\t\tresponse.writeHead(200, {\n\t\t\t'content-type': 'text/event-stream',\n\t\t\t'cache-control': 'no-cache',\n\t\t\tconnection: 'keep-alive',\n\t\t});\n\t\t// When the host changes, `EventSource` reconnects — to the new one.\n\t\tresponse.write('retry: 1000\\n\\n');\n\t\tsend(response, { type: 'snapshot', snapshot: this.snapshot(origin) });\n\t\tthis.streams.add({ origin, response });\n\t}\n\n\t/** Passes a read of one data API on to the app that serves it. */\n\tprivate async forward(\n\t\trequest: IncomingMessage,\n\t\tresponse: ServerResponse,\n\t\torigin: string | undefined,\n\t\tid: string,\n\t\tname: string,\n\t\tpath: string,\n\t\turl: URL,\n\t): Promise<void> {\n\t\tconst workspace = this.view.find(\n\t\t\t(w) => w.id === id && visibleTo(w, origin),\n\t\t);\n\t\tconst app = workspace?.apps.find((a) => a.name === name);\n\t\tif (!app) {\n\t\t\treply(response, 404, { error: 'AppNotFound' });\n\t\t\treturn;\n\t\t}\n\t\tif (!servesData(app, path)) {\n\t\t\treply(response, 404, {\n\t\t\t\terror: 'NotADataApi',\n\t\t\t\tmessage: `Only ${name}'s data APIs are forwarded: ${app.dataApis.map((a) => a.path).join(', ') || 'it has none'}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// The token is ours, not the app's.\n\t\tconst search = new URLSearchParams(url.searchParams);\n\t\tsearch.delete('token');\n\t\tconst query = search.size > 0 ? `?${search}` : '';\n\n\t\t// The response, not the request: a request's `close` fires once its\n\t\t// (empty) body is read, which would abort the read straight away.\n\t\tconst abort = new AbortController();\n\t\tresponse.once('close', () => abort.abort());\n\t\tlet upstream: Response;\n\t\ttry {\n\t\t\tupstream = await fetch(`http://localhost:${app.port}${path}${query}`, {\n\t\t\t\tmethod: request.method,\n\t\t\t\t// Only what describes the read: no cookies, no credentials.\n\t\t\t\theaders: { accept: request.headers.accept ?? '*/*' },\n\t\t\t\tsignal: abort.signal,\n\t\t\t});\n\t\t} catch {\n\t\t\treply(response, 502, {\n\t\t\t\terror: 'AppUnavailable',\n\t\t\t\tmessage: `${name} is not answering on port ${app.port}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst headers: Record<string, string> = {};\n\t\tfor (const key of FORWARDED_RESPONSE_HEADERS) {\n\t\t\tconst value = upstream.headers.get(key);\n\t\t\tif (value) headers[key] = value;\n\t\t}\n\t\tresponse.writeHead(upstream.status, headers);\n\t\tif (!upstream.body || request.method === 'HEAD') {\n\t\t\tresponse.end();\n\t\t\treturn;\n\t\t}\n\t\tReadable.fromWeb(upstream.body as never)\n\t\t\t.on('error', () => response.destroy())\n\t\t\t.pipe(response);\n\t}\n}\n\nfunction reply(response: ServerResponse, status: number, body: unknown) {\n\tresponse.writeHead(status, { 'content-type': 'application/json' });\n\tresponse.end(JSON.stringify(body));\n}\n\nfunction send(response: ServerResponse, event: DiscoveryEvent, id?: number) {\n\tresponse.write(\n\t\t`${id === undefined ? '' : `id: ${id}\\n`}event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// A session\n// ---------------------------------------------------------------------------\n\nexport interface JoinDiscoveryOptions {\n\trole: DevSessionRecord['role'];\n\tworkspace: DevSessionRecord['workspace'];\n\tallowedOrigins?: readonly string[];\n\tmanifest?: ConstructManifest;\n\tapps: SessionApp[];\n\t/** `0` hosts on a free port of its own, and never hands over. */\n\tport?: number;\n\tregistry?: string;\n\t/** How often the host rereads the registry. */\n\tpollMs?: number;\n\t/** How often a session that is not hosting tries to take over. */\n\telectionMs?: number;\n}\n\n/**\n * One `gkm dev`'s membership: its record in the registry, and — while it holds\n * the port — the endpoint itself.\n */\nexport class DiscoverySession {\n\tprivate host: DiscoveryHost | undefined;\n\tprivate election: NodeJS.Timeout | undefined;\n\tprivate left = false;\n\tprivate readonly cleanup = () => removeRecord(this.registry, this.record.id);\n\n\tprivate constructor(\n\t\tprivate readonly registry: string,\n\t\tprivate readonly port: number,\n\t\tprivate readonly record: DevSessionRecord,\n\t\treadonly token: string,\n\t\tprivate readonly pollMs: number,\n\t) {}\n\n\tstatic async join(options: JoinDiscoveryOptions): Promise<DiscoverySession> {\n\t\tconst registry = options.registry ?? discoveryRegistry();\n\t\tmkdirSync(sessionsDir(registry), { recursive: true, mode: 0o700 });\n\n\t\tconst now = new Date().toISOString();\n\t\tconst record: DevSessionRecord = {\n\t\t\tid: `${process.pid}-${randomBytes(4).toString('hex')}`,\n\t\t\tpid: process.pid,\n\t\t\trole: options.role,\n\t\t\tstartedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tworkspace: options.workspace,\n\t\t\tallowedOrigins: [...(options.allowedOrigins ?? [])],\n\t\t\t...(options.manifest ? { manifest: options.manifest } : {}),\n\t\t\tapps: options.apps,\n\t\t};\n\t\t// Registered before the token is settled, so a session starting at the\n\t\t// same moment sees this one and does not replace the token under it.\n\t\twriteRecord(registry, record);\n\t\tconst token = sessionToken(registry, record.id);\n\n\t\tconst session = new DiscoverySession(\n\t\t\tregistry,\n\t\t\toptions.port ?? DEFAULT_DISCOVERY_PORT,\n\t\t\trecord,\n\t\t\ttoken,\n\t\t\toptions.pollMs ?? 500,\n\t\t);\n\t\tprocess.once('exit', session.cleanup);\n\n\t\tawait session.elect();\n\t\t// On port 0 every session hosts its own, so there is nothing to take\n\t\t// over.\n\t\tif (!session.host && session.port !== 0) {\n\t\t\tsession.election = setInterval(\n\t\t\t\t() => void session.elect(),\n\t\t\t\toptions.electionMs ?? 1000,\n\t\t\t).unref();\n\t\t}\n\t\treturn session;\n\t}\n\n\t/** Whether this session is the one serving the endpoint. */\n\tget hosting(): boolean {\n\t\treturn this.host !== undefined;\n\t}\n\n\t/** The port clients reach — this host's own, when it chose one. */\n\tget endpointPort(): number {\n\t\treturn this.host?.port ?? this.port;\n\t}\n\n\t/** Jupyter-style: the endpoint, with the token that opens it. */\n\tget connectUrl(): string {\n\t\treturn `http://127.0.0.1:${this.endpointPort}${BASE}?token=${this.token}`;\n\t}\n\n\t/** Changes one of this session's apps, and tells the endpoint. */\n\tupdateApp(name: string, change: (app: SessionApp) => SessionApp): void {\n\t\tif (this.left) return;\n\t\tthis.record.apps = this.record.apps.map((app) =>\n\t\t\tapp.name === name ? change(app) : app,\n\t\t);\n\t\tthis.record.updatedAt = new Date().toISOString();\n\t\twriteRecord(this.registry, this.record);\n\t\t// The host hears of its own changes now, not on its next poll.\n\t\tvoid this.host?.scan();\n\t}\n\n\t/** Leaves the registry, and the port to whichever session takes it next. */\n\tasync leave(): Promise<void> {\n\t\tif (this.left) return;\n\t\tthis.left = true;\n\t\tif (this.election) clearInterval(this.election);\n\t\tprocess.removeListener('exit', this.cleanup);\n\t\tthis.cleanup();\n\t\tawait this.host?.close();\n\t\tthis.host = undefined;\n\t\t// The last one out takes the token with it.\n\t\tif (liveSessions(this.registry).length === 0) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(join(this.registry, 'token'));\n\t\t\t} catch {\n\t\t\t\t// Already gone.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async elect(): Promise<void> {\n\t\tif (this.host || this.left) return;\n\t\tconst host = new DiscoveryHost(this.registry, this.token, this.pollMs);\n\t\tif (!(await host.listen(this.port))) return;\n\t\tif (this.left) {\n\t\t\tawait host.close();\n\t\t\treturn;\n\t\t}\n\t\tthis.host = host;\n\t\tif (this.election) clearInterval(this.election);\n\t\tthis.election = undefined;\n\t}\n}\n\n/** Joins the machine's discovery; see {@link DiscoverySession}. */\nexport function joinDiscovery(\n\toptions: JoinDiscoveryOptions,\n): Promise<DiscoverySession> {\n\treturn DiscoverySession.join(options);\n}\n\n/** The data APIs a generated dev app mounts, from what `gkm dev` built. */\nexport function dataApisOf(options: {\n\tselfServing: boolean;\n\ttelescopePath?: string;\n\tdatabaseApi?: string;\n\topenApi: boolean;\n}): SessionDataApi[] {\n\t// An app that serves itself — an auth server — mounts none of them.\n\tif (options.selfServing) return [];\n\treturn [\n\t\t...(options.telescopePath\n\t\t\t? [{ kind: 'telescope' as const, path: `${options.telescopePath}/api` }]\n\t\t\t: []),\n\t\t...(options.databaseApi\n\t\t\t? [{ kind: 'database' as const, path: options.databaseApi }]\n\t\t\t: []),\n\t\t...(options.openApi ? [{ kind: 'openapi' as const, path: '/__docs' }] : []),\n\t];\n}\n","// src/server.ts\nimport { createServer as createServerHTTP } from \"http\";\n\n// src/listener.ts\nimport { Http2ServerRequest as Http2ServerRequest2 } from \"http2\";\n\n// src/request.ts\nimport { Http2ServerRequest } from \"http2\";\nimport { Readable } from \"stream\";\nvar RequestError = class extends Error {\n constructor(message, options) {\n super(message, options);\n this.name = \"RequestError\";\n }\n};\nvar toRequestError = (e) => {\n if (e instanceof RequestError) {\n return e;\n }\n return new RequestError(e.message, { cause: e });\n};\nvar GlobalRequest = global.Request;\nvar Request = class extends GlobalRequest {\n constructor(input, options) {\n if (typeof input === \"object\" && getRequestCache in input) {\n input = input[getRequestCache]();\n }\n if (typeof options?.body?.getReader !== \"undefined\") {\n ;\n options.duplex ??= \"half\";\n }\n super(input, options);\n }\n};\nvar newHeadersFromIncoming = (incoming) => {\n const headerRecord = [];\n const rawHeaders = incoming.rawHeaders;\n for (let i = 0; i < rawHeaders.length; i += 2) {\n const { [i]: key, [i + 1]: value } = rawHeaders;\n if (key.charCodeAt(0) !== /*:*/\n 58) {\n headerRecord.push([key, value]);\n }\n }\n return new Headers(headerRecord);\n};\nvar wrapBodyStream = Symbol(\"wrapBodyStream\");\nvar newRequestFromIncoming = (method, url, headers, incoming, abortController) => {\n const init = {\n method,\n headers,\n signal: abortController.signal\n };\n if (method === \"TRACE\") {\n init.method = \"GET\";\n const req = new Request(url, init);\n Object.defineProperty(req, \"method\", {\n get() {\n return \"TRACE\";\n }\n });\n return req;\n }\n if (!(method === \"GET\" || method === \"HEAD\")) {\n if (\"rawBody\" in incoming && incoming.rawBody instanceof Buffer) {\n init.body = new ReadableStream({\n start(controller) {\n controller.enqueue(incoming.rawBody);\n controller.close();\n }\n });\n } else if (incoming[wrapBodyStream]) {\n let reader;\n init.body = new ReadableStream({\n async pull(controller) {\n try {\n reader ||= Readable.toWeb(incoming).getReader();\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n });\n } else {\n init.body = Readable.toWeb(incoming);\n }\n }\n return new Request(url, init);\n};\nvar getRequestCache = Symbol(\"getRequestCache\");\nvar requestCache = Symbol(\"requestCache\");\nvar incomingKey = Symbol(\"incomingKey\");\nvar urlKey = Symbol(\"urlKey\");\nvar headersKey = Symbol(\"headersKey\");\nvar abortControllerKey = Symbol(\"abortControllerKey\");\nvar getAbortController = Symbol(\"getAbortController\");\nvar requestPrototype = {\n get method() {\n return this[incomingKey].method || \"GET\";\n },\n get url() {\n return this[urlKey];\n },\n get headers() {\n return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);\n },\n [getAbortController]() {\n this[getRequestCache]();\n return this[abortControllerKey];\n },\n [getRequestCache]() {\n this[abortControllerKey] ||= new AbortController();\n return this[requestCache] ||= newRequestFromIncoming(\n this.method,\n this[urlKey],\n this.headers,\n this[incomingKey],\n this[abortControllerKey]\n );\n }\n};\n[\n \"body\",\n \"bodyUsed\",\n \"cache\",\n \"credentials\",\n \"destination\",\n \"integrity\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"keepalive\"\n].forEach((k) => {\n Object.defineProperty(requestPrototype, k, {\n get() {\n return this[getRequestCache]()[k];\n }\n });\n});\n[\"arrayBuffer\", \"blob\", \"clone\", \"formData\", \"json\", \"text\"].forEach((k) => {\n Object.defineProperty(requestPrototype, k, {\n value: function() {\n return this[getRequestCache]()[k]();\n }\n });\n});\nObject.setPrototypeOf(requestPrototype, Request.prototype);\nvar newRequest = (incoming, defaultHostname) => {\n const req = Object.create(requestPrototype);\n req[incomingKey] = incoming;\n const incomingUrl = incoming.url || \"\";\n if (incomingUrl[0] !== \"/\" && // short-circuit for performance. most requests are relative URL.\n (incomingUrl.startsWith(\"http://\") || incomingUrl.startsWith(\"https://\"))) {\n if (incoming instanceof Http2ServerRequest) {\n throw new RequestError(\"Absolute URL for :path is not allowed in HTTP/2\");\n }\n try {\n const url2 = new URL(incomingUrl);\n req[urlKey] = url2.href;\n } catch (e) {\n throw new RequestError(\"Invalid absolute URL\", { cause: e });\n }\n return req;\n }\n const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;\n if (!host) {\n throw new RequestError(\"Missing host header\");\n }\n let scheme;\n if (incoming instanceof Http2ServerRequest) {\n scheme = incoming.scheme;\n if (!(scheme === \"http\" || scheme === \"https\")) {\n throw new RequestError(\"Unsupported scheme\");\n }\n } else {\n scheme = incoming.socket && incoming.socket.encrypted ? \"https\" : \"http\";\n }\n const url = new URL(`${scheme}://${host}${incomingUrl}`);\n if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\\d+$/, \"\")) {\n throw new RequestError(\"Invalid host header\");\n }\n req[urlKey] = url.href;\n return req;\n};\n\n// src/response.ts\nvar responseCache = Symbol(\"responseCache\");\nvar getResponseCache = Symbol(\"getResponseCache\");\nvar cacheKey = Symbol(\"cache\");\nvar GlobalResponse = global.Response;\nvar Response2 = class _Response {\n #body;\n #init;\n [getResponseCache]() {\n delete this[cacheKey];\n return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);\n }\n constructor(body, init) {\n let headers;\n this.#body = body;\n if (init instanceof _Response) {\n const cachedGlobalResponse = init[responseCache];\n if (cachedGlobalResponse) {\n this.#init = cachedGlobalResponse;\n this[getResponseCache]();\n return;\n } else {\n this.#init = init.#init;\n headers = new Headers(init.#init.headers);\n }\n } else {\n this.#init = init;\n }\n if (typeof body === \"string\" || typeof body?.getReader !== \"undefined\" || body instanceof Blob || body instanceof Uint8Array) {\n headers ||= init?.headers || { \"content-type\": \"text/plain; charset=UTF-8\" };\n this[cacheKey] = [init?.status || 200, body, headers];\n }\n }\n get headers() {\n const cache = this[cacheKey];\n if (cache) {\n if (!(cache[2] instanceof Headers)) {\n cache[2] = new Headers(cache[2]);\n }\n return cache[2];\n }\n return this[getResponseCache]().headers;\n }\n get status() {\n return this[cacheKey]?.[0] ?? this[getResponseCache]().status;\n }\n get ok() {\n const status = this.status;\n return status >= 200 && status < 300;\n }\n};\n[\"body\", \"bodyUsed\", \"redirected\", \"statusText\", \"trailers\", \"type\", \"url\"].forEach((k) => {\n Object.defineProperty(Response2.prototype, k, {\n get() {\n return this[getResponseCache]()[k];\n }\n });\n});\n[\"arrayBuffer\", \"blob\", \"clone\", \"formData\", \"json\", \"text\"].forEach((k) => {\n Object.defineProperty(Response2.prototype, k, {\n value: function() {\n return this[getResponseCache]()[k]();\n }\n });\n});\nObject.setPrototypeOf(Response2, GlobalResponse);\nObject.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);\n\n// src/utils.ts\nasync function readWithoutBlocking(readPromise) {\n return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);\n}\nfunction writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {\n const cancel = (error) => {\n reader.cancel(error).catch(() => {\n });\n };\n writable.on(\"close\", cancel);\n writable.on(\"error\", cancel);\n (currentReadPromise ?? reader.read()).then(flow, handleStreamError);\n return reader.closed.finally(() => {\n writable.off(\"close\", cancel);\n writable.off(\"error\", cancel);\n });\n function handleStreamError(error) {\n if (error) {\n writable.destroy(error);\n }\n }\n function onDrain() {\n reader.read().then(flow, handleStreamError);\n }\n function flow({ done, value }) {\n try {\n if (done) {\n writable.end();\n } else if (!writable.write(value)) {\n writable.once(\"drain\", onDrain);\n } else {\n return reader.read().then(flow, handleStreamError);\n }\n } catch (e) {\n handleStreamError(e);\n }\n }\n}\nfunction writeFromReadableStream(stream, writable) {\n if (stream.locked) {\n throw new TypeError(\"ReadableStream is locked.\");\n } else if (writable.destroyed) {\n return;\n }\n return writeFromReadableStreamDefaultReader(stream.getReader(), writable);\n}\nvar buildOutgoingHttpHeaders = (headers) => {\n const res = {};\n if (!(headers instanceof Headers)) {\n headers = new Headers(headers ?? void 0);\n }\n const cookies = [];\n for (const [k, v] of headers) {\n if (k === \"set-cookie\") {\n cookies.push(v);\n } else {\n res[k] = v;\n }\n }\n if (cookies.length > 0) {\n res[\"set-cookie\"] = cookies;\n }\n res[\"content-type\"] ??= \"text/plain; charset=UTF-8\";\n return res;\n};\n\n// src/utils/response/constants.ts\nvar X_ALREADY_SENT = \"x-hono-already-sent\";\n\n// src/globals.ts\nimport crypto from \"crypto\";\nvar webFetch = global.fetch;\nif (typeof global.crypto === \"undefined\") {\n global.crypto = crypto;\n}\nglobal.fetch = (info, init) => {\n init = {\n // Disable compression handling so people can return the result of a fetch\n // directly in the loader without messing with the Content-Encoding header.\n compress: false,\n ...init\n };\n return webFetch(info, init);\n};\n\n// src/listener.ts\nvar outgoingEnded = Symbol(\"outgoingEnded\");\nvar handleRequestError = () => new Response(null, {\n status: 400\n});\nvar handleFetchError = (e) => new Response(null, {\n status: e instanceof Error && (e.name === \"TimeoutError\" || e.constructor.name === \"TimeoutError\") ? 504 : 500\n});\nvar handleResponseError = (e, outgoing) => {\n const err = e instanceof Error ? e : new Error(\"unknown error\", { cause: e });\n if (err.code === \"ERR_STREAM_PREMATURE_CLOSE\") {\n console.info(\"The user aborted a request.\");\n } else {\n console.error(e);\n if (!outgoing.headersSent) {\n outgoing.writeHead(500, { \"Content-Type\": \"text/plain\" });\n }\n outgoing.end(`Error: ${err.message}`);\n outgoing.destroy(err);\n }\n};\nvar flushHeaders = (outgoing) => {\n if (\"flushHeaders\" in outgoing && outgoing.writable) {\n outgoing.flushHeaders();\n }\n};\nvar responseViaCache = async (res, outgoing) => {\n let [status, body, header] = res[cacheKey];\n if (header instanceof Headers) {\n header = buildOutgoingHttpHeaders(header);\n }\n if (typeof body === \"string\") {\n header[\"Content-Length\"] = Buffer.byteLength(body);\n } else if (body instanceof Uint8Array) {\n header[\"Content-Length\"] = body.byteLength;\n } else if (body instanceof Blob) {\n header[\"Content-Length\"] = body.size;\n }\n outgoing.writeHead(status, header);\n if (typeof body === \"string\" || body instanceof Uint8Array) {\n outgoing.end(body);\n } else if (body instanceof Blob) {\n outgoing.end(new Uint8Array(await body.arrayBuffer()));\n } else {\n flushHeaders(outgoing);\n await writeFromReadableStream(body, outgoing)?.catch(\n (e) => handleResponseError(e, outgoing)\n );\n }\n ;\n outgoing[outgoingEnded]?.();\n};\nvar isPromise = (res) => typeof res.then === \"function\";\nvar responseViaResponseObject = async (res, outgoing, options = {}) => {\n if (isPromise(res)) {\n if (options.errorHandler) {\n try {\n res = await res;\n } catch (err) {\n const errRes = await options.errorHandler(err);\n if (!errRes) {\n return;\n }\n res = errRes;\n }\n } else {\n res = await res.catch(handleFetchError);\n }\n }\n if (cacheKey in res) {\n return responseViaCache(res, outgoing);\n }\n const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);\n if (res.body) {\n const reader = res.body.getReader();\n const values = [];\n let done = false;\n let currentReadPromise = void 0;\n if (resHeaderRecord[\"transfer-encoding\"] !== \"chunked\") {\n let maxReadCount = 2;\n for (let i = 0; i < maxReadCount; i++) {\n currentReadPromise ||= reader.read();\n const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {\n console.error(e);\n done = true;\n });\n if (!chunk) {\n if (i === 1) {\n await new Promise((resolve) => setTimeout(resolve));\n maxReadCount = 3;\n continue;\n }\n break;\n }\n currentReadPromise = void 0;\n if (chunk.value) {\n values.push(chunk.value);\n }\n if (chunk.done) {\n done = true;\n break;\n }\n }\n if (done && !(\"content-length\" in resHeaderRecord)) {\n resHeaderRecord[\"content-length\"] = values.reduce((acc, value) => acc + value.length, 0);\n }\n }\n outgoing.writeHead(res.status, resHeaderRecord);\n values.forEach((value) => {\n ;\n outgoing.write(value);\n });\n if (done) {\n outgoing.end();\n } else {\n if (values.length === 0) {\n flushHeaders(outgoing);\n }\n await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);\n }\n } else if (resHeaderRecord[X_ALREADY_SENT]) {\n } else {\n outgoing.writeHead(res.status, resHeaderRecord);\n outgoing.end();\n }\n ;\n outgoing[outgoingEnded]?.();\n};\nvar getRequestListener = (fetchCallback, options = {}) => {\n const autoCleanupIncoming = options.autoCleanupIncoming ?? true;\n if (options.overrideGlobalObjects !== false && global.Request !== Request) {\n Object.defineProperty(global, \"Request\", {\n value: Request\n });\n Object.defineProperty(global, \"Response\", {\n value: Response2\n });\n }\n return async (incoming, outgoing) => {\n let res, req;\n try {\n req = newRequest(incoming, options.hostname);\n let incomingEnded = !autoCleanupIncoming || incoming.method === \"GET\" || incoming.method === \"HEAD\";\n if (!incomingEnded) {\n ;\n incoming[wrapBodyStream] = true;\n incoming.on(\"end\", () => {\n incomingEnded = true;\n });\n if (incoming instanceof Http2ServerRequest2) {\n ;\n outgoing[outgoingEnded] = () => {\n if (!incomingEnded) {\n setTimeout(() => {\n if (!incomingEnded) {\n setTimeout(() => {\n incoming.destroy();\n outgoing.destroy();\n });\n }\n });\n }\n };\n }\n }\n outgoing.on(\"close\", () => {\n const abortController = req[abortControllerKey];\n if (abortController) {\n if (incoming.errored) {\n req[abortControllerKey].abort(incoming.errored.toString());\n } else if (!outgoing.writableFinished) {\n req[abortControllerKey].abort(\"Client connection prematurely closed.\");\n }\n }\n if (!incomingEnded) {\n setTimeout(() => {\n if (!incomingEnded) {\n setTimeout(() => {\n incoming.destroy();\n });\n }\n });\n }\n });\n res = fetchCallback(req, { incoming, outgoing });\n if (cacheKey in res) {\n return responseViaCache(res, outgoing);\n }\n } catch (e) {\n if (!res) {\n if (options.errorHandler) {\n res = await options.errorHandler(req ? e : toRequestError(e));\n if (!res) {\n return;\n }\n } else if (!req) {\n res = handleRequestError();\n } else {\n res = handleFetchError(e);\n }\n } else {\n return handleResponseError(e, outgoing);\n }\n }\n try {\n return await responseViaResponseObject(res, outgoing, options);\n } catch (e) {\n return handleResponseError(e, outgoing);\n }\n };\n};\n\n// src/server.ts\nvar createAdaptorServer = (options) => {\n const fetchCallback = options.fetch;\n const requestListener = getRequestListener(fetchCallback, {\n hostname: options.hostname,\n overrideGlobalObjects: options.overrideGlobalObjects,\n autoCleanupIncoming: options.autoCleanupIncoming\n });\n const createServer = options.createServer || createServerHTTP;\n const server = createServer(options.serverOptions || {}, requestListener);\n return server;\n};\nvar serve = (options, listeningListener) => {\n const server = createAdaptorServer(options);\n server.listen(options?.port ?? 3e3, options.hostname, () => {\n const serverInfo = server.address();\n listeningListener && listeningListener(serverInfo);\n });\n return server;\n};\nexport {\n RequestError,\n createAdaptorServer,\n getRequestListener,\n serve\n};\n","/**\n * External APIs' app fakes, served for `gkm dev`.\n *\n * An image fake runs with the other containers. An app fake is a fetch handler\n * in `test/fakes/<id>.ts`, and nothing runs it unless this does: each one\n * listens on the port its key was allocated, which is the port the stage's\n * `<ID>_URL` already names.\n */\n\nimport { pathToFileURL } from 'node:url';\nimport type { Fake } from '@geekmidas/constructs/external-api';\nimport { type ServerType, serve } from '@hono/node-server';\nimport { fakeKey } from '../reconcile/containers.js';\nimport type { LocalFake } from '../reconcile/fakes.js';\nimport type { PortAssignments } from '../reconcile/ports.js';\n\n/** One app fake, listening. */\nexport interface ServedFake {\n\tid: string;\n\tport: number;\n\tserver: ServerType;\n}\n\n/**\n * Serve every app fake on its allocated port. Image fakes are skipped — their\n * containers are already up.\n */\nexport async function serveFakes(\n\tfakes: Readonly<Record<string, LocalFake>>,\n\tports: PortAssignments,\n): Promise<ServedFake[]> {\n\tconst served: ServedFake[] = [];\n\n\tfor (const [id, local] of Object.entries(fakes)) {\n\t\tif (local.image) continue;\n\n\t\tconst port = ports[fakeKey(id)];\n\t\tif (port === undefined) continue;\n\n\t\t// Read by `readFakes` already, so the module is known to be a fake.\n\t\tconst module = (await import(pathToFileURL(local.file).href)) as {\n\t\t\tdefault: Extract<Fake, { kind: 'app' }>;\n\t\t};\n\t\tconst { handler } = module.default;\n\t\tconst server = serve({ fetch: (request) => handler.fetch(request), port });\n\t\tserved.push({ id, port, server });\n\t}\n\n\treturn served;\n}\n\n/** Stop every served fake. */\nexport function closeFakes(served: readonly ServedFake[]): void {\n\tfor (const { server } of served) server.close();\n}\n","import { spawn } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { imageBuildCredentials, isImageBuild } from './imageBuild';\n\nconst logger = console;\n\n/** `gkm exec` was given nothing to run. */\nexport class NoCommandSpecified extends Error {\n\tconstructor() {\n\t\tsuper('No command specified. Usage: gkm exec -- <command>');\n\t\tthis.name = 'NoCommandSpecified';\n\t}\n}\n\n/**\n * Options for the exec command.\n */\nexport interface ExecOptions {\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Run a command with secrets injected into Credentials.\n * Uses Node's --import flag to preload a script that populates Credentials\n * before the command loads any modules that depend on them.\n *\n * @example\n * ```bash\n * gkm exec -- npx @better-auth/cli migrate\n * gkm exec -- npx prisma migrate dev\n * ```\n */\nexport async function execCommand(\n\tcommandArgs: string[],\n\toptions: ExecOptions = {},\n): Promise<void> {\n\tconst cwd = options.cwd ?? process.cwd();\n\n\tif (!commandArgs[0]) {\n\t\tthrow new NoCommandSpecified();\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials: loads secrets, resolves Docker ports, rewrites URLs,\n\t// injects dependency URLs. Uses readonly port mode (no probing for new ports).\n\t//\n\t// Inside an image build there is none of that to do: the build args are the\n\t// stage's public values, and nothing on a developer's machine is reachable.\n\tconst { credentials, secretsJsonPath, appName } = isImageBuild()\n\t\t? await imageBuildEntry(cwd)\n\t\t: await prepareEntryCredentials({ cwd });\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName}`);\n\t}\n\n\tconst secretCount = Object.keys(credentials).filter(\n\t\t(k) => k !== 'PORT',\n\t).length;\n\tif (secretCount > 0 && !isImageBuild()) {\n\t\tlogger.log(`🔐 Loaded ${secretCount} secret(s)`);\n\t}\n\n\t// Create preload script that injects Credentials\n\t// Written as .mjs (plain ESM) so it doesn't need tsx — this avoids\n\t// breaking frameworks like Next.js whose workers inherit NODE_OPTIONS.\n\tconst preloadDir = join(cwd, '.gkm');\n\tawait mkdir(preloadDir, { recursive: true });\n\tconst preloadPath = join(preloadDir, 'credentials-preload.mjs');\n\tawait createCredentialsPreload(preloadPath, secretsJsonPath);\n\n\t// Build command\n\tconst [cmd, ...args] = commandArgs as [string, ...string[]];\n\n\tlogger.log(`🚀 Running: ${[cmd, ...args].join(' ')}`);\n\n\t// Build NODE_OPTIONS for the child process.\n\t// Strip any --import flags from the inherited NODE_OPTIONS — the gkm binary\n\t// adds --import=tsx for itself, but the spawned command (e.g. next, prisma)\n\t// doesn't need it and it breaks frameworks that spawn their own workers.\n\tconst existingNodeOptions = (process.env.NODE_OPTIONS ?? '')\n\t\t.replace(/--import[= ]\\S+/g, '')\n\t\t.trim();\n\tconst preloadImport = `--import=${preloadPath}`;\n\n\tconst nodeOptions = [existingNodeOptions, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Spawn the command with secrets in both:\n\t// 1. Environment variables (for tools that read process.env directly)\n\t// 2. Preload script (for tools that use Credentials object)\n\tconst child = spawn(cmd, args, {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...credentials, // Inject secrets as env vars\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for the command to complete\n\tconst exitCode = await new Promise<number>((resolve) => {\n\t\tchild.on('close', (code: number | null) => resolve(code ?? 0));\n\t\tchild.on('error', (error: Error) => {\n\t\t\tlogger.error(`Failed to run command: ${error.message}`);\n\t\t\tresolve(1);\n\t\t});\n\t});\n\n\tif (exitCode !== 0) {\n\t\tprocess.exit(exitCode);\n\t}\n}\n\n/**\n * `gkm exec` inside an image build: the public values the Dockerfile's build\n * args set, written where the preload reads them. No workspace is loaded, no\n * secret read and no address resolved.\n */\nasync function imageBuildEntry(cwd: string): Promise<{\n\tcredentials: Record<string, string>;\n\tsecretsJsonPath: string;\n\tappName?: string;\n}> {\n\tconst credentials = imageBuildCredentials();\n\tlogger.log(\n\t\t`🐳 Image build: ${Object.keys(credentials).length} public value(s) from the build args`,\n\t);\n\tconst dir = join(cwd, '.gkm');\n\tawait mkdir(dir, { recursive: true });\n\tconst secretsJsonPath = join(dir, 'image-build-env.json');\n\tawait writeFile(secretsJsonPath, JSON.stringify(credentials, null, 2));\n\treturn { credentials, secretsJsonPath };\n}\n","import { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport chokidar from 'chokidar';\nimport fg from 'fast-glob';\nimport { appPackageName, buildApp, turboFilters } from '../build/index';\nimport type {\n\tNormalizedHooksConfig,\n\tNormalizedProductionConfig,\n\tNormalizedTelescopeConfig,\n} from '../build/types';\nimport {\n\tloadAppConfig,\n\tloadWorkspaceConfig,\n\tNotABackendApp,\n\tNotInAnApp,\n\tparseModuleConfig,\n} from '../config';\nimport {\n\tcreateEntryWrapper,\n\tfindAvailablePort,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadSecretsForApp,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { resolveOpenApiConfig } from '../openapi';\nimport { withOwningTsconfigJsx } from '../owningTsconfigJsx.js';\nimport { describeServices } from '../reconcile/containers.js';\nimport { FAKE_ENV, reconcileWorkspace } from '../reconcile/workspace.js';\nimport { toEmbeddableSecrets } from '../secrets/storage.js';\nimport { FileSecretsStore, secretsStoreFor } from '../secrets/store.js';\nimport { ensureTrusted } from '../trust/index.js';\nimport type { GkmConfig, Runtime, TelescopeConfig } from '../types';\nimport {\n\tcacheBackendFor,\n\teventsBackendFor,\n\tproviderOf,\n} from '../workspace/backends.js';\nimport { appKey } from '../workspace/derive.js';\nimport {\n\ttype FrontendFramework,\n\tgetAppBuildOrder,\n\ttype MobileFramework,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport {\n\tAPP_TAG_ENV,\n\ttype AppRunning,\n\tappTag,\n\tassignAppPorts,\n\tdescribeHolder,\n\tholderOf,\n\twithAppPorts,\n} from './appPorts.js';\nimport {\n\ttype AppStatus,\n\tDISCOVERY_QUIET_ENV,\n\ttype DiscoverySession,\n\tdataApisOf,\n\tdiscoveryPort,\n\tjoinDiscovery,\n} from './discovery.js';\nimport { closeFakes, serveFakes } from './fakes.js';\n\n// Re-export shared utilities from credentials module so existing imports\n// from '../dev' or '../dev/index' continue to work.\nexport {\n\tcreateCredentialsPreload,\n\tcreateEntryWrapper,\n\ttype EntryCredentialsResult,\n\tfindAvailablePort,\n\tfindSecretsRoot,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadPortState,\n\tloadSecretsForApp,\n\ttype PortState,\n\tprepareEntryCredentials,\n\tsavePortState,\n} from '../credentials';\n\n// Re-export execCommand from its own module\nexport { type ExecOptions, execCommand } from '../exec';\n\nconst logger = console;\n\n/**\n * Normalize telescope configuration\n * @internal Exported for testing\n */\nexport function normalizeTelescopeConfig(\n\tconfig: GkmConfig['telescope'],\n): NormalizedTelescopeConfig | undefined {\n\tif (config === false) {\n\t\treturn undefined;\n\t}\n\n\t// Handle string path (e.g., './src/config/telescope')\n\tif (typeof config === 'string') {\n\t\tconst { path: telescopePath, importPattern: telescopeImportPattern } =\n\t\t\tparseModuleConfig(config, 'telescope');\n\n\t\treturn {\n\t\t\tenabled: true,\n\t\t\ttelescopePath,\n\t\t\ttelescopeImportPattern,\n\t\t\tpath: '/__telescope',\n\t\t\tignore: [],\n\t\t\trecordBody: true,\n\t\t\tmaxEntries: 1000,\n\t\t\twebsocket: true,\n\t\t};\n\t}\n\n\t// Default to enabled in development mode\n\tconst isEnabled =\n\t\tconfig === true || config === undefined || config.enabled !== false;\n\n\tif (!isEnabled) {\n\t\treturn undefined;\n\t}\n\n\tconst telescopeConfig: TelescopeConfig =\n\t\ttypeof config === 'object' ? config : {};\n\n\treturn {\n\t\tenabled: true,\n\t\tpath: telescopeConfig.path ?? '/__telescope',\n\t\tignore: telescopeConfig.ignore ?? [],\n\t\trecordBody: telescopeConfig.recordBody ?? true,\n\t\tmaxEntries: telescopeConfig.maxEntries ?? 1000,\n\t\twebsocket: telescopeConfig.websocket ?? true,\n\t};\n}\n\n/**\n * Normalize hooks configuration\n * @internal Exported for testing\n */\nexport function normalizeHooksConfig(\n\tconfig: GkmConfig['hooks'],\n\tcwd: string = process.cwd(),\n): NormalizedHooksConfig | undefined {\n\tif (!config?.server) {\n\t\treturn undefined;\n\t}\n\n\t// Resolve the path (handle .ts extension)\n\tconst serverPath = config.server.endsWith('.ts')\n\t\t? config.server\n\t\t: `${config.server}.ts`;\n\n\tconst resolvedPath = resolve(cwd, serverPath);\n\n\treturn {\n\t\tserverHooksPath: resolvedPath,\n\t};\n}\n\n/**\n * What a `--production` build is.\n *\n * Background work — queues polled, crons scheduled, subscribers drained — is\n * included here, and `buildApp` takes it back out when the app serves a\n * RestApi: an API's image answers HTTP and nothing else, and that work belongs\n * to a Worker. The build still writes their files on every server build.\n *\n * @internal Exported for testing\n */\nexport function normalizeProductionConfig(\n\tcliProduction: boolean,\n): NormalizedProductionConfig | undefined {\n\tif (!cliProduction) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tenabled: true,\n\t\tbundle: true,\n\t\tminify: true,\n\t\thealthCheck: '/health',\n\t\tgracefulShutdown: true,\n\t\texternal: [],\n\t\tsubscribers: 'include',\n\t\topenapi: false,\n\t};\n}\n\nexport interface DevOptions {\n\tport?: number;\n\tportExplicit?: boolean;\n\tenableOpenApi?: boolean;\n\t/** Specific app to run in workspace mode (default: all apps) */\n\tapp?: string;\n\t/** Filter apps by pattern (passed to turbo --filter) */\n\tfilter?: string;\n\t/** Entry file to run (bypasses gkm config) */\n\tentry?: string;\n\t/** Watch for file changes (default: true with --entry) */\n\twatch?: boolean;\n\t/** Apply pending migrations before the apps start. */\n\tmigrate?: boolean;\n\t/** Migrate, then run the seeds, before the apps start. */\n\tseed?: boolean;\n\t/**\n\t * Call each external API's fake (`test/fakes/<id>.ts`) instead of the\n\t * provider. Without it an external API is the real one, at its URL for the\n\t * local stage, with the local stage's own credentials.\n\t */\n\tfake?: boolean;\n\t/**\n\t * `false` (`--no-subscribers`) runs no topic subscribers. Every declared\n\t * subscriber runs otherwise — fan-out is the default, opting out is this.\n\t */\n\tsubscribers?: boolean;\n}\n\n/** Read by the generated server: no subscriber is subscribed or polled. */\nexport const SUBSCRIBERS_ENV = 'GKM_SUBSCRIBERS';\n\nexport async function devCommand(options: DevOptions): Promise<void> {\n\t// Set on this process, so the server it starts — directly or through turbo\n\t// — inherits it.\n\tif (options.subscribers === false) process.env[SUBSCRIBERS_ENV] = 'off';\n\n\t// Handle --entry mode: run any file with secret injection\n\tif (options.entry) {\n\t\treturn entryDevCommand(options);\n\t}\n\n\t// Load default .env file BEFORE loading config\n\t// This ensures env vars are available when config and its dependencies are loaded\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// The app whose configured path holds this directory. Anywhere else, the\n\t// workspace runs: turbo starts each app's own `gkm dev`, in its folder.\n\tconst appConfig = await loadAppConfig().catch((error: unknown) => {\n\t\tif (error instanceof NotInAnApp || error instanceof NotABackendApp) {\n\t\t\treturn undefined;\n\t\t}\n\t\tthrow error;\n\t});\n\n\tif (!appConfig) {\n\t\t// Discovery imports every construct and route module — the longest\n\t\t// silence of a start, before anything else can be said.\n\t\tlogger.log('🔎 Reading gkm.config.ts and the constructs');\n\t\tconst { workspace: everything } = await loadWorkspaceConfig();\n\t\treturn workspaceDevCommand(everything, options);\n\t}\n\n\tconst config: GkmConfig = appConfig.gkmConfig;\n\tconst appRoot = appConfig.appRoot;\n\tconst secretsRoot = appConfig.workspaceRoot; // Where .gkm/secrets/ lives\n\tconst workspaceAppName = appConfig.appName;\n\t// The same rule the workspace start applies, for this app alone — run on\n\t// its own, it moves off another project's port too. Under the workspace\n\t// start its port was just checked free, so it stays put.\n\tconst assigned = await assignAppPorts(\n\t\tappConfig.workspace,\n\t\t[workspaceAppName],\n\t\t{\n\t\t\tfree: isPortAvailable,\n\t\t\tholder: holderOf,\n\t\t},\n\t);\n\tif (assigned.running.length > 0) {\n\t\tthrow new WorkspacePortsInUse(assigned.running);\n\t}\n\tfor (const { app, from, to, holder } of assigned.moved) {\n\t\tlogger.log(\n\t\t\t`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`,\n\t\t);\n\t}\n\tconst workspace: NormalizedWorkspace = withAppPorts(\n\t\tappConfig.workspace,\n\t\tassigned.ports,\n\t);\n\tconst workspaceAppPort =\n\t\tassigned.ports[workspaceAppName] ?? appConfig.app.port;\n\t// Tagged, so a later start can tell this app's server from another\n\t// project's on the same port. The server is spawned from this process and\n\t// inherits it, and so does anything it forks.\n\tprocess.env[APP_TAG_ENV] = appTag(appConfig.workspaceRoot, workspaceAppName);\n\n\t// An app with an entry point (a non-gkm app like better-auth) runs it.\n\tif (appConfig.app.entry) {\n\t\tlogger.log(`📄 Using entry point: ${appConfig.app.entry}`);\n\t\treturn entryDevCommand({\n\t\t\t...options,\n\t\t\tentry: appConfig.app.entry,\n\t\t\tport: workspaceAppPort,\n\t\t\tportExplicit: true,\n\t\t});\n\t}\n\n\t// Load any additional env files specified in config\n\tif (config.env) {\n\t\tconst { loaded, missing } = loadEnvFiles(config.env, appRoot);\n\t\tif (loaded.length > 0) {\n\t\t\tlogger.log(`📦 Loaded env: ${loaded.join(', ')}`);\n\t\t}\n\t\tif (missing.length > 0) {\n\t\t\tlogger.warn(`⚠️ Missing env files: ${missing.join(', ')}`);\n\t\t}\n\t}\n\n\t// Normalize telescope configuration\n\tconst telescope = normalizeTelescopeConfig(config.telescope);\n\n\t// Normalize hooks configuration\n\tconst hooks = normalizeHooksConfig(config.hooks, appRoot);\n\n\t// Resolve OpenAPI configuration\n\tconst openApiConfig = resolveOpenApiConfig(config);\n\tconst enableOpenApi = openApiConfig.enabled;\n\n\t// The build's own pipeline, for the server target: what dev runs is what\n\t// `gkm build` would have generated, never a second reading of the same\n\t// constructs.\n\t// Quietly: the build's progress — every count, every generated file — is\n\t// `gkm build`'s output, and repeated on every start and rebuild it buried\n\t// the one line dev has to say. Warnings and errors still print.\n\tconst build = (bustCache = false) =>\n\t\tquietly(() =>\n\t\t\tbuildApp({\n\t\t\t\tconfig,\n\t\t\t\t// Where a surface's `path` is measured from, so the build can tell\n\t\t\t\t// which surface this app serves.\n\t\t\t\tworkspaceRoot: workspace?.root ?? secretsRoot,\n\t\t\t\tappRoot,\n\t\t\t\ttarget: 'server',\n\t\t\t\tenableOpenApi,\n\t\t\t\tcacheBackend: cacheBackendFor(providerOf(workspace ?? config)),\n\t\t\t\t// The local stage's broker: the target's, which the dev stack runs.\n\t\t\t\teventsBackend: eventsBackendFor(providerOf(workspace ?? config)),\n\t\t\t\ttelescope,\n\t\t\t\tdatabaseApi: true,\n\t\t\t\thooks,\n\t\t\t\tskipBundle: true,\n\t\t\t\tbustCache,\n\t\t\t\tserveEmpty: true,\n\t\t\t}),\n\t\t);\n\n\t// Build initial version\n\tlogger.log(`🔨 Building ${workspaceAppName ?? 'the app'}`);\n\tconst initial = await build();\n\n\t// Determine runtime (default to node)\n\tconst runtime: Runtime = config.runtime ?? 'node';\n\n\t// Load secrets for dev mode, resolve every declared address, and write to\n\t// JSON file\n\tlet secretsJsonPath: string | undefined;\n\tlet publicUrl: string | undefined;\n\tlet manifest: ConstructManifest | undefined;\n\t// The local stage's store, which is always the file.\n\tconst appSecrets = await loadSecretsForApp(\n\t\tworkspace\n\t\t\t? await secretsStoreFor(workspace, config.stages.local)\n\t\t\t: new FileSecretsStore(secretsRoot),\n\t\tconfig.stages.local,\n\t\tworkspaceAppName,\n\t);\n\n\tif (workspace) {\n\t\t// The same reconcile `gkm setup` and the workspace dev path run: derive\n\t\t// the containers from what the app declares, start them, create what the\n\t\t// URLs name, and inject those URLs.\n\t\tconst reconciled = await reconcileWorkspace(workspace, {\n\t\t\tstage: workspace.stages.local,\n\t\t\t...(options.fake ? { fake: true } : {}),\n\t\t\tprogress: (message) => logger.log(message),\n\t\t});\n\n\t\t// Every start, not only the one that changed something: where the inbox\n\t\t// is matters on the hundredth `gkm dev` as much as the first.\n\t\tif (reconciled.services.length > 0) {\n\t\t\tlogger.log('🐳 Services');\n\t\t\tfor (const line of describeServices(reconciled.services)) {\n\t\t\t\tlogger.log(line);\n\t\t\t}\n\t\t}\n\n\t\t// Declared URLs win over anything sniffed or stored — the manifest is the\n\t\t// statement of what exists.\n\t\tObject.assign(appSecrets, reconciled.env);\n\n\t\t// This app's own address behind the edge, for the ready line.\n\t\tconst own = reconciled.plan.resources.find(\n\t\t\t(r) =>\n\t\t\t\t(r.kind === 'rest-api' || r.kind === 'site') &&\n\t\t\t\tappKey(r.id) === workspaceAppName,\n\t\t);\n\t\tpublicUrl = own ? reconciled.env[own.envKey] : undefined;\n\t\tmanifest = reconciled.manifest;\n\t}\n\n\tif (Object.keys(appSecrets).length > 0) {\n\t\tconst secretsDir = join(secretsRoot, '.gkm');\n\t\tawait mkdir(secretsDir, { recursive: true });\n\t\tconst secretsFileName = workspaceAppName\n\t\t\t? `dev-secrets-${workspaceAppName}.json`\n\t\t\t: 'dev-secrets.json';\n\t\tsecretsJsonPath = join(secretsDir, secretsFileName);\n\t\tawait writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));\n\t}\n\n\t// Start the dev server\n\t// Priority: explicit --port option > workspace app port > default 3000\n\tconst devServer = new DevServer(\n\t\toptions.port ?? workspaceAppPort ?? 3000,\n\t\t// A workspace's port is as fixed as one passed with --port: every other\n\t\t// app's URL, CORS list and cookie domain names it. Drifting to the next\n\t\t// free port served the app where nothing points — and in a workspace the\n\t\t// next free port is usually another app's.\n\t\toptions.portExplicit ?? workspaceAppPort !== undefined,\n\t\tenableOpenApi,\n\t\ttelescope,\n\t\tinitial.databaseApi,\n\t\truntime,\n\t\tappRoot,\n\t\tsecretsJsonPath,\n\t\tinitial.selfServing !== undefined,\n\t);\n\n\tdevServer.label = workspaceAppName ?? 'server';\n\tdevServer.publicUrl = publicUrl;\n\tawait devServer.start();\n\n\t// Said to the machine's discovery endpoint, so a console can find this app\n\t// and read its data APIs without being told the port.\n\tconst discovery = await joinDiscovery({\n\t\trole: 'app',\n\t\tport: discoveryPort(workspace.dev),\n\t\tworkspace: {\n\t\t\tname: workspace.name,\n\t\t\troot: workspace.root,\n\t\t\tstage: workspace.stages.local,\n\t\t},\n\t\tallowedOrigins: workspace.dev?.allowedOrigins ?? [],\n\t\t...(manifest ? { manifest } : {}),\n\t\tapps: [\n\t\t\t{\n\t\t\t\tname: workspaceAppName,\n\t\t\t\ttype: 'backend',\n\t\t\t\tport: devServer.port,\n\t\t\t\t...(publicUrl ? { publicUrl } : {}),\n\t\t\t\tstatus: 'ready',\n\t\t\t\treloads: 0,\n\t\t\t\tdataApis: dataApisOf({\n\t\t\t\t\tselfServing: devServer.selfServing,\n\t\t\t\t\ttelescopePath: telescope?.path,\n\t\t\t\t\tdatabaseApi: initial.databaseApi,\n\t\t\t\t\topenApi: enableOpenApi,\n\t\t\t\t}),\n\t\t\t},\n\t\t],\n\t});\n\t// Under a workspace's `gkm dev`, which printed it once for every app.\n\tif (!process.env[DISCOVERY_QUIET_ENV]) announce(discovery);\n\tdevServer.onStatus = (status) =>\n\t\tdiscovery.updateApp(workspaceAppName, (app) => ({\n\t\t\t...app,\n\t\t\tstatus,\n\t\t\tport: devServer.port,\n\t\t\treloads:\n\t\t\t\tapp.status === 'reloading' && status === 'ready'\n\t\t\t\t\t? app.reloads + 1\n\t\t\t\t\t: app.reloads,\n\t\t}));\n\n\t// Watch for file changes\n\t// Get hooks file path for watching\n\tconst hooksFileParts = config.hooks?.server?.split('#');\n\tconst hooksFile = hooksFileParts?.[0];\n\n\t// One glob to watch, the same one the build loads from. The logger and the\n\t// environment parser are inside it — they are constructs now, not module\n\t// paths beside the code.\n\tconst watchPatterns = [\n\t\tconfig.constructs,\n\t\t// Add hooks file to watch list\n\t\t...(hooksFile\n\t\t\t? [hooksFile.endsWith('.ts') ? hooksFile : `${hooksFile}.ts`]\n\t\t\t: []),\n\t]\n\t\t.flat()\n\t\t.filter((p): p is string => typeof p === 'string');\n\n\t// Relative to the app, which the watcher runs from: the construct globs\n\t// arrive absolute from the config, and a relative path is what the change\n\t// line prints.\n\tconst normalizedPatterns = watchPatterns.map((p) =>\n\t\tisAbsolute(p) ? relative(appRoot, p) : p.replace(/^\\.\\//, ''),\n\t);\n\n\t// Resolve glob patterns to actual files (chokidar 4.x doesn't support globs)\n\tconst resolvedFiles = await fg(normalizedPatterns, {\n\t\tcwd: appRoot,\n\t\tabsolute: false,\n\t\tonlyFiles: true,\n\t});\n\n\t// Also watch the directories for new files\n\tconst dirsToWatch = [\n\t\t...new Set(\n\t\t\tresolvedFiles.map((f) => {\n\t\t\t\tconst parts = f.split('/');\n\t\t\t\treturn parts.slice(0, -1).join('/');\n\t\t\t}),\n\t\t),\n\t];\n\n\tconst watcher = chokidar.watch([...resolvedFiles, ...dirsToWatch], {\n\t\tignored: /(^|[/\\\\])\\../, // ignore dotfiles\n\t\tpersistent: true,\n\t\tignoreInitial: true,\n\t\tcwd: appRoot,\n\t});\n\n\twatcher.on('error', (error) => {\n\t\tlogger.error('❌ Watcher error:', error);\n\t});\n\n\tlet rebuildTimeout: NodeJS.Timeout | null = null;\n\n\twatcher.on('change', async (path) => {\n\t\tlogger.log(`🔄 ${path} changed — rebuilding`);\n\n\t\t// Debounce rebuilds\n\t\tif (rebuildTimeout) {\n\t\t\tclearTimeout(rebuildTimeout);\n\t\t}\n\n\t\trebuildTimeout = setTimeout(async () => {\n\t\t\ttry {\n\t\t\t\t// Bust the module cache: the edit is what the rebuild is for.\n\t\t\t\tconst rebuilt = await build(true);\n\n\t\t\t\tdevServer.selfServing = rebuilt.selfServing !== undefined;\n\t\t\t\tawait devServer.restart();\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`❌ Rebuild failed: ${err.message}`);\n\t\t\t\tif (err.stack) {\n\t\t\t\t\tlogger.error(err.stack);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 300);\n\t});\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\n\t\t// Use sync-style shutdown to ensure it completes before exit\n\t\tPromise.all([watcher.close(), devServer.stop(), discovery.leave()])\n\t\t\t.catch((err) => {\n\t\t\t\tlogger.error('Error during shutdown:', err);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tprocess.exit(0);\n\t\t\t});\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n}\n\n/**\n * Check for port conflicts across all apps.\n * Returns list of conflicts if any ports are duplicated.\n * @internal Exported for testing\n */\nexport function checkPortConflicts(\n\tworkspace: NormalizedWorkspace,\n): { app1: string; app2: string; port: number }[] {\n\tconst conflicts: { app1: string; app2: string; port: number }[] = [];\n\tconst portToApp = new Map<number, string>();\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tconst existingApp = portToApp.get(app.port);\n\t\tif (existingApp) {\n\t\t\tconflicts.push({ app1: existingApp, app2: appName, port: app.port });\n\t\t} else {\n\t\t\tportToApp.set(app.port, appName);\n\t\t}\n\t}\n\n\treturn conflicts;\n}\n\n/**\n * A framework the dev server starts an app with.\n *\n * Expo is a mobile framework, not a frontend one, but it is detected and\n * validated here the same way — so the union is what this table is keyed by.\n * It used to be keyed by `FrontendFramework` alone, with the Expo entry typed\n * as an excess property and the one call site casting around it.\n */\ntype ClientFramework = FrontendFramework | MobileFramework;\n\n/**\n * Per-framework validation spec for the frameworks the dev server supports.\n */\ninterface FrontendFrameworkSpec {\n\tdisplayName: string;\n\tconfigFiles: string[];\n\tdependency: string;\n\tinstallCommand: string;\n}\n\nconst FRONTEND_FRAMEWORKS: Record<ClientFramework, FrontendFrameworkSpec> = {\n\tnextjs: {\n\t\tdisplayName: 'Next.js',\n\t\tconfigFiles: [\n\t\t\t'next.config.js',\n\t\t\t'next.config.ts',\n\t\t\t'next.config.mjs',\n\t\t\t'next.config.cjs',\n\t\t],\n\t\tdependency: 'next',\n\t\tinstallCommand: 'pnpm add next react react-dom',\n\t},\n\tremix: {\n\t\tdisplayName: 'Remix',\n\t\tconfigFiles: [\n\t\t\t'remix.config.js',\n\t\t\t'remix.config.mjs',\n\t\t\t'remix.config.ts',\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@remix-run/dev',\n\t\tinstallCommand: 'pnpm add -D @remix-run/dev',\n\t},\n\tvite: {\n\t\tdisplayName: 'Vite',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: 'vite',\n\t\tinstallCommand: 'pnpm add -D vite',\n\t},\n\t'tanstack-start': {\n\t\tdisplayName: 'TanStack Start',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@tanstack/react-start',\n\t\tinstallCommand: 'pnpm add @tanstack/react-start @tanstack/react-router',\n\t},\n\texpo: {\n\t\tdisplayName: 'Expo',\n\t\tconfigFiles: ['app.config.ts', 'app.config.js', 'app.json'],\n\t\tdependency: 'expo',\n\t\tinstallCommand: 'pnpm add expo',\n\t},\n};\n\n/** Whether a configured framework is one this table knows how to start. */\nfunction isClientFramework(\n\tframework: string | undefined,\n): framework is ClientFramework {\n\treturn framework !== undefined && framework in FRONTEND_FRAMEWORKS;\n}\n\n/**\n * Auto-detect the frontend framework by scanning package.json deps and config\n * files. Dependency match wins over config file match because deps are more\n * distinctive (a Remix app has both vite.config.ts AND @remix-run/dev).\n */\nfunction detectFrontendFramework(\n\tfullPath: string,\n\tdeps: Record<string, string>,\n): ClientFramework | undefined {\n\t// tanstack-start before vite/remix so its more specific dep wins; vite last\n\t// because plain vite is the fallback when neither nextjs/remix/tanstack match.\n\t// Order matters: more specific deps win over general ones.\n\t// expo first (own dep), then tanstack-start (uses vite), remix (uses vite),\n\t// nextjs (own dep), and plain vite last as the fallback.\n\tconst order: ClientFramework[] = [\n\t\t'expo',\n\t\t'tanstack-start',\n\t\t'nextjs',\n\t\t'remix',\n\t\t'vite',\n\t];\n\tfor (const name of order) {\n\t\tif (deps[FRONTEND_FRAMEWORKS[name].dependency]) {\n\t\t\treturn name;\n\t\t}\n\t}\n\tfor (const name of order) {\n\t\tconst hasConfig = FRONTEND_FRAMEWORKS[name].configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (hasConfig) {\n\t\t\treturn name;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * Validation result for a frontend app.\n */\nexport interface FrontendValidationResult {\n\tappName: string;\n\tvalid: boolean;\n\terrors: string[];\n\twarnings: string[];\n}\n\n/**\n * Validate a frontend app configuration.\n *\n * If `framework` is provided, validates strictly against that framework's\n * expected config file and dependency. Otherwise auto-detects the framework\n * from package.json and config files. If no recognized framework is found, the\n * app is allowed through with a warning provided it has a `dev` script.\n *\n * @internal Exported for testing\n */\nexport async function validateFrontendApp(\n\tappName: string,\n\tappPath: string,\n\tworkspaceRoot: string,\n\tframework?: ClientFramework,\n): Promise<FrontendValidationResult> {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst fullPath = join(workspaceRoot, appPath);\n\n\tconst packageJsonPath = join(fullPath, 'package.json');\n\tif (!existsSync(packageJsonPath)) {\n\t\terrors.push(\n\t\t\t`package.json not found at ${appPath}. Run: pnpm init in the app directory.`,\n\t\t);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tlet pkg: {\n\t\tdependencies?: Record<string, string>;\n\t\tdevDependencies?: Record<string, string>;\n\t\tscripts?: Record<string, string>;\n\t};\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tpkg = require(packageJsonPath);\n\t} catch {\n\t\terrors.push(`Failed to read package.json at ${packageJsonPath}`);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tconst deps: Record<string, string> = {\n\t\t...pkg.dependencies,\n\t\t...pkg.devDependencies,\n\t};\n\n\tconst resolvedFramework =\n\t\tframework ?? detectFrontendFramework(fullPath, deps);\n\n\tif (resolvedFramework) {\n\t\tconst spec = FRONTEND_FRAMEWORKS[resolvedFramework];\n\t\tconst hasConfig = spec.configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (!hasConfig) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} config file not found. Expected one of: ${spec.configFiles.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!deps[spec.dependency]) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} not found in dependencies. Run: ${spec.installCommand}`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\twarnings.push(\n\t\t\t'No recognized frontend framework detected (Next.js, Vite, Remix). ' +\n\t\t\t\t'The app will run via its \"dev\" script. Set `framework` in your app config to enable strict validation.',\n\t\t);\n\t}\n\n\tif (!pkg.scripts?.dev) {\n\t\tif (resolvedFramework) {\n\t\t\twarnings.push(\n\t\t\t\t'No \"dev\" script found in package.json. Turbo expects a \"dev\" script to run.',\n\t\t\t);\n\t\t} else {\n\t\t\terrors.push(\n\t\t\t\t'No \"dev\" script found in package.json. Without a recognized framework or a dev script, there is nothing to run.',\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tappName,\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n/**\n * Validate all frontend apps in the workspace.\n * Returns validation results for each frontend app.\n * @internal Exported for testing\n */\nexport async function validateFrontendApps(\n\tworkspace: NormalizedWorkspace,\n): Promise<FrontendValidationResult[]> {\n\tconst results: FrontendValidationResult[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'web') {\n\t\t\tconst result = await validateFrontendApp(\n\t\t\t\tappName,\n\t\t\t\tapp.path,\n\t\t\t\tworkspace.root,\n\t\t\t\tisClientFramework(app.framework) ? app.framework : undefined,\n\t\t\t);\n\t\t\tresults.push(result);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Load secrets for development stage.\n * Returns env vars to inject, or empty object if secrets not configured/found.\n * @internal Exported for testing\n */\nexport async function loadDevSecrets(\n\tworkspace: NormalizedWorkspace,\n): Promise<Record<string, string>> {\n\t// Check if secrets are enabled in workspace config\n\tif (!workspace.secrets.enabled) {\n\t\treturn {};\n\t}\n\n\tconst stage = workspace.stages.local;\n\tconst secrets = await (await secretsStoreFor(workspace, stage)).read(stage);\n\tif (secrets) return toEmbeddableSecrets(secrets);\n\n\t// Nothing to warn about: the local stage's own secrets and every address are\n\t// derived by reconcile. A stored stage only adds what nothing can derive — a\n\t// third party's key — and a construct missing one says so when it is read.\n\treturn {};\n}\n\n/**\n * Workspace dev command - orchestrates multi-app development using Turbo.\n *\n * Flow:\n * 1. Check for port conflicts\n * 2. Start docker-compose services (db, cache, mail)\n * 3. Generate dependency URLs ({APP_NAME}_URL)\n * 4. Spawn turbo run dev with injected env vars\n */\nasync function workspaceDevCommand(\n\tconfigured: NormalizedWorkspace,\n\toptions: DevOptions,\n): Promise<void> {\n\t// Each app's local port, before anything reads one: the edge routes, every\n\t// address an app is handed, and the ready lines all follow it. An app whose\n\t// port another project holds moves; one this workspace already has running\n\t// is refused, since moving would start a second copy beside it.\n\tconst scoped = options.app\n\t\t? [options.app]\n\t\t: options.filter\n\t\t\t? []\n\t\t\t: Object.keys(configured.apps);\n\tconst assigned = await assignAppPorts(configured, scoped, {\n\t\tfree: isPortAvailable,\n\t\tholder: holderOf,\n\t});\n\tif (assigned.running.length > 0) {\n\t\tthrow new WorkspacePortsInUse(assigned.running);\n\t}\n\tfor (const { app, from, to, holder } of assigned.moved) {\n\t\tlogger.log(\n\t\t\t`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`,\n\t\t);\n\t}\n\tconst workspace = withAppPorts(configured, assigned.ports);\n\tconst appCount = Object.keys(workspace.apps).length;\n\tconst frontendApps = Object.entries(workspace.apps).filter(\n\t\t([_, app]) => app.type === 'web',\n\t);\n\n\t// Check for port conflicts\n\tconst conflicts = checkPortConflicts(workspace);\n\tif (conflicts.length > 0) {\n\t\tfor (const conflict of conflicts) {\n\t\t\tlogger.error(\n\t\t\t\t`❌ Port conflict: Apps \"${conflict.app1}\" and \"${conflict.app2}\" both use port ${conflict.port}`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(\n\t\t\t'Port conflicts detected. Please assign unique ports to each app.',\n\t\t);\n\t}\n\n\t// Validate frontend apps (Next.js setup)\n\tif (frontendApps.length > 0) {\n\t\tconst validationResults = await validateFrontendApps(workspace);\n\n\t\tlet hasErrors = false;\n\t\tfor (const result of validationResults) {\n\t\t\tif (!result.valid) {\n\t\t\t\thasErrors = true;\n\t\t\t\tlogger.error(\n\t\t\t\t\t`\\n❌ Frontend app \"${result.appName}\" validation failed:`,\n\t\t\t\t);\n\t\t\t\tfor (const error of result.errors) {\n\t\t\t\t\tlogger.error(` • ${error}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const warning of result.warnings) {\n\t\t\t\tlogger.warn(` ⚠️ ${result.appName}: ${warning}`);\n\t\t\t}\n\t\t}\n\n\t\tif (hasErrors) {\n\t\t\tthrow new Error(\n\t\t\t\t'Frontend app validation failed. Fix the issues above and try again.',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Frontend apps import each API's client from the workspace root's\n\t// `.gkm/client/` through their tsconfig alias\n\t// (`import { createApi } from '@myapp/client/api'`) — nothing is copied.\n\n\tconst rawSecrets = await loadDevSecrets(workspace);\n\n\t// Derive the containers from what the apps declare, start them, create what\n\t// the URLs name, and inject those URLs. Safe to do on every start because\n\t// the blast radius is this project's containers and `.gkm/`, and because the\n\t// converged case costs one hash and one health check.\n\tconst reconciled = await reconcileWorkspace(workspace, {\n\t\tstage: workspace.stages.local,\n\t\t...(options.fake ? { fake: true } : {}),\n\t\tprogress: (message) => logger.log(message),\n\t});\n\n\t// Every start, not only the one that changed something: where the inbox is\n\t// matters on the hundredth `gkm dev` as much as the first.\n\tif (reconciled.services.length > 0) {\n\t\tlogger.log('🐳 Services');\n\t\tfor (const line of describeServices(reconciled.services)) {\n\t\t\tlogger.log(line);\n\t\t}\n\t}\n\n\tconst secretsEnv: Record<string, string> = {\n\t\t...rawSecrets,\n\t\t...reconciled.env,\n\t};\n\n\t// Only with `--fake`, and here rather than in reconcile: every app's own\n\t// `gkm dev` reconciles too, and only this process — the one that outlives\n\t// them — may own the ports.\n\tconst fakes = options.fake\n\t\t? await serveFakes(reconciled.fakes, reconciled.ports)\n\t\t: [];\n\tfor (const { id, port } of fakes) {\n\t\tlogger.log(`🎭 ${id} fake: http://localhost:${port}`);\n\t}\n\n\t// Asked for, the databases are migrated (and seeded) before anything\n\t// starts, and a failure stops here. Otherwise pending migrations are only\n\t// reported, and a failure to check is only a warning: nothing about it\n\t// should keep the apps from starting.\n\tlogger.log(\n\t\toptions.migrate || options.seed\n\t\t\t? '🗄️ Migrating the databases'\n\t\t\t: '🗄️ Checking for pending migrations',\n\t);\n\tif (options.migrate || options.seed) {\n\t\tconst { prepareDevDatabases } = await import('../migrate/index.js');\n\t\tawait prepareDevDatabases(workspace, reconciled.env, {\n\t\t\tseed: !!options.seed,\n\t\t});\n\t} else {\n\t\tawait import('../migrate/index.js')\n\t\t\t.then(({ reportPendingMigrations }) =>\n\t\t\t\treportPendingMigrations(workspace, reconciled.env),\n\t\t\t)\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t});\n\t}\n\n\t// Where each app answers, behind the edge — the addresses the apps were just\n\t// given, rather than their ports.\n\tconst appUrls: Record<string, string> = {};\n\tfor (const resource of reconciled.plan.resources) {\n\t\tif (resource.kind !== 'rest-api' && resource.kind !== 'site') continue;\n\t\tconst address = reconciled.env[resource.envKey];\n\t\tif (address) appUrls[resource.id] = address;\n\t}\n\n\t// A browser trusts the edge's HTTPS addresses only once its authority is in\n\t// the system store. Asked here, once, rather than left for the first page\n\t// load to say \"your connection is not private\".\n\tconst firstUrl = Object.values(appUrls).find((url) =>\n\t\turl.startsWith('https://'),\n\t);\n\tif (firstUrl) await ensureTrusted(workspace.root, firstUrl);\n\n\t// Build turbo filter\n\tlet turboFilter: string[] = [];\n\tif (options.app) {\n\t\t// Run specific app\n\t\tif (!workspace.apps[options.app]) {\n\t\t\tconst appNames = Object.keys(workspace.apps).join(', ');\n\t\t\tthrow new Error(\n\t\t\t\t`App \"${options.app}\" not found. Available apps: ${appNames}`,\n\t\t\t);\n\t\t}\n\t\tturboFilter = [\n\t\t\t'--filter',\n\t\t\tappPackageName(workspace, options.app) ?? options.app,\n\t\t];\n\t} else if (options.filter) {\n\t\t// Use custom filter\n\t\tturboFilter = ['--filter', options.filter];\n\t} else {\n\t\t// Every app, by name. Left to infer its own scope at the workspace root,\n\t\t// turbo includes the root package — whose `dev` script is `gkm dev`,\n\t\t// which arrives here and starts turbo again, and every app twice over.\n\t\t// `gkm build` names its apps for the same reason.\n\t\tconst { filters, unpackaged } = turboFilters(workspace);\n\t\tturboFilter = filters.flatMap((name) => ['--filter', name]);\n\t\tif (unpackaged.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t`⚠️ No package.json with a name for: ${unpackaged.join(', ')} — turbo cannot run ${unpackaged.length === 1 ? 'it' : 'them'}.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Each app once: the address it is reached at, and the local port the edge\n\t// forwards it to.\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tconst width = Math.max(...buildOrder.map((name) => name.length));\n\tlogger.log(`\\n${workspace.name}: ${appCount} app(s)`);\n\tfor (const appName of buildOrder) {\n\t\tconst app = workspace.apps[appName];\n\t\tif (!app) continue;\n\t\t// A mobile app answers on its scheme, and a phone reaches this machine\n\t\t// at its LAN address — which is what to check when sign-in fails there.\n\t\tif (app.type === 'mobile') {\n\t\t\tconst own = reconciled.plan.resources.find(\n\t\t\t\t(r) => r.kind === 'mobile-app' && appKey(r.id) === appName,\n\t\t\t);\n\t\t\tconst scheme = own ? reconciled.env[own.envKey] : undefined;\n\t\t\tconst device = Object.entries(reconciled.env).find(([key]) =>\n\t\t\t\tkey.endsWith('_DEVICE_URL'),\n\t\t\t)?.[1];\n\t\t\tlogger.log(\n\t\t\t\t` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : 'mobile'}${device ? ` — devices reach ${new URL(device).hostname}` : ''}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst local = `http://localhost:${app.port}`;\n\t\tconst url = Object.entries(appUrls).find(\n\t\t\t([id]) => appKey(id) === appName,\n\t\t)?.[1];\n\t\tlogger.log(\n\t\t\t` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`,\n\t\t);\n\t}\n\tlogger.log('');\n\n\t// Find the config file path for GKM_CONFIG_PATH\n\tconst configFiles = ['gkm.config.ts', 'gkm.config.js', 'gkm.config.json'];\n\tlet configPath = '';\n\tfor (const file of configFiles) {\n\t\tconst fullPath = join(workspace.root, file);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconfigPath = fullPath;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Every app turbo starts, as this workspace lists them. Each backend app's\n\t// own `gkm dev` registers too, with its status and its data APIs.\n\tconst discovery = await joinDiscovery({\n\t\trole: 'workspace',\n\t\tport: discoveryPort(workspace.dev),\n\t\tworkspace: {\n\t\t\tname: workspace.name,\n\t\t\troot: workspace.root,\n\t\t\tstage: workspace.stages.local,\n\t\t},\n\t\tallowedOrigins: workspace.dev?.allowedOrigins ?? [],\n\t\t...(reconciled.manifest ? { manifest: reconciled.manifest } : {}),\n\t\tapps: buildOrder.flatMap((name) => {\n\t\t\tconst app = workspace.apps[name];\n\t\t\tif (!app) return [];\n\t\t\tconst publicUrl = Object.entries(appUrls).find(\n\t\t\t\t([id]) => appKey(id) === name,\n\t\t\t)?.[1];\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tport: app.port,\n\t\t\t\t\t...(publicUrl ? { publicUrl } : {}),\n\t\t\t\t\tstatus: 'starting' as const,\n\t\t\t\t\treloads: 0,\n\t\t\t\t\tdataApis: [],\n\t\t\t\t},\n\t\t\t];\n\t\t}),\n\t});\n\tannounce(discovery);\n\n\t// Prepare environment variables\n\t// Order matters: secrets first, then dependencies (dependencies can override)\n\tconst turboEnv: Record<string, string> = {\n\t\t...process.env,\n\t\t...secretsEnv,\n\t\tNODE_ENV: 'development',\n\t\t// Inject config path so child processes can find the workspace config\n\t\t...(configPath ? { GKM_CONFIG_PATH: configPath } : {}),\n\t\t// Each app reconciles again, and must point at the same fakes.\n\t\t...(options.fake ? { [FAKE_ENV]: '1' } : {}),\n\t\t// The connect URL was printed above; the apps need not repeat it.\n\t\t[DISCOVERY_QUIET_ENV]: '1',\n\t};\n\n\t// Spawn turbo run dev\n\tlogger.log(\n\t\t`🚀 Starting ${appCount} app(s) — each builds before it answers, and says so when it is ready`,\n\t);\n\n\tconst turboProcess = spawn('pnpm', ['turbo', 'run', 'dev', ...turboFilter], {\n\t\tcwd: workspace.root,\n\t\tstdio: 'inherit',\n\t\tenv: turboEnv,\n\t\tdetached: true,\n\t});\n\n\t// No file watcher needed — frontend apps import API clients directly\n\t// from backend packages via workspace dependencies.\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down workspace...');\n\t\tcloseFakes(fakes);\n\t\tvoid discovery.leave();\n\n\t\t// Kill turbo process group\n\t\tconst pid = turboProcess.pid;\n\t\tif (pid) {\n\t\t\ttry {\n\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\t// Process already dead\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Force kill after timeout if processes are still alive\n\t\tsetTimeout(() => {\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tprocess.exit(0);\n\t\t}, 3000);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Wait for turbo to exit\n\treturn new Promise((resolve, reject) => {\n\t\tturboProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Turbo error:', error);\n\t\t\treject(error);\n\t\t});\n\n\t\tturboProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0) {\n\t\t\t\treject(new Error(`Turbo exited with code ${code}`));\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Run any TypeScript file with secret injection.\n * Does not require gkm.config.ts.\n */\nasync function entryDevCommand(options: DevOptions): Promise<void> {\n\tconst { entry, watch = true } = options;\n\n\tif (!entry) {\n\t\tthrow new Error('--entry requires a file path');\n\t}\n\n\tconst entryPath = resolve(process.cwd(), entry);\n\n\tif (!existsSync(entryPath)) {\n\t\tthrow new Error(`Entry file not found: ${entryPath}`);\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials (loads workspace config, secrets, injects PORT)\n\t// Only pass explicitPort if --port was actually specified by the user\n\tconst { credentials, resolvedPort, secretsJsonPath, appName } =\n\t\tawait prepareEntryCredentials({\n\t\t\texplicitPort: options.portExplicit ? options.port : undefined,\n\t\t});\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName} (port ${resolvedPort})`);\n\t}\n\n\tlogger.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);\n\n\tif (Object.keys(credentials).length > 1) {\n\t\tlogger.log(\n\t\t\t`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`,\n\t\t);\n\t}\n\n\t// Create wrapper entry that injects secrets before importing user's file\n\tconst wrapperDir = join(process.cwd(), '.gkm');\n\tawait mkdir(wrapperDir, { recursive: true });\n\tconst wrapperPath = join(wrapperDir, 'entry-wrapper.ts');\n\tawait createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);\n\n\t// Start with tsx\n\tconst runner = new EntryRunner(wrapperPath, entryPath, watch, resolvedPort);\n\tawait runner.start();\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\t\trunner.stop();\n\t\tprocess.exit(0);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Keep the process alive\n\tawait new Promise(() => {});\n}\n\n/**\n * Runs and watches a TypeScript entry file using tsx.\n */\nclass EntryRunner {\n\tprivate childProcess: ChildProcess | null = null;\n\tprivate watcher: ReturnType<typeof chokidar.watch> | null = null;\n\tprivate isRunning = false;\n\n\tconstructor(\n\t\tprivate wrapperPath: string,\n\t\tprivate entryPath: string,\n\t\tprivate watch: boolean,\n\t\tprivate port: number,\n\t) {}\n\n\tasync start(): Promise<void> {\n\t\tawait this.runProcess();\n\n\t\tif (this.watch) {\n\t\t\t// Watch the entry file's directory for changes\n\t\t\tconst watchDir = dirname(this.entryPath);\n\n\t\t\tthis.watcher = chokidar.watch(watchDir, {\n\t\t\t\tignored: /(^|[/\\\\])\\../,\n\t\t\t\tpersistent: true,\n\t\t\t\tignoreInitial: true,\n\t\t\t});\n\n\t\t\tlet restartTimeout: NodeJS.Timeout | null = null;\n\n\t\t\tthis.watcher.on('change', (path) => {\n\t\t\t\tlogger.log(`📝 File changed: ${path}`);\n\n\t\t\t\t// Debounce restarts\n\t\t\t\tif (restartTimeout) {\n\t\t\t\t\tclearTimeout(restartTimeout);\n\t\t\t\t}\n\n\t\t\t\trestartTimeout = setTimeout(async () => {\n\t\t\t\t\tlogger.log('🔄 Restarting...');\n\t\t\t\t\tawait this.restart();\n\t\t\t\t}, 300);\n\t\t\t});\n\n\t\t\tlogger.log(`👀 Watching for changes in: ${watchDir}`);\n\t\t}\n\t}\n\n\tprivate async runProcess(): Promise<void> {\n\t\t// Pass PORT as environment variable\n\t\tconst env = {\n\t\t\t...process.env,\n\t\t\tPORT: String(this.port),\n\t\t\tNODE_OPTIONS: withOwningTsconfigJsx(process.env.NODE_OPTIONS),\n\t\t};\n\n\t\tthis.childProcess = spawn(\n\t\t\t...tsxCommand(dirname(this.wrapperPath), [this.wrapperPath]),\n\t\t\t{\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv,\n\t\t\t\tdetached: true,\n\t\t\t},\n\t\t);\n\n\t\tthis.isRunning = true;\n\n\t\tthis.childProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Process error:', error);\n\t\t});\n\n\t\tthis.childProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0 && code !== 143) {\n\t\t\t\t// 143 = SIGTERM\n\t\t\t\tlogger.error(`❌ Process exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t});\n\n\t\t// Give the process a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t\tif (this.isRunning) {\n\t\t\tlogger.log('');\n\t\t\tlogger.log(\n\t\t\t\t` \\x1b[32m✓ Ready\\x1b[0m at \\x1b[36mhttp://localhost:${this.port}\\x1b[0m`,\n\t\t\t);\n\t\t\tlogger.log('');\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tthis.stopProcess();\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\tawait this.runProcess();\n\t}\n\n\tstop(): void {\n\t\tthis.watcher?.close();\n\t\tthis.stopProcess();\n\t}\n\n\tprivate stopProcess(): void {\n\t\tif (this.childProcess && this.isRunning) {\n\t\t\tconst pid = this.childProcess.pid;\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.childProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\t}\n}\n\n/**\n * Generate the content of the dev server entry file (server.ts).\n * Uses dynamic import for createApp so Credentials are populated\n * before any app modules evaluate.\n * @internal Exported for testing\n */\nexport function generateServerEntryContent(options: {\n\tsecretsJsonPath?: string;\n\truntime?: Runtime;\n\tenableOpenApi?: boolean;\n\tappImportPath?: string;\n\t/**\n\t * `app.ts` is a surface serving itself — it exports the construct's own\n\t * `app`, with no `createApp` around it to start.\n\t */\n\tselfServing?: boolean;\n}): string {\n\tconst {\n\t\tsecretsJsonPath,\n\t\truntime = 'node',\n\t\tenableOpenApi = false,\n\t\tappImportPath = './app.js',\n\t\tselfServing = false,\n\t} = options;\n\n\t// Exit with the `gkm dev` that started this server. Dev stops it on a\n\t// signal, but a dev process killed outright — SIGKILL, a closed terminal, a\n\t// crashed parent — never gets to, and the server kept its port: the next\n\t// `gkm dev` found it taken and started somewhere nothing points at.\n\tconst parentWatch = `// Exit when the gkm dev that started this server is gone.\nconst __gkmDevPid = Number(process.env.GKM_DEV_PID);\nif (__gkmDevPid) {\n setInterval(() => {\n try {\n process.kill(__gkmDevPid, 0);\n } catch {\n process.exit(0);\n }\n }, 1000).unref();\n}\n\n`;\n\n\tconst credentialsInjection = secretsJsonPath\n\t\t? `import { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets via globalThis (must happen before app import)\nconst secretsPath = '${secretsJsonPath}';\nif (existsSync(secretsPath)) {\n const __secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));\n globalThis.__gkm_credentials__ = __secrets;\n Object.assign(process.env, __secrets);\n}\n\n`\n\t\t: '';\n\n\tconst serveCode =\n\t\truntime === 'bun'\n\t\t\t? `Bun.serve({\n port,\n fetch: app.fetch,\n });`\n\t\t\t: `const { serve } = await import('@hono/node-server');\n const server = serve({\n fetch: app.fetch,\n port,\n });\n // Inject WebSocket support if available\n const injectWs = (app as any).__injectWebSocket;\n if (injectWs) {\n injectWs(server);\n console.log('🔌 Telescope real-time updates enabled');\n }`;\n\n\tif (selfServing) {\n\t\treturn `#!/usr/bin/env node\n/**\n * Development server entry point for a surface that serves itself\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// Dynamic import so Credentials are populated before the surface evaluates\nconst { app } = await import('${appImportPath}');\n\n${serveCode.replace(/^ {4}/gm, '')}\n`;\n\t}\n\n\treturn `#!/usr/bin/env node\n/**\n * Development server entry point\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// Dynamic import so Credentials are populated before env.ts evaluates\nconst { createApp } = await import('${appImportPath}');\n\n// createApp is async to support optional WebSocket setup\nconst { app, start } = await createApp(undefined, ${enableOpenApi});\n\n// Start the server\nstart({\n port,\n serve: async (app, port) => {\n ${serveCode}\n },\n}).catch((error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n});\n`;\n}\n\n/**\n * The discovery endpoint's connect URL, Jupyter-style: the token in it is what\n * lets a console read what this machine is running.\n */\nfunction announce(discovery: DiscoverySession): void {\n\tlogger.log(`🧭 Discovery: ${discovery.connectUrl}`);\n}\n\n/** Run `fn` with `console.log` muted — warnings and errors still print. */\nasync function quietly<T>(fn: () => Promise<T>): Promise<T> {\n\tconst log = console.log;\n\tconsole.log = () => {};\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\tconsole.log = log;\n\t}\n}\n\n/**\n * How to run a TypeScript entry with the app's own tsx.\n *\n * Straight through node rather than `npx tsx`: npx reads the developer's npm\n * config on every start and warned about each key it did not recognise — nine\n * lines per app, per restart, about nothing gkm does.\n */\nfunction tsxCommand(appRoot: string, args: string[]): [string, string[]] {\n\ttry {\n\t\tconst cli = createRequire(join(appRoot, 'package.json')).resolve('tsx/cli');\n\t\treturn [process.execPath, [cli, ...args]];\n\t} catch {\n\t\treturn ['npx', ['tsx', ...args]];\n\t}\n}\n\n/** A port this app must serve on is held by something else. */\nexport class DevPortInUse extends Error {\n\tconstructor(\n\t\treadonly port: number,\n\t\t/** What holds it, when `lsof` could say — `node (pid 123)`. */\n\t\treadonly holder: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\t`Port ${port} is already in use${holder ? ` by ${holder}` : ''}. ` +\n\t\t\t\t'It is the port this app is provisioned on — the one every other ' +\n\t\t\t\t'app and its CORS origins point at — so dev will not move off it. ' +\n\t\t\t\t'Stop what is holding it (often a dev server a previous run left ' +\n\t\t\t\t'behind), or pass -p/--port to run this app somewhere else.',\n\t\t);\n\t\tthis.name = 'DevPortInUse';\n\t}\n}\n\n/** Apps whose provisioned ports are held before the workspace starts. */\n/**\n * This workspace's own apps are already running — left by a previous start.\n *\n * Only these are refused: a port another project holds is moved off instead\n * (see `assignAppPorts`), but moving off our own would start a second copy.\n */\nexport class WorkspacePortsInUse extends Error {\n\tconstructor(readonly held: readonly AppRunning[]) {\n\t\tsuper(\n\t\t\t`This workspace's apps are already running:\\n${held\n\t\t\t\t.map(\n\t\t\t\t\t({ app, port, holder }) =>\n\t\t\t\t\t\t` ${app}: ${port} — ${describeHolder(holder)}`,\n\t\t\t\t)\n\t\t\t\t.join('\\n')}\\n` +\n\t\t\t\t'A previous `gkm dev` left them behind. Stop them (kill the pids above) ' +\n\t\t\t\t'and start again. Nothing was started.',\n\t\t);\n\t\tthis.name = 'WorkspacePortsInUse';\n\t}\n}\n\n/** What is listening on a port, as `command (pid N)`, if `lsof` can tell. */\nfunction listenerOn(port: number): string | undefined {\n\ttry {\n\t\tconst out = execSync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -Fpc`, {\n\t\t\tencoding: 'utf8',\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t});\n\t\tconst pid = out.match(/^p(\\d+)/m)?.[1];\n\t\tconst command = out.match(/^c(.+)$/m)?.[1];\n\t\treturn pid ? `${command ?? 'a process'} (pid ${pid})` : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nclass DevServer {\n\tprivate serverProcess: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate actualPort: number;\n\tprivate startTime = Date.now();\n\n\tconstructor(\n\t\tprivate requestedPort: number,\n\t\tprivate portExplicit: boolean,\n\t\tprivate enableOpenApi: boolean,\n\t\tprivate telescope: NormalizedTelescopeConfig | undefined,\n\t\t/** Where the database's JSON API is served, when one is declared. */\n\t\tprivate databaseApi: string | undefined,\n\t\tprivate runtime: Runtime = 'node',\n\t\tprivate appRoot: string = process.cwd(),\n\t\tprivate secretsJsonPath?: string,\n\t\t/** Whether `app.ts` is a surface serving itself rather than `createApp`. */\n\t\tpublic selfServing = false,\n\t) {\n\t\tthis.actualPort = requestedPort;\n\t}\n\n\t/** What the ready line calls this app. */\n\tlabel = 'server';\n\n\t/** Told when the server is ready, reloading, or exits on its own. */\n\tonStatus: ((status: AppStatus) => void) | undefined;\n\n\t/** The port it is serving on. */\n\tget port(): number {\n\t\treturn this.actualPort;\n\t}\n\n\t/**\n\t * Where the app is reached — its HTTPS address behind the edge, when it has\n\t * one. The local port is only what the edge forwards to.\n\t */\n\tpublicUrl: string | undefined;\n\n\tasync start(): Promise<void> {\n\t\tthis.startTime = Date.now();\n\t\tif (this.isRunning) {\n\t\t\tawait this.stop();\n\t\t}\n\n\t\t// Check port availability\n\t\tif (this.portExplicit) {\n\t\t\t// Port was explicitly specified - throw if unavailable\n\t\t\tconst available = await isPortAvailable(this.requestedPort);\n\t\t\tif (!available) {\n\t\t\t\tthrow new DevPortInUse(\n\t\t\t\t\tthis.requestedPort,\n\t\t\t\t\tlistenerOn(this.requestedPort),\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.actualPort = this.requestedPort;\n\t\t} else {\n\t\t\t// Find an available port starting from the default\n\t\t\tthis.actualPort = await findAvailablePort(this.requestedPort);\n\n\t\t\tif (this.actualPort !== this.requestedPort) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst serverEntryPath = join(this.appRoot, '.gkm', 'server', 'server.ts');\n\n\t\t// Create server entry file\n\t\tawait this.createServerEntry();\n\n\t\t// Start the server using tsx (TypeScript execution)\n\t\t// Use detached: true so we can kill the entire process tree\n\t\tthis.serverProcess = spawn(\n\t\t\t...tsxCommand(this.appRoot, [\n\t\t\t\tserverEntryPath,\n\t\t\t\t'--port',\n\t\t\t\tthis.actualPort.toString(),\n\t\t\t]),\n\t\t\t{\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t\tNODE_ENV: 'development',\n\t\t\t\t\t// So the server can exit with this process — see the entry.\n\t\t\t\t\tGKM_DEV_PID: String(process.pid),\n\t\t\t\t\t// The app runs from its own directory, and tsx compiles only\n\t\t\t\t\t// what that tsconfig includes with its options — so a\n\t\t\t\t\t// construct's `.tsx` in the workspace would lose its JSX\n\t\t\t\t\t// settings. See `bin/owning-tsconfig-jsx.mjs`.\n\t\t\t\t\tNODE_OPTIONS: withOwningTsconfigJsx(process.env.NODE_OPTIONS),\n\t\t\t\t},\n\t\t\t\tdetached: true,\n\t\t\t},\n\t\t);\n\n\t\tthis.isRunning = true;\n\n\t\tthis.serverProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Server error:', error);\n\t\t});\n\n\t\tconst child = this.serverProcess;\n\t\tchild.on('exit', (code, signal) => {\n\t\t\tif (code !== null && code !== 0 && signal !== 'SIGTERM') {\n\t\t\t\tlogger.error(`❌ Server exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t\t// Still the current server, so nothing here stopped it: it exited on\n\t\t\t// its own. `stop()` lets go of the one it kills before it dies.\n\t\t\tif (this.serverProcess === child) this.onStatus?.('stopped');\n\t\t});\n\n\t\t// Give the server a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\n\t\tif (this.isRunning) {\n\t\t\tconst local = `http://localhost:${this.actualPort}`;\n\t\t\tconst address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;\n\t\t\tconst seconds = ((Date.now() - this.startTime) / 1000).toFixed(1);\n\t\t\tlogger.log(\n\t\t\t\t`\\x1b[32m✓\\x1b[0m ${this.label} ready in ${seconds}s ${address}`,\n\t\t\t);\n\n\t\t\t// What the generated app mounts. An app that serves itself — an auth\n\t\t\t// server — mounts none of it.\n\t\t\tconst tools = this.selfServing\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\t...(this.enableOpenApi ? ['docs /__docs'] : []),\n\t\t\t\t\t\t...(this.telescope ? [`telescope ${this.telescope.path}`] : []),\n\t\t\t\t\t\t...(this.databaseApi ? [`db ${this.databaseApi}`] : []),\n\t\t\t\t\t];\n\t\t\tif (tools.length > 0) logger.log(` ${tools.join(' · ')}`);\n\t\t\tthis.onStatus?.('ready');\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst port = this.actualPort;\n\n\t\tif (this.serverProcess && this.isRunning) {\n\t\t\tconst pid = this.serverProcess.pid;\n\n\t\t\t// Use SIGKILL directly since the server ignores SIGTERM\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process might already be dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.serverProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\n\t\t// Also kill any processes still holding the port\n\t\tthis.killProcessesOnPort(port);\n\t}\n\n\tprivate killProcessesOnPort(port: number): void {\n\t\ttry {\n\t\t\t// Whatever is *listening* on the port — the server this replaces.\n\t\t\t// Without `-sTCP:LISTEN`, lsof also lists every client connected to\n\t\t\t// it, so a restart killed the browser, the web app's server, or the\n\t\t\t// test runner that happened to hold a keep-alive socket.\n\t\t\texecSync(\n\t\t\t\t`lsof -ti tcp:${port} -sTCP:LISTEN | xargs kill -9 2>/dev/null || true`,\n\t\t\t\t{ stdio: 'ignore' },\n\t\t\t);\n\t\t} catch {\n\t\t\t// Ignore errors - port may already be free\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tconst portToReuse = this.actualPort;\n\t\tthis.onStatus?.('reloading');\n\t\tawait this.stop();\n\n\t\t// Wait for port to be released (up to 3 seconds)\n\t\tlet attempts = 0;\n\t\twhile (attempts < 30) {\n\t\t\tif (await isPortAvailable(portToReuse)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\t\t\tattempts++;\n\t\t}\n\n\t\t// Force reuse the same port\n\t\tthis.requestedPort = portToReuse;\n\t\tawait this.start();\n\t}\n\n\tprivate async createServerEntry(): Promise<void> {\n\t\tconst { writeFile: fsWriteFile } = await import('node:fs/promises');\n\n\t\tconst serverPath = join(this.appRoot, '.gkm', 'server', 'server.ts');\n\n\t\tconst content = generateServerEntryContent({\n\t\t\tsecretsJsonPath: this.secretsJsonPath,\n\t\t\truntime: this.runtime,\n\t\t\tenableOpenApi: this.enableOpenApi,\n\t\t\tselfServing: this.selfServing,\n\t\t});\n\n\t\tawait fsWriteFile(serverPath, content);\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Function } from '@geekmidas/constructs/functions';\nimport type { BuildContext } from '../build/types';\nimport type { FunctionInfo } from '../types';\nimport { runtimeFor } from './EndpointGenerator.js';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\nexport class FunctionGenerator extends ConstructGenerator<\n\tFunction<any, any, any, any, any, any, any, any, any, any>,\n\tFunctionInfo[]\n> {\n\tisConstruct(\n\t\tvalue: any,\n\t): value is Function<any, any, any, any, any, any, any, any, any, any> {\n\t\treturn Function.isFunction(value);\n\t}\n\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<\n\t\t\tFunction<any, any, any, any, any, any, any, any, any, any>\n\t\t>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<FunctionInfo[]> {\n\t\tconst target = options?.target ?? 'aws';\n\t\tconst logger = console;\n\t\tconst functionInfos: FunctionInfo[] = [];\n\n\t\tif (constructs.length === 0 || target === 'server') {\n\t\t\treturn functionInfos;\n\t\t}\n\n\t\t// Create functions subdirectory\n\t\tconst functionsDir = join(outputDir, 'functions');\n\t\tawait mkdir(functionsDir, { recursive: true });\n\n\t\t// Generate function handlers\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateFunctionHandler(\n\t\t\t\tfunctionsDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tcontext,\n\t\t\t\tconstruct.owner,\n\t\t\t);\n\n\t\t\tfunctionInfos.push({\n\t\t\t\tname: key,\n\t\t\t\thandler: relative(options?.root ?? process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t\tdependencies: construct.constructs,\n\t\t\t});\n\n\t\t\tlogger.log(`Generated function handler: ${key}`);\n\t\t}\n\n\t\treturn functionInfos;\n\t}\n\n\tprivate async generateFunctionHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\tcontext: BuildContext,\n\t\t/** The construct that owns this — its worker, or its surface. */\n\t\towner: string | undefined,\n\t): Promise<string> {\n\t\tconst handlerFileName = `${exportName}.ts`;\n\t\tconst handlerPath = join(outputDir, handlerFileName);\n\n\t\tconst relativePath = relative(dirname(handlerPath), sourceFile);\n\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\t// Imports the construct that owns this, and binds `envParser` and\n\t\t// `logger` off it — the objects it was declared with, rather than a\n\t\t// module path printed in from config.\n\t\tconst runtime = runtimeFor(context, dirname(handlerPath), owner);\n\n\t\tconst content = `import { AWSLambdaFunction } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\n${runtime.imports}\n${context.storageDrivers?.imports ?? ''}\n${runtime.bindings}\n${context.storageDrivers?.setup ? `\\n// The handler registers the drivers its target needs.\\n${context.storageDrivers.setup}\\n` : ''}\nconst adapter = new AWSLambdaFunction(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n}\n","import { Topic } from '@geekmidas/constructs/topic';\nimport type { BuildContext } from '../build/types';\nimport type { TopicInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\n/**\n * Discovers topics (`new Topic(…)`) into `manifest.topics`. A topic is a\n * *resource*, not a function — it has no handler to generate. Producers name it\n * with `.event(topic, …)` or `.dependsOn([topic])`, and subscribers bind with\n * `worker.topic(topic)`; this generator\n * only records the topic + its event contract so infra can provision the SNS\n * topic. Identical output for every provider (locally pg-boss routes by event\n * name, so there's nothing to run).\n */\nexport class TopicGenerator extends ConstructGenerator<\n\tTopic<any, any>,\n\tTopicInfo[]\n> {\n\tisConstruct(value: any): value is Topic<any, any> {\n\t\treturn Topic.isTopic(value);\n\t}\n\n\tasync build(\n\t\t_context: BuildContext,\n\t\tconstructs: GeneratedConstruct<Topic<any, any>>[],\n\t\t_outputDir: string,\n\t\t_options?: GeneratorOptions,\n\t): Promise<TopicInfo[]> {\n\t\tconst logger = console;\n\t\tconst topicInfos = constructs.map(({ construct }) => ({\n\t\t\tname: construct.name,\n\t\t\tevents: construct.eventTypes,\n\t\t}));\n\n\t\tfor (const topic of topicInfos) {\n\t\t\tlogger.log(`Discovered topic: ${topic.name}`);\n\t\t}\n\n\t\treturn topicInfos;\n\t}\n}\n","import type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\n\nimport type { CronInfo, FunctionInfo, RouteInfo } from '../types';\n\nexport interface ProcessedEndpoint {\n\tfile: string;\n\texportName: string;\n\tendpoint: Endpoint<any, any, any, any, any, any>;\n\trouteInfo: RouteInfo;\n}\n\nexport interface ProcessedFunction {\n\tfile: string;\n\texportName: string;\n\tfn: Function<any, any, any, any, any>;\n}\n\nexport interface ProcessedCron {\n\tfile: string;\n\texportName: string;\n\tcron: Cron<any, any, any, any>;\n\tschedule?: string;\n}\n\nexport interface NormalizedTelescopeConfig {\n\tenabled: boolean;\n\t/** Path to user's telescope module (if provided) */\n\ttelescopePath?: string;\n\t/** Import pattern for telescope (e.g., '{ telescope }' or 'telescope') */\n\ttelescopeImportPattern?: string;\n\t/** UI path for telescope dashboard */\n\tpath: string;\n\tignore: string[];\n\trecordBody: boolean;\n\tmaxEntries: number;\n\twebsocket: boolean;\n}\n\n/**\n * Where `gkm dev` serves the database's read-only JSON API\n * (`@geekmidas/db/introspect`). Under `/__gkm` with the rest of what the dev\n * server adds, so it cannot collide with an application route.\n */\nexport const DEV_DATABASE_API_PATH = '/__gkm/db';\n\n/**\n * The database the dev server's JSON API reads, and where it is declared.\n *\n * The API needs a client, and a client comes from a construct — so the entry\n * imports the declaration discovery already found and resolves it there. One\n * declared database is one browsable database; a project with none gets no\n * API, which is the correct answer rather than a stub.\n */\nexport interface DevDatabaseApi {\n\tpath: string;\n\tdatabase: { specifier: string; exportName: string };\n}\n\nexport interface NormalizedHooksConfig {\n\t/** Path to server hooks module */\n\tserverHooksPath: string;\n}\n\nexport interface NormalizedProductionConfig {\n\tenabled: boolean;\n\tbundle: boolean;\n\tminify: boolean;\n\thealthCheck: string;\n\tgracefulShutdown: boolean;\n\texternal: string[];\n\tsubscribers: 'include' | 'exclude';\n\topenapi: boolean;\n}\n\nexport interface BuildContext {\n\t/**\n\t * The surface this server serves, if the app declared one.\n\t *\n\t * Carried so the generated entry can set up CORS from the graph instead of a\n\t * hand-written hook: the origins arrive as `<ID>_TRUSTED_ORIGINS`, resolved\n\t * from whatever declared an edge to this surface.\n\t */\n\tsurface?: {\n\t\tid: string;\n\t\ttrustedOriginsKey: string;\n\t\t/**\n\t\t * Where the surface is declared, so the entry can import it.\n\t\t *\n\t\t * The logger a surface was given is an *object*, and a generator can\n\t\t * print a specifier but not an object — which is why the logger used to\n\t\t * be named in config as a module path. Discovery already knows the path,\n\t\t * so the entry imports the surface and reads the logger off it, and\n\t\t * nothing is written down twice.\n\t\t */\n\t\tmodule?: { specifier: string; exportName: string };\n\t\tcors?: {\n\t\t\tmaxAge?: number;\n\t\t\tcredentials?: boolean;\n\t\t\tallowHeaders?: readonly string[];\n\t\t\texposeHeaders?: readonly string[];\n\t\t};\n\t};\n\n\ttelescope?: NormalizedTelescopeConfig;\n\t/** The dev server's database JSON API. Never set for `gkm build`. */\n\tdatabaseApi?: DevDatabaseApi;\n\thooks?: NormalizedHooksConfig;\n\t/** Production build configuration */\n\tproduction?: NormalizedProductionConfig;\n\t/**\n\t * When true, optional env vars get a `?` suffix in each construct's\n\t * environment array (e.g. `PORT?` instead of `PORT`).\n\t */\n\tmarkOptional?: boolean;\n\t/**\n\t * Storage drivers the generated entry points should register.\n\t *\n\t * The scheme in an injected URL picks the driver, so registering is the entry\n\t * point's job — see `generators/drivers.ts`.\n\t */\n\tstorageDrivers?: import('../generators/drivers.js').RuntimeDrivers;\n\t/**\n\t * The constructs glob, so the build can emit the manifest once the routes it\n\t * folds in are known.\n\t */\n\tconstructGlobs?: string | readonly string[];\n\t/**\n\t * The backends this build registered drivers for.\n\t *\n\t * Recorded in the emitted manifest so a deploy reads the same answer rather\n\t * than choosing its own — see `reconcile/emit.ts`.\n\t */\n\tcacheBackend?: import('../types.js').CacheBackend;\n\t/**\n\t * The events brokers this build registered drivers for — empty when the app\n\t * declares no topic or queue. What a generated file decides from when it\n\t * has broker-specific code to include, such as SNS push subscriptions.\n\t */\n\teventsBackends?: readonly import('../types.js').EventsBackend[];\n\temailBackend?: import('../types.js').EmailBackend;\n\t/**\n\t * Every construct that can own a runnable, by id — the surfaces and the\n\t * workers — mapped to the module that exports it.\n\t *\n\t * What lets a generated cron import the worker that runs it rather than a\n\t * logger path from config.\n\t */\n\towners?: Record<string, { specifier: string; exportName: string }>;\n\t/**\n\t * What the production entry starts OpenTelemetry with, when\n\t * `OTEL_EXPORTER_OTLP_ENDPOINT` asks for it — see `generators/telemetry.ts`.\n\t */\n\ttelemetry?: import('../generators/telemetry.js').TelemetryContext;\n}\n\nexport interface ProviderBuildResult {\n\troutes: RouteInfo[];\n\tfunctions: FunctionInfo[];\n\tcrons: CronInfo[];\n}\n","import { resolve } from 'node:path';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { ConstructSource } from '../reconcile/discover.js';\nimport { type BuildContext, DEV_DATABASE_API_PATH } from './types';\n\n/**\n * What a generated entry imports its runtime from, read off the discovered\n * constructs: the surface it serves, every construct a runnable can be built\n * from, and the database the dev server's JSON API reads.\n *\n * `gkm build` and `gkm dev` both write entries that import the surface for its\n * logger and environment parser, so both ask here. A dev server that skipped it\n * had nothing to import them from.\n */\nexport function ownersContext(options: {\n\tdeclared: ConstructManifest;\n\tsources: Record<string, ConstructSource>;\n\tworkspaceRoot: string;\n\t/** The directory being built — the app a surface's `path` names. */\n\tappRoot: string;\n\t/** Whether to serve the database's JSON API — `gkm dev` only. */\n\tdatabaseApi?: boolean;\n}): Pick<BuildContext, 'owners' | 'surface' | 'databaseApi'> {\n\tconst { declared, sources, workspaceRoot, appRoot, databaseApi } = options;\n\n\t// Which surface this server answers on, so the entry can derive its CORS.\n\t//\n\t// The app's own API, not the auth server it may also mount: an auth surface\n\t// declares its own endpoints, and the origins that may call *it* are a\n\t// different list from the ones that may call the API.\n\tconst surfaces = restApis(declared);\n\tconst served = servedSurface(declared, workspaceRoot, appRoot);\n\tconst primary =\n\t\tserved ?? surfaces.find((d) => d.endpoints.length === 0) ?? surfaces[0];\n\n\t// Which database the JSON API reads: the one the app declared. A reader is\n\t// not a candidate — it is the same data through a role that cannot write,\n\t// so browsing it would be the same rows under a second name.\n\tconst browsable = Object.entries(declared).find(\n\t\t([, d]) => d.kind === 'database',\n\t);\n\tconst browsableSource = browsable ? sources[browsable[0]] : undefined;\n\n\t// Every construct something can be built from, by id. A generated cron\n\t// imports the worker that owns it; a generated handler imports its surface.\n\tconst owners: Record<string, { specifier: string; exportName: string }> = {};\n\tfor (const [id, declaration] of Object.entries(declared)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'worker')\n\t\t\tcontinue;\n\t\tconst source = sources[id];\n\t\tif (!source) continue;\n\t\towners[id] = { specifier: source.file, exportName: source.exportName };\n\t}\n\n\tconst primarySource = primary ? sources[primary.id] : undefined;\n\n\treturn {\n\t\towners,\n\t\t...(primary\n\t\t\t? {\n\t\t\t\t\tsurface: {\n\t\t\t\t\t\tid: primary.id,\n\t\t\t\t\t\ttrustedOriginsKey: provideKey(primary.id, 'trustedOrigins'),\n\t\t\t\t\t\t...(primary.cors ? { cors: primary.cors } : {}),\n\t\t\t\t\t\t...(primarySource\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\t\t\t\tspecifier: primarySource.file,\n\t\t\t\t\t\t\t\t\t\texportName: primarySource.exportName,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t\t...(databaseApi && browsableSource\n\t\t\t? {\n\t\t\t\t\tdatabaseApi: {\n\t\t\t\t\t\tpath: DEV_DATABASE_API_PATH,\n\t\t\t\t\t\tdatabase: {\n\t\t\t\t\t\t\tspecifier: browsableSource.file,\n\t\t\t\t\t\t\texportName: browsableSource.exportName,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/**\n * The endpoints one surface serves.\n *\n * One glob finds every surface's endpoints, wherever their files live. A build\n * keeps the ones built from the surface it serves; one built from no surface at\n * all has nowhere else to go.\n */\nexport function servedBy<T extends { construct: { surface?: { id: string } } }>(\n\tendpoints: T[],\n\tsurface: BuildContext['surface'],\n): T[] {\n\tif (!surface) return endpoints;\n\n\treturn endpoints.filter(\n\t\t({ construct }) =>\n\t\t\t!construct.surface || construct.surface.id === surface.id,\n\t);\n}\n\ntype RestApiDeclaration = Extract<\n\tConstructManifest[string],\n\t{ kind: 'rest-api' }\n>;\n\nfunction restApis(declared: ConstructManifest): RestApiDeclaration[] {\n\treturn Object.values(declared).filter(\n\t\t(d): d is RestApiDeclaration => d.kind === 'rest-api',\n\t);\n}\n\n/**\n * The surface whose declared `path` is the directory being built — asked of\n * every surface, because a workspace has several and each app's build serves\n * exactly one.\n */\nexport function servedSurface(\n\tdeclared: ConstructManifest,\n\tworkspaceRoot: string,\n\tappRoot: string,\n): RestApiDeclaration | undefined {\n\treturn restApis(declared).find(\n\t\t(d) => resolve(workspaceRoot, d.path) === resolve(appRoot),\n\t);\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport type { ConstructSource } from '../reconcile/discover.js';\nimport { servedSurface } from './owners';\n\n/** A construct that builds its own server — `BetterAuth` and its routes. */\ninterface ServesItself {\n\tserver(options: unknown): Promise<{ app: unknown }>;\n}\n\n/** Whether a construct serves itself, asked of the construct. */\nexport function servesItself(construct: unknown): construct is ServesItself {\n\treturn (\n\t\ttypeof (construct as { server?: unknown } | null)?.server === 'function'\n\t);\n}\n\n/**\n * The surface this app serves, when that surface serves itself.\n *\n * An auth server's routes are a wildcard the construct mounts, so a glob finds\n * nothing and the entry only has to start it. That used to be inferred —\n * \"nothing found, and the surface declares routes\" — which is a guess about\n * the construct from the outside. The construct can simply be asked.\n */\nexport function selfServingSurface(options: {\n\tdeclared: ConstructManifest;\n\tsources: Record<string, ConstructSource>;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}): { id: string; source: ConstructSource } | undefined {\n\tconst { declared, sources, workspaceRoot, appRoot } = options;\n\n\tconst served = servedSurface(declared, workspaceRoot, appRoot);\n\tconst source = served ? sources[served.id] : undefined;\n\n\tif (!served || !source || !servesItself(source.construct)) return undefined;\n\n\treturn { id: served.id, source };\n}\n\n/**\n * The entry for a surface that serves itself.\n *\n * Two lines, because the construct owns the serving. A generator writing the\n * mounts would be a second description of routes the declaration already\n * carries — which is how Better Auth came to be mounted by a hand-written hook,\n * and then served by nothing at all when that hook was deleted for duplicating\n * CORS the graph had started deriving.\n *\n * The import specifier comes from discovery, which globbed the file and\n * imported it. Nothing about the surface is named here.\n */\nexport async function writeSurfaceEntry(\n\toutputDir: string,\n\tsource: ConstructSource,\n): Promise<void> {\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst rel = relative(outputDir, source.file).replace(/\\.ts$/, '.js');\n\tconst specifier = rel.startsWith('.') ? rel : `./${rel}`;\n\n\tawait writeFile(\n\t\tjoin(outputDir, 'app.ts'),\n\t\t`/**\n * Generated entry for a surface that serves itself.\n *\n * Its routes, its CORS origins and its clients all come from the construct's\n * own declaration. This file exists only to start it.\n */\nimport { snifferContext } from '@geekmidas/constructs';\nimport { defaultEnvParser } from '@geekmidas/constructs/endpoints';\nimport { ${source.exportName} as surface } from '${specifier}';\n\nconst envParser = defaultEnvParser();\n\nexport const { app } = await surface.server({ envParser, context: snifferContext });\n\nexport default app;\n`,\n\t);\n}\n\n/**\n * The production server for a surface that serves itself.\n *\n * `app.ts` exports the construct's own Hono app and starts nothing, which is\n * what `gkm dev` wants: its server mounts the app beside its tools. An image\n * needs a process, so a production build starts one here — the health check\n * every image is probed on, the surface behind it, and the same bounded drain\n * on SIGTERM the generated route servers have. Without it an auth server had\n * no bundle to put in an image at all.\n */\nexport async function writeSurfaceServer(\n\toutputDir: string,\n\toptions: { healthCheck: string; gracefulShutdown: boolean },\n): Promise<string> {\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst shutdown = options.gracefulShutdown\n\t\t? `\n// Stop taking requests, let in-flight ones finish, then close what the\n// construct opened — bounded by GKM_SHUTDOWN_TIMEOUT_MS, under Docker's 10s\n// stop timeout, so the process exits on its own terms.\nlet shuttingDown = false;\nconst shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n const deadline = Number(process.env.GKM_SHUTDOWN_TIMEOUT_MS) || 8000;\n setTimeout(() => process.exit(1), deadline).unref();\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await runShutdownHooks((error) => console.error(error));\n process.exit(0);\n};\n\nprocess.on('SIGTERM', shutdown);\nprocess.on('SIGINT', shutdown);\n`\n\t\t: '';\n\n\tconst path = join(outputDir, 'server.ts');\n\tawait writeFile(\n\t\tpath,\n\t\t`#!/usr/bin/env node\n/**\n * Production server for a surface that serves itself.\n * Generated by 'gkm build --production'.\n */\nimport { serve } from '@hono/node-server';\nimport { Hono } from 'hono';\n${options.gracefulShutdown ? \"import { runShutdownHooks } from '@geekmidas/constructs';\\n\" : ''}import { app as surface } from './app.js';\n\nconst port = Number(process.env.PORT) || 3000;\n\nconst app = new Hono();\n// First, so a probe is answered without reaching the surface's own routes.\napp.get(${JSON.stringify(options.healthCheck)}, (c) =>\n c.json({ status: 'ok', timestamp: Date.now() }),\n);\napp.route('/', surface);\n\nconst server = serve({ fetch: app.fetch, port });\nconsole.log(JSON.stringify({ msg: 'Production server started', port }));\n${shutdown}`,\n\t);\n\n\treturn path;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { chmod, mkdir, rm, writeFile } from 'node:fs/promises';\nimport { join, relative, resolve } from 'node:path';\nimport type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\nimport type { Queue } from '@geekmidas/constructs/queue';\nimport type { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { Topic } from '@geekmidas/constructs/topic';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { loadAppConfig, loadConfig, loadWorkspaceConfig } from '../config';\nimport {\n\tnormalizeHooksConfig,\n\tnormalizeProductionConfig,\n\tnormalizeTelescopeConfig,\n} from '../dev';\nimport {\n\tCronGenerator,\n\tcacheBackendsIn,\n\tdriversFor,\n\tEndpointGenerator,\n\teventsBackendsIn,\n\tFunctionGenerator,\n\ttype GeneratedConstruct,\n\tQueueGenerator,\n\tSubscriberGenerator,\n\tTopicGenerator,\n\tWorkerGenerator,\n\tworkerBundleName,\n\tworkerEntryDir,\n} from '../generators';\nimport { telemetryFor } from '../generators/telemetry';\nimport { generateOpenApi } from '../openapi.js';\nimport { type ConstructSource, discover } from '../reconcile/discover.js';\nimport {\n\ttype Backends,\n\tmanifestModule,\n\twithCompute,\n\twithRoutes,\n} from '../reconcile/emit.js';\nimport { CommandFailed, DEFAULT_TIMEOUT_MS } from '../run';\nimport { LocalSandbox } from '../sandbox/local';\nimport { keyFingerprint } from '../secrets/encryption';\nimport type {\n\tBuildOptions,\n\tBuildResult,\n\tCacheBackend,\n\tCronInfo,\n\tEventsBackend,\n\tFunctionInfo,\n\tGkmConfig,\n\tMainProvider,\n\tQueueInfo,\n\tRouteInfo,\n\tRoutes,\n\tSubscriberInfo,\n} from '../types';\nimport { DEFAULT_EMAIL } from '../types.js';\nimport {\n\tcacheBackendFor,\n\teventsBackendFor,\n\tproviderOf,\n} from '../workspace/backends.js';\nimport {\n\tallConstructGlobs,\n\tgetAppBuildOrder,\n\tgetAppGkmConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport { ownersContext, servedBy } from './owners';\nimport {\n\tselfServingSurface,\n\twriteSurfaceEntry,\n\twriteSurfaceServer,\n} from './surfaceEntry';\nimport type {\n\tBuildContext,\n\tNormalizedHooksConfig,\n\tNormalizedProductionConfig,\n\tNormalizedTelescopeConfig,\n} from './types';\nimport { type WorkerUnit, workerUnits } from './workers';\n\nconst logger = console;\n\n/**\n * Where `gkm build --stage` leaves the key its bundle's secrets were encrypted\n * with, beside the bundle in `.gkm/server/` and readable by its owner alone.\n */\nexport const MASTER_KEY_FILE = 'master.key';\n\n/**\n * What a build run at the workspace root reads.\n *\n * One backend app there, and it is that app's config, so its own `openapi`\n * and `telescope` settings still apply. Otherwise it is the workspace's: every\n * construct glob, and the backends they resolve to.\n */\nfunction rootGkmConfig(workspace: NormalizedWorkspace): GkmConfig {\n\tconst backends = Object.entries(workspace.apps).filter(\n\t\t([, app]) => app.type === 'backend',\n\t);\n\tconst only = backends.length === 1 ? backends[0] : undefined;\n\tconst own = only ? getAppGkmConfig(workspace, only[0]) : undefined;\n\n\treturn (\n\t\town ?? {\n\t\t\tstages: workspace.stages,\n\t\t\t...(workspace.deploy ? { deploy: workspace.deploy } : {}),\n\t\t\tconstructs: allConstructGlobs(workspace),\n\t\t}\n\t);\n}\n\n/** Directories under `.gkm/` that the removed per-provider builds wrote. */\nconst SUPERSEDED_OUTPUT = [\n\t'aws-apigatewayv1',\n\t'aws-apigatewayv2',\n\t'aws-lambda',\n];\n\n/** Whether `--provider` named something a build can target. */\nexport function isMainProvider(value: string): value is MainProvider {\n\treturn value === 'aws' || value === 'server';\n}\n\nexport class UnknownBuildProvider extends Error {\n\tconstructor(readonly provider: string) {\n\t\tsuper(\n\t\t\t`'${provider}' is not a build target. Pass --provider aws or --provider server, or leave it out to build for where gkm.config.ts deploys.`,\n\t\t);\n\t\tthis.name = 'UnknownBuildProvider';\n\t}\n}\n\n/** `--cache` named something that is not a cache backend. */\nexport class UnknownCacheBackend extends Error {\n\tconstructor(readonly backend: string) {\n\t\tsuper(\n\t\t\t`'${backend}' is not a cache backend. Pass --cache upstash, elasticache, db or redis, or leave it out to register the deploy target's.`,\n\t\t);\n\t\tthis.name = 'UnknownCacheBackend';\n\t}\n}\n\nexport async function buildCommand(\n\toptions: BuildOptions,\n): Promise<BuildResult> {\n\t// Load config with workspace detection\n\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t// Route to workspace build mode for multi-app workspaces\n\t// BUT only if we're at the workspace root (prevents recursive builds when\n\t// Turbo runs gkm build in each app subdirectory)\n\tif (loadedConfig.type === 'workspace') {\n\t\tconst cwd = resolve(process.cwd());\n\t\tconst workspaceRoot = resolve(loadedConfig.workspace.root);\n\t\tconst isAtWorkspaceRoot = cwd === workspaceRoot;\n\n\t\t// Turbo only when there is a subdirectory for it to descend into. With\n\t\t// every app at the root — or no apps at all — routing through it\n\t\t// re-enters this same directory: turbo runs the root package's `build`,\n\t\t// which is `gkm build`, which arrives here again.\n\t\tconst someAppIsElsewhere = Object.values(loadedConfig.workspace.apps).some(\n\t\t\t(app) => resolve(workspaceRoot, app.path) !== workspaceRoot,\n\t\t);\n\n\t\tif (isAtWorkspaceRoot && someAppIsElsewhere) {\n\t\t\tlogger.log('📦 Detected workspace configuration');\n\t\t\treturn workspaceBuildCommand(loadedConfig.workspace, options);\n\t\t}\n\t}\n\n\t// At the root there is no app to pick: the build reads every construct the\n\t// globs find and writes one manifest and a spec per surface. Asking\n\t// package.json which app this is was a question only a subdirectory has.\n\tconst config =\n\t\tloadedConfig.type !== 'workspace'\n\t\t\t? await loadConfig()\n\t\t\t: resolve(process.cwd()) === resolve(loadedConfig.workspace.root)\n\t\t\t\t? rootGkmConfig(loadedConfig.workspace)\n\t\t\t\t: (await loadAppConfig()).gkmConfig;\n\n\t// Where it deploys decides what it builds: one Lambda per construct for\n\t// AWS, one process for a server. `--provider` overrides it for a Dockerfile,\n\t// which builds a server whatever the project deploys to.\n\tconst target = options.provider ?? providerOf(loadedConfig.workspace);\n\tconst workspaceRoot = loadedConfig.workspace.root;\n\tconst appRoot = process.cwd();\n\n\tconst output = await buildOneApp({\n\t\tconfig,\n\t\toptions,\n\t\tworkspace: loadedConfig.workspace,\n\t\tappRoot,\n\t\ttarget,\n\t});\n\n\t// Inside an app, its handlers are all there is to write: the manifest is\n\t// the application's, and only the root has all of it.\n\tif (resolve(appRoot) === resolve(workspaceRoot)) {\n\t\tawait writeManifest({\n\t\t\tworkspaceRoot,\n\t\t\ttarget,\n\t\t\tbuilds: output.built ? [output.built] : [],\n\t\t\tconstructs: await declaredIn(config, workspaceRoot),\n\t\t\tbackends: backendsOf(loadedConfig.workspace),\n\t\t});\n\t}\n\n\treturn output;\n}\n\n/** What the workspace declares, read through a config's globs. */\nasync function declaredIn(\n\tconfig: GkmConfig,\n\tcwd: string,\n): Promise<ConstructManifest> {\n\treturn discover({ patterns: config.constructs, cwd });\n}\n\n/**\n * The backend choices the manifest records — answered by the deploy target,\n * the same place reconcile and the build's drivers read them.\n */\nfunction backendsOf(workspace: { deploy?: { default?: string } }): {\n\tcache: CacheBackend;\n\temail: typeof DEFAULT_EMAIL;\n} {\n\treturn {\n\t\tcache: cacheBackendFor(providerOf(workspace)),\n\t\temail: DEFAULT_EMAIL,\n\t};\n}\n\n/** One app's build, from its config and the command's options. */\nasync function buildOneApp(input: {\n\tconfig: GkmConfig;\n\toptions: BuildOptions;\n\tworkspace: NormalizedWorkspace;\n\tappRoot: string;\n\ttarget: MainProvider;\n}): Promise<AppBuildOutput> {\n\tconst { config, options, workspace, appRoot, target } = input;\n\n\t// One answer for which backends this app uses, read once — from the\n\t// deploy target, which is the same place reconcile reads it. The build\n\t// registers drivers for it and records it in the manifest, so a deploy\n\t// cannot pick differently and hand the running code a URL it has no driver\n\t// for.\n\t//\n\t// `--cache` is the one exception: the stack `gkm compose` runs has its own\n\t// Redis whatever the target, and its Dockerfiles say so.\n\tconst cacheBackend = options.cache ?? cacheBackendFor(providerOf(workspace));\n\tconst eventsBackend = eventsBackendFor(providerOf(workspace));\n\n\tconst production = normalizeProductionConfig(options.production ?? false);\n\tif (production) {\n\t\tlogger.log(`🏭 Building for PRODUCTION`);\n\t}\n\n\tlogger.log(`Building for ${target}`);\n\tlogger.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);\n\n\t// Normalize telescope configuration (disabled in production)\n\tconst telescope = production\n\t\t? undefined\n\t\t: normalizeTelescopeConfig(config.telescope);\n\tif (telescope) {\n\t\tlogger.log(`🔭 Telescope enabled at ${telescope.path}`);\n\t}\n\n\tconst hooks = normalizeHooksConfig(config.hooks, appRoot);\n\tif (hooks) {\n\t\tlogger.log(`🪝 Server hooks enabled`);\n\t}\n\n\treturn buildApp({\n\t\tconfig,\n\t\tworkspaceRoot: workspace.root,\n\t\tappRoot,\n\t\ttarget,\n\t\tenableOpenApi: options.enableOpenApi ?? false,\n\t\tcacheBackend,\n\t\teventsBackend,\n\t\tproduction,\n\t\ttelescope,\n\t\thooks,\n\t\tmarkOptional: options.markOptional ?? false,\n\t\tskipBundle: options.skipBundle ?? false,\n\t\tstage: options.stage,\n\t\tworkspaceName: workspace.name,\n\t\tworkspace,\n\t});\n}\n\n/** What one app's build needs, once its config has been read. */\nexport interface BuildAppInput {\n\tconfig: GkmConfig;\n\tworkspaceRoot: string;\n\t/** The app being built — the directory a surface's `path` names. */\n\tappRoot: string;\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget: MainProvider;\n\tenableOpenApi: boolean;\n\tcacheBackend: CacheBackend;\n\t/**\n\t * The broker the target puts topics and queues on. Its driver is registered\n\t * only when the app declares one — see `eventsBackendsIn`.\n\t */\n\teventsBackend: EventsBackend;\n\tproduction?: NormalizedProductionConfig;\n\ttelescope?: NormalizedTelescopeConfig;\n\t/**\n\t * Serve the declared database's read-only JSON API at `/__gkm/db`. Only\n\t * `gkm dev` asks: it hands every row to whoever can reach the port.\n\t */\n\tdatabaseApi?: boolean;\n\thooks?: NormalizedHooksConfig;\n\tmarkOptional?: boolean;\n\tskipBundle?: boolean;\n\tstage?: string;\n\t/** Re-import changed modules — `gkm dev` rebuilding after an edit. */\n\tbustCache?: boolean;\n\t/** The workspace's name — telemetry's `service.namespace`. */\n\tworkspaceName?: string;\n\t/**\n\t * The workspace the app is in. A production server build reads it to know\n\t * which workers this app carries the entries of — see `workerUnits`.\n\t */\n\tworkspace?: NormalizedWorkspace;\n\t/**\n\t * Generate a server even when the globs find nothing.\n\t *\n\t * A build with nothing in it has nothing to deploy. A dev server with\n\t * nothing in it is how a project starts: it runs, and the first endpoint\n\t * written appears on the next rebuild.\n\t */\n\tserveEmpty?: boolean;\n}\n\nexport interface AppBuildOutput extends BuildResult {\n\t/**\n\t * The surface the entry starts, when the app's surface serves itself — its\n\t * `app.ts` exports the construct's own `app`, with no `createApp` to call.\n\t */\n\tselfServing?: string;\n\t/** Where the generated server serves the database's JSON API, if it does. */\n\tdatabaseApi?: string;\n\t/** What it generated, for the application's manifest. */\n\tbuilt?: AppBuild;\n}\n\n/** One app's generated handlers, as the application's manifest records them. */\nexport interface AppBuild {\n\t/** The surface its endpoints are served on. */\n\tsurface?: string;\n\troutes: RouteInfo[];\n\tfunctions: FunctionInfo[];\n\tcrons: CronInfo[];\n\tsubscribers: SubscriberInfo[];\n\tqueues: QueueInfo[];\n}\n\n/**\n * Write the application's manifest: every declared construct, with what each\n * app generated folded into it.\n *\n * The manifest belongs to the whole application, so only the root writes it —\n * once, after every app has built, from the constructs the workspace declares.\n * An app's own build generates its handlers and nothing else.\n */\nexport async function writeManifest(input: {\n\tworkspaceRoot: string;\n\ttarget: MainProvider;\n\tbuilds: readonly AppBuild[];\n\tconstructs: ConstructManifest;\n\tbackends: Backends;\n}): Promise<void> {\n\tconst { workspaceRoot, target, builds, constructs, backends } = input;\n\tconst manifestDir = join(workspaceRoot, '.gkm', 'manifest');\n\tawait mkdir(manifestDir, { recursive: true });\n\n\t// One manifest, for the target this build is for. The other target's,\n\t// left by an earlier build, would describe an application that is not\n\t// being deployed.\n\tconst other = target === 'aws' ? 'server' : 'aws';\n\tawait rm(join(manifestDir, `${other}.ts`), { force: true });\n\n\t// Each app's routes go to the surface it serves; then the compute every\n\t// app generated, which nests in the queue or topic that triggers it.\n\tconst withServed = builds.reduce(\n\t\t(manifest, build) =>\n\t\t\twithRoutes(\n\t\t\t\tmanifest,\n\t\t\t\tbuild.routes.filter((route) => route.method !== 'ALL'),\n\t\t\t\t{\n\t\t\t\t\tperRoute: true,\n\t\t\t\t\t...(build.surface ? { surface: build.surface } : {}),\n\t\t\t\t},\n\t\t\t),\n\t\tconstructs,\n\t);\n\tconst folded = withCompute(withServed, {\n\t\tfunctions: builds.flatMap((build) => build.functions),\n\t\tcrons: builds.flatMap((build) => build.crons),\n\t\tqueues: builds.flatMap((build) => build.queues),\n\t\tsubscribers: builds.flatMap((build) => build.subscribers),\n\t});\n\n\tconst path = join(manifestDir, `${target}.ts`);\n\tawait writeFile(path, manifestModule(folded, backends));\n\tlogger.log(`Manifest: ${relative(process.cwd(), path)}`);\n}\n\n/**\n * Turn one app's constructs into its generated entry.\n *\n * `gkm build` and `gkm dev` both run this. They used to be two copies of it,\n * and every time the build learned something about constructs — that the\n * entry takes its logger from the surface, that an auth server serves itself —\n * dev did not, and failed on exactly the apps the build had learned to handle.\n */\nexport async function buildApp(input: BuildAppInput): Promise<AppBuildOutput> {\n\tconst {\n\t\tconfig,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t\ttarget,\n\t\tenableOpenApi,\n\t\tcacheBackend,\n\t\teventsBackend,\n\t\tproduction,\n\t\ttelescope,\n\t\tdatabaseApi,\n\t\thooks,\n\t\tbustCache = false,\n\t} = input;\n\n\tconst constructGlobs = config.constructs;\n\n\t// Discovery imports application code, so it runs once here and everything\n\t// downstream reads what it wrote — a deploy config calling it would evaluate\n\t// the whole runtime graph inside its own toolchain. It runs before the build\n\t// context rather than after the generators because the entry point's drivers\n\t// are decided from it.\n\tconst constructSources: Record<string, ConstructSource> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst declared = constructGlobs\n\t\t? await discover({\n\t\t\t\tpatterns: constructGlobs,\n\t\t\t\tcwd: appRoot,\n\t\t\t\tbustCache,\n\t\t\t\tsources: constructSources,\n\t\t\t\tbackground,\n\t\t\t})\n\t\t: {};\n\n\t// A surface that serves itself is started, not generated for: its routes\n\t// are the construct's, and the entry only has to call it.\n\tconst selfServing = selfServingSurface({\n\t\tdeclared,\n\t\tsources: constructSources,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t});\n\n\tif (selfServing) {\n\t\tawait writeSurfaceEntry(\n\t\t\tjoin(appRoot, '.gkm', 'server'),\n\t\t\tselfServing.source,\n\t\t);\n\t\tlogger.log(\n\t\t\t`Generated a server for ${selfServing.id} from its own declaration`,\n\t\t);\n\n\t\t// An image needs a process that listens, which the dev entry is not.\n\t\tif (production?.bundle && !input.skipBundle) {\n\t\t\tconst outputDir = join(appRoot, '.gkm', 'server');\n\t\t\tconst entryPoint = await writeSurfaceServer(outputDir, production);\n\t\t\tconst { bundleServer } = await import('./bundler');\n\t\t\tawait bundleServer({\n\t\t\t\tentryPoint,\n\t\t\t\toutputDir: join(outputDir, 'dist'),\n\t\t\t\tminify: production.minify,\n\t\t\t\tsourcemap: false,\n\t\t\t\texternal: production.external,\n\t\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t\t});\n\t\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);\n\t\t}\n\n\t\treturn { selfServing: selfServing.id };\n\t}\n\n\tconst derived = ownersContext({\n\t\tdeclared,\n\t\tsources: constructSources,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t\tdatabaseApi,\n\t});\n\n\t// The broker, only when something declares a topic or a queue: a project\n\t// with no events registers nothing and never resolves `@geekmidas/events`.\n\tconst eventsBackends = eventsBackendsIn(declared, eventsBackend);\n\n\tconst buildContext: BuildContext = {\n\t\t...derived,\n\t\ttelescope,\n\t\thooks,\n\t\tproduction,\n\t\tconstructGlobs,\n\t\tcacheBackend,\n\t\t// Mail is SMTP everywhere; the provider is whatever the stage's URL\n\t\t// names, so there is no choice to read here.\n\t\temailBackend: DEFAULT_EMAIL,\n\t\t// Both halves of \"where does the cache live\": the declaration for one\n\t\t// that named its database, and the deploy target's default for one that\n\t\t// named nowhere. Reading only the default registers a driver for a\n\t\t// protocol the target never composes.\n\t\tstorageDrivers: driversFor({\n\t\t\tappRoot,\n\t\t\tcache: cacheBackendsIn(declared, cacheBackend),\n\t\t\tevents: eventsBackends,\n\t\t}),\n\t\teventsBackends,\n\t\tmarkOptional: input.markOptional ?? false,\n\t\t...(production && {\n\t\t\ttelemetry: telemetryFor({\n\t\t\t\tappRoot,\n\t\t\t\tsurfaceId: derived.surface?.id,\n\t\t\t\tworkspaceName: input.workspaceName,\n\t\t\t}),\n\t\t}),\n\t};\n\n\t// Initialize generators\n\tconst endpointGenerator = new EndpointGenerator();\n\tconst functionGenerator = new FunctionGenerator();\n\tconst cronGenerator = new CronGenerator();\n\tconst subscriberGenerator = new SubscriberGenerator();\n\tconst queueGenerator = new QueueGenerator();\n\tconst topicGenerator = new TopicGenerator();\n\n\t// One glob, every kind.\n\t//\n\t// Six globs was six things to keep in step, and a handler in the wrong\n\t// directory simply never loaded. It was never necessary: each generator\n\t// already filters what it loads by a type predicate — `Endpoint.isEndpoint`,\n\t// `Cron.isCron` — so which *kind* a module exports comes from the value, and\n\t// the glob only ever had to say where to look. It says it once.\n\tconst code = constructGlobs;\n\n\tconst [\n\t\tloadedEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t] = await Promise.all([\n\t\tendpointGenerator.load(code, appRoot, bustCache),\n\t\tfunctionGenerator.load(code, appRoot, bustCache),\n\t\tcronGenerator.load(code, appRoot, bustCache),\n\t\tsubscriberGenerator.load(code, appRoot, bustCache),\n\t\tqueueGenerator.load(code, appRoot, bustCache),\n\t\ttopicGenerator.load(code, appRoot, bustCache),\n\t]);\n\n\tconst allEndpoints = servedBy(loadedEndpoints, derived.surface);\n\n\tlogger.log(`Found ${allEndpoints.length} endpoints`);\n\tlogger.log(`Found ${allFunctions.length} functions`);\n\tlogger.log(`Found ${allCrons.length} crons`);\n\tlogger.log(`Found ${allSubscribers.length} subscribers`);\n\tlogger.log(`Found ${allQueues.length} queues`);\n\tlogger.log(`Found ${allTopics.length} topics`);\n\n\tif (\n\t\t!input.serveEmpty &&\n\t\tallEndpoints.length === 0 &&\n\t\tallFunctions.length === 0 &&\n\t\tallCrons.length === 0 &&\n\t\tallSubscribers.length === 0 &&\n\t\tallQueues.length === 0 &&\n\t\tallTopics.length === 0\n\t) {\n\t\tlogger.log(\n\t\t\t'No endpoints, functions, crons, subscribers, queues, or topics found to process',\n\t\t);\n\t\treturn {};\n\t}\n\n\t// A RestApi's production image answers HTTP and nothing else. Queues,\n\t// crons and subscribers belong to a Worker — the process with no port —\n\t// even when they sit in the API's directory, so the server it builds leaves\n\t// them out rather than running them beside the routes.\n\tif (production?.subscribers === 'include' && derived.surface) {\n\t\tbuildContext.production = { ...production, subscribers: 'exclude' };\n\t\tconst left = [\n\t\t\t[allCrons.length, 'cron'],\n\t\t\t[allQueues.length, 'queue consumer'],\n\t\t\t[allSubscribers.length, 'subscriber'],\n\t\t]\n\t\t\t.filter(([n]) => (n as number) > 0)\n\t\t\t.map(([n, what]) => `${n} ${what}${n === 1 ? '' : 's'}`);\n\t\tif (left.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t`Serving ${derived.surface.id} only: leaving out ${left.join(', ')} — they run in a Worker's image`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst result = await buildForTarget(\n\t\ttarget,\n\t\tbuildContext,\n\t\tappRoot,\n\t\tworkspaceRoot,\n\t\tendpointGenerator,\n\t\tfunctionGenerator,\n\t\tcronGenerator,\n\t\tsubscriberGenerator,\n\t\tqueueGenerator,\n\t\ttopicGenerator,\n\t\tallEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t\tenableOpenApi,\n\t\tinput.skipBundle ?? false,\n\t\tinput.stage,\n\t);\n\n\t// Each Worker this app carries: its own entry, and — bundling — its own\n\t// bundle beside the server's, which the worker's image copies out.\n\tif (target === 'server' && production?.enabled && input.workspace) {\n\t\tconst appName = Object.entries(input.workspace.apps).find(\n\t\t\t([, app]) =>\n\t\t\t\tresolve(input.workspace!.root, app.path) === resolve(appRoot),\n\t\t)?.[0];\n\t\tconst hosted = workerUnits(input.workspace, declared, background).filter(\n\t\t\t(unit) => unit.app === appName,\n\t\t);\n\t\tawait buildWorkers({\n\t\t\tcontext: buildContext,\n\t\t\tworkers: hosted,\n\t\t\tserverDir: join(appRoot, '.gkm', 'server'),\n\t\t\tcrons: allCrons,\n\t\t\tqueues: allQueues,\n\t\t\tsubscribers: allSubscribers,\n\t\t\tbundle: Boolean(production.bundle && !input.skipBundle),\n\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t});\n\t}\n\n\t// One spec per surface, from the endpoints the build already loaded rather\n\t// than from a second discovery pass over the same files.\n\tawait generateOpenApi(\n\t\tallEndpoints.map(({ construct }) => construct),\n\t\t{ openapi: config.openapi, root: workspaceRoot },\n\t);\n\n\treturn {\n\t\t...result,\n\t\t...(buildContext.databaseApi\n\t\t\t? { databaseApi: buildContext.databaseApi.path }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Write each worker's entry — and, for an image, bundle it — from the\n * runnables built from that worker, and nothing built from another.\n */\nasync function buildWorkers(input: {\n\tcontext: BuildContext;\n\tworkers: readonly WorkerUnit[];\n\tserverDir: string;\n\tcrons: GeneratedConstruct<Cron<any, any, any, any>>[];\n\tqueues: GeneratedConstruct<Queue<any, any, any, any, any, any>>[];\n\tsubscribers: GeneratedConstruct<\n\t\tSubscriber<any, any, any, any, any, any, any>\n\t>[];\n\tbundle: boolean;\n\tstage?: string;\n}): Promise<void> {\n\tconst generator = new WorkerGenerator();\n\tfor (const worker of input.workers) {\n\t\tconst owned = <T extends { construct: { owner?: string } }>(list: T[]) =>\n\t\t\tlist.filter(({ construct }) => construct.owner === worker.id);\n\t\tconst crons = owned(input.crons);\n\t\tconst queues = owned(input.queues);\n\t\tconst subscribers = owned(input.subscribers);\n\n\t\tconst entryPoint = await generator.build({\n\t\t\tcontext: input.context,\n\t\t\tworkerId: worker.id,\n\t\t\toutputDir: workerEntryDir(input.serverDir, worker.id),\n\t\t\tcrons,\n\t\t\tqueues,\n\t\t\tsubscribers,\n\t\t});\n\t\tlogger.log(\n\t\t\t`Generated worker ${worker.id}: ${crons.length} crons, ${queues.length} queues, ${subscribers.length} subscribers`,\n\t\t);\n\n\t\tif (!input.bundle) continue;\n\t\tconst { bundleServer } = await import('./bundler');\n\t\tconst outfile = workerBundleName(worker.id);\n\t\tawait bundleServer({\n\t\t\tentryPoint,\n\t\t\toutputDir: join(input.serverDir, 'dist'),\n\t\t\toutfile,\n\t\t\tminify: input.context.production?.minify ?? false,\n\t\t\tsourcemap: false,\n\t\t\texternal: input.context.production?.external ?? [],\n\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t\tconstructs: [...crons, ...queues, ...subscribers].map((c) => c.construct),\n\t\t});\n\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/${outfile}`);\n\t}\n}\n\nasync function buildForTarget(\n\ttarget: MainProvider,\n\tcontext: BuildContext,\n\tappRoot: string,\n\tworkspaceRoot: string,\n\tendpointGenerator: EndpointGenerator,\n\tfunctionGenerator: FunctionGenerator,\n\tcronGenerator: CronGenerator,\n\tsubscriberGenerator: SubscriberGenerator,\n\tqueueGenerator: QueueGenerator,\n\ttopicGenerator: TopicGenerator,\n\tendpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],\n\tfunctions: GeneratedConstruct<Function<any, any, any, any>>[],\n\tcrons: GeneratedConstruct<Cron<any, any, any, any>>[],\n\tsubscribers: GeneratedConstruct<\n\t\tSubscriber<any, any, any, any, any, any, any>\n\t>[],\n\tqueues: GeneratedConstruct<Queue<any, any, any, any, any, any>>[],\n\ttopics: GeneratedConstruct<Topic<any, any>>[],\n\tenableOpenApi: boolean,\n\tskipBundle: boolean,\n\tstage?: string,\n): Promise<AppBuildOutput> {\n\t// The handlers live beside the app they import. What they are goes into\n\t// the application's manifest, which the root writes, so every path is\n\t// measured from there.\n\tconst outputDir = join(appRoot, '.gkm', target);\n\n\t// What an older build wrote and nothing writes now — the per-provider trees\n\t// and an app-level manifest — would otherwise sit beside the real output\n\t// forever, read by whoever opens `.gkm/` first.\n\tawait Promise.all(\n\t\t[\n\t\t\t...SUPERSEDED_OUTPUT.map((dir) => join(appRoot, '.gkm', dir)),\n\t\t\t...(appRoot === workspaceRoot ? [] : [join(appRoot, '.gkm', 'manifest')]),\n\t\t].map((dir) => rm(dir, { recursive: true, force: true })),\n\t);\n\n\t// A fresh tree for AWS, so a deleted endpoint's handler goes with it. Not\n\t// for the server: `gkm dev` rebuilds into it while its process runs.\n\tif (target === 'aws') await rm(outputDir, { recursive: true, force: true });\n\tawait mkdir(outputDir, { recursive: true });\n\n\tlogger.log(`\\nGenerating handlers for ${target}`);\n\tconst options = { target, root: workspaceRoot };\n\n\t// Build all constructs in parallel.\n\t// context.markOptional is forwarded to each generator so that\n\t// getEnvironment({ markOptional }) produces `VARNAME?` for optional vars.\n\tconst [\n\t\troutes,\n\t\tfunctionInfos,\n\t\tcronInfos,\n\t\tsubscriberInfos,\n\t\tqueueInfos,\n\t\ttopicInfos,\n\t] = await Promise.all([\n\t\tendpointGenerator.build(context, endpoints, outputDir, {\n\t\t\t...options,\n\t\t\tenableOpenApi,\n\t\t}),\n\t\tfunctionGenerator.build(context, functions, outputDir, options),\n\t\tcronGenerator.build(context, crons, outputDir, options),\n\t\tsubscriberGenerator.build(context, subscribers, outputDir, options),\n\t\tqueueGenerator.build(context, queues, outputDir, options),\n\t\ttopicGenerator.build(context, topics, outputDir, options),\n\t]);\n\n\tlogger.log(\n\t\t`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${target}`,\n\t);\n\n\t// What the manifest folds into the declarations they belong to.\n\tconst fields = {\n\t\t...(context.surface ? { surface: context.surface.id } : {}),\n\t\tfunctions: functionInfos,\n\t\tcrons: cronInfos,\n\t\tqueues: queueInfos,\n\t\tsubscribers: subscriberInfos,\n\t};\n\n\tif (target === 'server') {\n\t\t// Every endpoint, as on AWS — its method, path, edges and authorizer —\n\t\t// served by the one process: the app's entry is each one's handler.\n\t\tconst handler = relative(workspaceRoot, join(outputDir, 'app.ts'));\n\t\tconst built: AppBuild = {\n\t\t\t...fields,\n\t\t\troutes: await Promise.all(\n\t\t\t\tendpoints.map(async ({ construct }) => ({\n\t\t\t\t\tpath: construct._path,\n\t\t\t\t\tmethod: construct.method,\n\t\t\t\t\thandler,\n\t\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t\t}),\n\t\t\t\t\tdependencies: construct.constructs,\n\t\t\t\t\tauthorizer: construct.authorizer?.name ?? 'none',\n\t\t\t\t})),\n\t\t\t),\n\t\t};\n\n\t\t// Bundle for production if enabled\n\t\tlet masterKey: string | undefined;\n\t\tif (context.production?.bundle && !skipBundle) {\n\t\t\tlogger.log(`\\n📦 Bundling production server...`);\n\t\t\tconst { bundleServer } = await import('./bundler');\n\n\t\t\t// Collect all constructs for environment variable validation\n\t\t\tconst allConstructs = [\n\t\t\t\t...endpoints.map((e) => e.construct),\n\t\t\t\t...functions.map((f) => f.construct),\n\t\t\t\t...crons.map((c) => c.construct),\n\t\t\t\t...subscribers.map((s) => s.construct),\n\t\t\t\t...queues.map((q) => q.construct),\n\t\t\t];\n\n\t\t\tconst bundleResult = await bundleServer({\n\t\t\t\tentryPoint: join(outputDir, 'server.ts'),\n\t\t\t\toutputDir: join(outputDir, 'dist'),\n\t\t\t\tminify: context.production.minify,\n\t\t\t\tsourcemap: false,\n\t\t\t\texternal: context.production.external,\n\t\t\t\tstage,\n\t\t\t\tconstructs: allConstructs,\n\t\t\t});\n\t\t\tmasterKey = bundleResult.masterKey;\n\t\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);\n\n\t\t\t// The key is written, not printed: it decrypts every secret of the\n\t\t\t// stage, and build output lands in CI logs and scrollback. The\n\t\t\t// fingerprint is enough to tell which key a build used.\n\t\t\tif (masterKey) {\n\t\t\t\tconst keyPath = join(outputDir, MASTER_KEY_FILE);\n\t\t\t\tawait writeFile(keyPath, `${masterKey}\\n`, { mode: 0o600 });\n\t\t\t\tawait chmod(keyPath, 0o600);\n\t\t\t\tlogger.log(`\\n🔐 Secrets encrypted for deployment`);\n\t\t\t\tlogger.log(\n\t\t\t\t\t` Run with GKM_MASTER_KEY set to the key in ${relative(appRoot, keyPath)} (fingerprint ${keyFingerprint(masterKey)})`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn { masterKey, built };\n\t}\n\n\treturn {\n\t\tbuilt: { ...fields, routes },\n\t};\n}\n\n/**\n * Result of building a single app in a workspace.\n */\nexport interface AppBuildResult {\n\tappName: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tsuccess: boolean;\n\toutputPath?: string;\n\terror?: string;\n}\n\n/**\n * Result of workspace build command.\n */\nexport interface WorkspaceBuildResult extends BuildResult {\n\tapps: AppBuildResult[];\n}\n\n/**\n * Detect available package manager.\n * @internal Exported for testing\n */\nexport function detectPackageManager(): 'pnpm' | 'npm' | 'yarn' {\n\tif (existsSync('pnpm-lock.yaml')) return 'pnpm';\n\tif (existsSync('yarn.lock')) return 'yarn';\n\treturn 'npm';\n}\n\n/**\n * The program and argv that run turbo's build.\n *\n * `filters` names the packages to build. Passing none lets turbo infer its own\n * scope from the working directory, which for a workspace root means the\n * workspace package itself — and since that package's `build` script is\n * `gkm build`, inferring is how you get a build that runs itself forever.\n * `workspaceBuildCommand` always names the apps.\n *\n * An array, not a command string: the filters are package names read from the\n * workspace, and each must reach turbo as one argument whatever it holds. Each\n * is `--filter=<name>`, so even a name starting with `-` stays a filter value.\n *\n * @internal Exported for testing\n */\nexport function getTurboArgs(\n\tpm: 'pnpm' | 'npm' | 'yarn',\n\tfilters: string | readonly string[] = [],\n\t/** Build only the named packages, not what they depend on. */\n\t{ only = false }: { only?: boolean } = {},\n): [bin: string, args: string[]] {\n\tconst list = typeof filters === 'string' ? [filters] : filters;\n\tconst turbo = [\n\t\t'turbo',\n\t\t'run',\n\t\t'build',\n\t\t...list.map((f) => `--filter=${f}`),\n\t\t...(only ? ['--only'] : []),\n\t];\n\tswitch (pm) {\n\t\tcase 'pnpm':\n\t\t\treturn ['pnpm', ['exec', ...turbo]];\n\t\tcase 'yarn':\n\t\t\treturn ['yarn', turbo];\n\t\tcase 'npm':\n\t\t\treturn ['npx', turbo];\n\t}\n}\n\n/**\n * The package names turbo should build: one per app in the workspace.\n *\n * Read from each app's own `package.json`, because that is the name turbo\n * knows it by — and the name `loadAppConfig` reads back when turbo runs\n * `gkm build` inside the app, which is what routes that invocation to the\n * single-app path instead of back here.\n *\n * An app without a `package.json` is not a package turbo can run, so it is\n * reported rather than silently skipped.\n *\n * @internal Exported for testing\n */\nexport function turboFilters(\n\tworkspace: NormalizedWorkspace,\n\t{ exclude }: { exclude?: NormalizedAppConfig['type'] } = {},\n): {\n\tfilters: string[];\n\tunpackaged: string[];\n} {\n\tconst filters: string[] = [];\n\tconst unpackaged: string[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === exclude) continue;\n\t\tconst name = appPackageName(workspace, appName);\n\t\tif (name) filters.push(name);\n\t\telse unpackaged.push(appName);\n\t}\n\n\treturn { filters, unpackaged };\n}\n\n/**\n * The package name turbo knows an app by, from its own `package.json`.\n *\n * Not the app's key: `api` in the workspace is `@shop/api` to turbo, and a\n * filter naming the key matches nothing.\n */\nexport function appPackageName(\n\tworkspace: NormalizedWorkspace,\n\tappName: string,\n): string | undefined {\n\tconst app = workspace.apps[appName];\n\tif (!app) return undefined;\n\n\tconst pkgPath = join(workspace.root, app.path, 'package.json');\n\tif (!existsSync(pkgPath)) return undefined;\n\n\tconst name = JSON.parse(readFileSync(pkgPath, 'utf8')).name;\n\treturn typeof name === 'string' && name.length > 0 ? name : undefined;\n}\n\n/**\n * Build all apps in a workspace using Turbo for dependency-ordered parallel builds.\n * @internal Exported for testing\n */\nexport async function workspaceBuildCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: BuildOptions,\n): Promise<WorkspaceBuildResult> {\n\tconst results: AppBuildResult[] = [];\n\tconst apps = Object.entries(workspace.apps);\n\tconst backendApps = apps.filter(([, app]) => app.type === 'backend');\n\tconst frontendApps = apps.filter(([, app]) => app.type === 'web');\n\n\tlogger.log(`\\n🏗️ Building workspace: ${workspace.name}`);\n\tlogger.log(\n\t\t` Backend apps: ${backendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\tlogger.log(\n\t\t` Frontend apps: ${frontendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\n\tif (options.production) {\n\t\tlogger.log(` 🏭 Production mode enabled`);\n\t}\n\n\t// Get build order (topologically sorted by dependencies)\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlogger.log(` Build order: ${buildOrder.join(' → ')}`);\n\n\ttry {\n\t\t// The backends here, in this process, because the manifest is the\n\t\t// application's: the root builds each one, then writes it once from\n\t\t// everything they generated and everything the workspace declares.\n\t\tconst target = options.provider ?? providerOf(workspace);\n\t\tconst builds: AppBuild[] = [];\n\t\tfor (const appName of buildOrder) {\n\t\t\tconst app = workspace.apps[appName];\n\t\t\tconst config = getAppGkmConfig(workspace, appName);\n\t\t\tif (!app || app.type !== 'backend' || !config) continue;\n\n\t\t\tlogger.log(`\\n⚙️ ${appName}`);\n\t\t\tconst output = await buildOneApp({\n\t\t\t\tconfig,\n\t\t\t\toptions,\n\t\t\t\tworkspace,\n\t\t\t\tappRoot: join(workspace.root, app.path),\n\t\t\t\ttarget,\n\t\t\t});\n\t\t\tif (output.built) builds.push(output.built);\n\t\t}\n\n\t\tawait writeManifest({\n\t\t\tworkspaceRoot: workspace.root,\n\t\t\ttarget,\n\t\t\tbuilds,\n\t\t\tconstructs: await discover({\n\t\t\t\tpatterns: allConstructGlobs(workspace),\n\t\t\t\tcwd: workspace.root,\n\t\t\t}),\n\t\t\tbackends: backendsOf(workspace),\n\t\t});\n\n\t\t// Everything else is its own toolchain's — Vite, Next — through turbo.\n\t\tconst { filters, unpackaged } = turboFilters(workspace, {\n\t\t\texclude: 'backend',\n\t\t});\n\t\tif (unpackaged.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No package.json for workspace app(s): ${unpackaged.join(', ')}. ` +\n\t\t\t\t\t`Each app needs one — turbo builds packages, and gkm reads the ` +\n\t\t\t\t\t`name back to know which app it is building.`,\n\t\t\t);\n\t\t}\n\t\tconst pm = detectPackageManager();\n\t\tconst [turboBin, turboArgs] = getTurboArgs(pm, filters, { only: true });\n\n\t\tif (filters.length > 0) {\n\t\t\tlogger.log(`\\n📦 Using ${pm} with Turbo for the other apps...\\n`);\n\t\t\tlogger.log(`Running: ${[turboBin, ...turboArgs].join(' ')}`);\n\n\t\t\t// In the sandbox: the apps' build scripts are the project's code,\n\t\t\t// and see the sandbox's environment rather than this process's —\n\t\t\t// no deploy credential, no registry login. A remote cache's token\n\t\t\t// is passed on only by the default sandbox, for a project the host\n\t\t\t// already trusts.\n\t\t\tconst sandbox =\n\t\t\t\toptions.sandbox ??\n\t\t\t\tnew LocalSandbox({ root: workspace.root, passEnv: ['TURBO_TOKEN'] });\n\t\t\tconst built = await sandbox.exec(turboBin, turboArgs, {\n\t\t\t\tcwd: workspace.root,\n\t\t\t\tenv: {\n\t\t\t\t\t...sandbox.env,\n\t\t\t\t\t// Pass production flag to builds\n\t\t\t\t\tNODE_ENV: options.production ? 'production' : 'development',\n\t\t\t\t},\n\t\t\t\ttimeoutMs: DEFAULT_TIMEOUT_MS,\n\t\t\t\toutput: 'inherit',\n\t\t\t});\n\t\t\tif (built.exitCode !== 0) {\n\t\t\t\tthrow new CommandFailed(\n\t\t\t\t\tturboBin,\n\t\t\t\t\tturboArgs,\n\t\t\t\t\tbuilt.exitCode,\n\t\t\t\t\tbuilt.signal as NodeJS.Signals | null,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Mark all apps as successful\n\t\tfor (const [appName, app] of apps) {\n\t\t\tconst outputPath = getAppOutputPath(workspace, appName, app);\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: true,\n\t\t\t\toutputPath,\n\t\t\t});\n\t\t}\n\n\t\tlogger.log(`\\n✅ Workspace build complete!`);\n\n\t\t// No OpenAPI pass here. Each backend's build above wrote its surfaces'\n\t\t// clients to the root's `.gkm/client/<surface>.ts` before turbo built\n\t\t// the sites that import them as `@<name>/client/<surface>`.\n\n\t\t// Summary\n\t\tlogger.log(`\\n📋 Build Summary:`);\n\t\tfor (const result of results) {\n\t\t\tconst icon =\n\t\t\t\tresult.type === 'backend'\n\t\t\t\t\t? '⚙️'\n\t\t\t\t\t: result.type === 'mobile'\n\t\t\t\t\t\t? '📱'\n\t\t\t\t\t\t: '🌐';\n\t\t\tlogger.log(\n\t\t\t\t` ${icon} ${result.appName}: ${result.outputPath || 'built'}`,\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tconst errorMessage =\n\t\t\terror instanceof Error ? error.message : 'Build failed';\n\t\tlogger.log(`\\n❌ Build failed: ${errorMessage}`);\n\n\t\t// Mark all apps as failed\n\t\tfor (const [appName, app] of apps) {\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t});\n\t\t}\n\n\t\tthrow error;\n\t}\n\n\treturn { apps: results };\n}\n\n/**\n * Get the output path for a built app.\n */\nfunction getAppOutputPath(\n\tworkspace: NormalizedWorkspace,\n\t_appName: string,\n\tapp: NormalizedAppConfig,\n): string {\n\tconst appPath = join(workspace.root, app.path);\n\n\tif (app.type === 'mobile') {\n\t\t// Mobile builds are produced by the framework's own toolchain\n\t\t// (e.g. EAS Build) — no local output path.\n\t\treturn '';\n\t}\n\tif (app.type === 'web') {\n\t\tswitch (app.framework) {\n\t\t\tcase 'vite':\n\t\t\tcase 'tanstack-start':\n\t\t\t\treturn join(appPath, 'dist');\n\t\t\tcase 'remix':\n\t\t\t\treturn join(appPath, 'build');\n\t\t\tdefault:\n\t\t\t\treturn join(appPath, '.next');\n\t\t}\n\t}\n\t// Backend .gkm output\n\treturn join(appPath, '.gkm');\n}\n\n/** Format routes for logging. */\nfunction formatRoutes(routes: Routes): string {\n\treturn Array.isArray(routes) ? routes.join(', ') : routes;\n}\n","/**\n * `gkm compose` — a workspace's APIs and sites for one stage, as one Docker\n * Compose stack behind Caddy.\n *\n * A convenience over `gkm deploy --target compose`: the stage defaults to the\n * local one, `--build`/`--pull` choose the images whatever `--tag` says, and\n * `--down` stops the stack. Everything else — the order, the image check, the\n * state, the health checks — is the compose target's, run through the same\n * `deploy()` as any other target, so there is one way a stack comes up.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { loadWorkspaceConfig } from '../config';\nimport { deploy } from '../deploy/deploy';\nimport { parseDevServices } from '../deploy/devServices';\nimport { deployIdentity } from '../deploy/identity.js';\nimport type { DeployResult } from '../deploy/types';\nimport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\tcomposeTarget,\n\tstackOverrideFile,\n} from '../target/compose/index';\nimport { dockerCompose, type StackRef } from './docker';\nimport { type ImageDigests, parseDigests, pinnedRef } from './images';\nimport { type ComposeStack, composeProject, stackDir } from './stack';\n\nexport {\n\tComposeAppsUnhealthy,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n} from '../target/compose/index';\nexport { isMissingManifest, PushDigestUnknown } from './docker';\nexport {\n\tassertImagesExist,\n\tImageDigestMismatch,\n\tImageDigestMissing,\n\tImageDigestsInvalid,\n\tImageTagNotFound,\n\tRegistryRequired,\n\tRegistryUnreachable,\n\tsiteTag,\n} from './images';\nexport {\n\tLogsEndpointConflict,\n\tLogsPasswordMissing,\n\tLogsPasswordWeak,\n\tOPENOBSERVE_IMAGE,\n} from './logs';\nexport {\n\tLogsAllowEmpty,\n\tLogsAllowEntryInvalid,\n\tLogsPortInvalid,\n\tLogsRetentionInvalid,\n} from './logsConfig';\nexport {\n\tREDIS_MAXMEMORY,\n\tREDIS_PASSWORD_KEY,\n\tRedisPasswordMissing,\n\tSTACK_CACHE,\n} from './redis';\nexport {\n\tcomposeStack,\n\tEnvValueMultiline,\n\tLOG_ROTATION,\n\tNothingToCompose,\n\tStageSecretMissing,\n\tStageSeedMissing,\n} from './stack';\n\nexport interface ComposeOptions {\n\t/** The stage to run. Always named: nothing defaults to the local stage. */\n\tstage: string;\n\t/** A release tag: pull every app's image at it, build nothing. */\n\ttag?: string;\n\t/** Build images here, whatever `--tag` says. */\n\tbuild?: boolean;\n\t/** Pull images, whatever `--tag` says — `latest` when no tag is given. */\n\tpull?: boolean;\n\t/**\n\t * With `--build`: push every image built to `deploy.registry`, and start\n\t * nothing — no provisioning, no `up`, nothing recorded. What CI runs.\n\t */\n\tpush?: boolean;\n\t/**\n\t * With `--push`, where each pushed image's `<ref>@sha256:…` is written,\n\t * as JSON by app. With `--tag`/`--pull`, the file to read them back from:\n\t * each image is pulled and run at its digest rather than its tag.\n\t */\n\tdigestsFile?: string;\n\t/** Write the files and print the plan; touch nothing else. */\n\tdryRun?: boolean;\n\t/** Stop the stage's stack. Its volumes are kept. */\n\tdown?: boolean;\n\t/** The workspace — the current directory when absent. */\n\tcwd?: string;\n\t/**\n\t * `--allow-dev-services minio,mailpit`: on a deployed stage, run MinIO\n\t * and Mailpit for the buckets and mail its secrets do not configure.\n\t */\n\tallowDevServices?: string | readonly string[];\n}\n\nexport interface ComposeResult {\n\tstack: ComposeStack;\n\t/** Every file written, absolute. */\n\tfiles: string[];\n\t/** Each app's recorded image — absent on a dry run. */\n\timages?: Record<string, ComposeImage>;\n\t/** What the deploy reports, as `gkm deploy --target compose` would. */\n\tdeploy: DeployResult;\n}\n\n/** `--build` and `--pull` together ask for two different things. */\nexport class ComposeModeConflict extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--build and --pull ask for opposite things: build images from this ' +\n\t\t\t\t'checkout, or pull a tag CI pushed. Pass one of them.',\n\t\t);\n\t\tthis.name = 'ComposeModeConflict';\n\t}\n}\n\n/** Each pushed image as `<ref>@sha256:…`, by app. */\nfunction pushedDigests(run: ComposeRun): ImageDigests {\n\treturn Object.fromEntries(\n\t\tObject.entries(run.images)\n\t\t\t.filter(([, image]) => image.digest)\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([app, image]) => [app, pinnedRef(image.ref, image.digest!)]),\n\t);\n}\n\n/** `gkm compose`. */\nexport async function composeCommand(\n\toptions: ComposeOptions,\n\tdeps: Partial<ComposeDeps> = {},\n): Promise<ComposeResult | undefined> {\n\tif (options.build && options.pull) throw new ComposeModeConflict();\n\tif (options.push && !options.build) throw new ComposePushNeedsBuild();\n\tconst pulls = !options.build && (options.pull || options.tag !== undefined);\n\tif (options.digestsFile && !options.push && !pulls) {\n\t\tthrow new ComposePinNeedsPull();\n\t}\n\tconst allowDevServices = parseDevServices(options.allowDevServices);\n\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\t// Read here only for what the command adds: the project `--down` stops. The deploy loads it again, as it\n\t// loads every project, in its sandbox.\n\tconst { workspace } = await loadWorkspaceConfig(cwd);\n\tconst { stage } = options;\n\n\tif (options.down) {\n\t\tconst override = stackOverrideFile(workspace.root, stage);\n\t\tconst ref: StackRef = {\n\t\t\tproject: composeProject(deployIdentity(workspace, stage)),\n\t\t\tfile: join(workspace.root, stackDir(stage), 'docker-compose.yml'),\n\t\t\t...(existsSync(override) ? { overrides: [override] } : {}),\n\t\t\tcwd: workspace.root,\n\t\t};\n\t\tawait (deps.docker ?? dockerCompose).down(ref);\n\t\tconsole.log(`🛑 Stopped ${ref.project}. Its volumes are kept.`);\n\t\treturn undefined;\n\t}\n\n\tlet finished: ComposeRun | undefined;\n\tconst mode = options.build ? 'build' : options.pull ? 'pull' : undefined;\n\tconst tag = options.tag ?? (options.pull ? 'latest' : undefined);\n\n\t// A pinned release: each image at the digest its push reported.\n\tconst pin =\n\t\toptions.digestsFile && pulls\n\t\t\t? {\n\t\t\t\t\tfile: options.digestsFile,\n\t\t\t\t\tdigests: parseDigests(\n\t\t\t\t\t\toptions.digestsFile,\n\t\t\t\t\t\tawait readFile(resolve(cwd, options.digestsFile), 'utf-8'),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: undefined;\n\n\tconst run = deploy({\n\t\tcwd,\n\t\tstage,\n\t\ttarget: 'compose',\n\t\t// The target with this command's switches, in place of the built-in.\n\t\ttargets: {\n\t\t\tcompose: composeTarget({\n\t\t\t\t...deps,\n\t\t\t\t...(mode ? { mode } : {}),\n\t\t\t\t...(options.push ? { push: true } : {}),\n\t\t\t\t...(pin ? { pin } : {}),\n\t\t\t\treport: (done) => {\n\t\t\t\t\tfinished = done;\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t\t...(tag ? { tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.push ? { buildOnly: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\tconst result = await run.result;\n\tif (!finished) return undefined;\n\n\tif (options.push && !options.dryRun) {\n\t\tconst digests = pushedDigests(finished);\n\t\tconsole.log(`\\n✅ Pushed ${Object.keys(digests).length} image(s):`);\n\t\tfor (const [app, ref] of Object.entries(digests)) {\n\t\t\tconsole.log(` ${app.padEnd(12)} ${ref}`);\n\t\t}\n\t\tif (options.digestsFile) {\n\t\t\tconst file = resolve(cwd, options.digestsFile);\n\t\t\tawait mkdir(dirname(file), { recursive: true });\n\t\t\tawait writeFile(file, `${JSON.stringify(digests, null, 2)}\\n`);\n\t\t\tconsole.log(`\\n📝 Wrote the digests to ${options.digestsFile}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tstack: finished.stack,\n\t\tfiles: finished.files,\n\t\t...(options.dryRun ? {} : { images: finished.images }),\n\t\tdeploy: result,\n\t};\n}\n","let _debug = false;\n\n/**\n * Enable debug mode globally.\n * When enabled, verbose error details are shown everywhere.\n */\nexport function enableDebug(): void {\n\t_debug = true;\n}\n\n/**\n * Check if debug mode is active.\n * Activated by `--debug` flag or `GKM_DEBUG=1` env var.\n */\nexport function isDebug(): boolean {\n\treturn _debug || process.env.GKM_DEBUG === '1';\n}\n\n/**\n * Log a message only when debug mode is active.\n */\nexport function debug(...args: unknown[]): void {\n\tif (isDebug()) {\n\t\tconsole.debug('[debug]', ...args);\n\t}\n}\n\n/**\n * Format a fatal error for display.\n * Always includes the full stack trace since these are process-ending errors.\n */\nexport function formatError(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tlet output = error.stack ?? error.message;\n\n\t// Include cause chain if present\n\tlet cause = error.cause;\n\twhile (cause) {\n\t\tif (cause instanceof Error) {\n\t\t\toutput += `\\n\\nCaused by: ${cause.stack ?? cause.message}`;\n\t\t\tcause = cause.cause;\n\t\t} else {\n\t\t\toutput += `\\n\\nCaused by: ${String(cause)}`;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn output;\n}\n\n/**\n * Format a non-fatal error for display.\n * Shows only the message by default, full stack in debug mode.\n */\nexport function formatWarning(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tif (!isDebug()) {\n\t\treturn error.message;\n\t}\n\n\treturn error.stack ?? error.message;\n}\n","import {\n\tgetDokployCredentials,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployRegistryId,\n} from '../auth';\nimport { DokployApi } from '../target/dokploy/dokploy-api';\nimport type { DokployDeployConfig } from './types';\n\nconst logger = console;\n\nexport interface DeployInitOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Project name (creates new or uses existing) */\n\tprojectName: string;\n\t/** Application name */\n\tappName: string;\n\t/** Use existing project ID instead of creating/finding */\n\tprojectId?: string;\n\t/** Registry ID in Dokploy (optional, uses stored if available) */\n\tregistryId?: string;\n}\n\nexport interface RegistrySetupOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Registry name (for display in Dokploy) */\n\tregistryName: string;\n\t/** Registry URL (e.g., ghcr.io, docker.io) */\n\tregistryUrl: string;\n\t/** Registry username */\n\tusername: string;\n\t/** Registry password or token */\n\tpassword: string;\n\t/** Image prefix (optional, e.g., org-name) */\n\timagePrefix?: string;\n}\n\n/**\n * Get the Dokploy API token from stored credentials or environment\n */\nasync function getApiToken(): Promise<string> {\n\tconst token = await getDokployToken();\n\tif (!token) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found.\\n' +\n\t\t\t\t'Run \"gkm login --service dokploy\" to authenticate, or set DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\treturn token;\n}\n\n/**\n * Get Dokploy endpoint from options or stored credentials\n */\nasync function getEndpoint(providedEndpoint?: string): Promise<string> {\n\tif (providedEndpoint) {\n\t\treturn providedEndpoint;\n\t}\n\n\tconst stored = await getDokployCredentials();\n\tif (stored) {\n\t\treturn stored.endpoint;\n\t}\n\n\tthrow new Error(\n\t\t'Dokploy endpoint not specified.\\n' +\n\t\t\t'Either run \"gkm login --service dokploy\" first, or provide --endpoint.',\n\t);\n}\n\n/**\n * Create a Dokploy API client\n */\nasync function createApi(endpoint: string): Promise<DokployApi> {\n\tconst token = await getApiToken();\n\treturn new DokployApi({ baseUrl: endpoint, token });\n}\n\n/**\n * Initialize Dokploy deployment configuration\n */\nexport async function deployInitCommand(\n\toptions: DeployInitOptions,\n): Promise<DokployDeployConfig> {\n\tconst {\n\t\tprojectName,\n\t\tappName,\n\t\tprojectId: existingProjectId,\n\t\tregistryId,\n\t} = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🚀 Initializing Dokploy deployment...`);\n\tlogger.log(` Endpoint: ${endpoint}`);\n\n\t// Step 1: Find or create project\n\tlet projectId: string;\n\n\tif (existingProjectId) {\n\t\tprojectId = existingProjectId;\n\t\tlogger.log(`\\n📁 Using existing project: ${projectId}`);\n\t} else {\n\t\tlogger.log(`\\n📁 Looking for project: ${projectName}`);\n\n\t\tconst projects = await api.listProjects();\n\t\tconst existingProject = projects.find(\n\t\t\t(p) => p.name.toLowerCase() === projectName.toLowerCase(),\n\t\t);\n\n\t\tif (existingProject) {\n\t\t\tprojectId = existingProject.projectId;\n\t\t\tlogger.log(` Found existing project: ${projectId}`);\n\t\t} else {\n\t\t\tlogger.log(` Creating new project...`);\n\t\t\tconst result = await api.createProject(projectName);\n\t\t\tprojectId = result.project.projectId;\n\t\t\tlogger.log(` ✓ Created project: ${projectId}`);\n\t\t}\n\t}\n\n\t// Step 2: Get project to find environment\n\tconst project = await api.getProject(projectId);\n\tlet environmentId: string;\n\n\tconst firstEnv = project.environments?.[0];\n\tif (firstEnv) {\n\t\tenvironmentId = firstEnv.environmentId;\n\t} else {\n\t\t// Create a default environment\n\t\tlogger.log(` Creating production environment...`);\n\t\tconst env = await api.createEnvironment(projectId, 'production');\n\t\tenvironmentId = env.environmentId;\n\t}\n\n\t// Step 3: Create application\n\tlogger.log(`\\n📦 Creating application: ${appName}`);\n\tconst application = await api.createApplication(\n\t\tappName,\n\t\tprojectId,\n\t\tenvironmentId,\n\t);\n\tlogger.log(` ✓ Created application: ${application.applicationId}`);\n\n\t// Step 4: Configure registry if provided\n\tif (registryId) {\n\t\tlogger.log(`\\n🔧 Configuring registry: ${registryId}`);\n\t\tawait api.updateApplication(application.applicationId, { registryId });\n\t\tlogger.log(` ✓ Registry configured`);\n\t} else {\n\t\t// List available registries\n\t\ttry {\n\t\t\tconst registries = await api.listRegistries();\n\t\t\tif (registries.length > 0) {\n\t\t\t\tlogger.log(`\\n📋 Available registries:`);\n\t\t\t\tfor (const reg of registries) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlogger.log(`\\n To use a registry, run with --registry-id <id>`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore registry listing errors\n\t\t}\n\t}\n\n\t// Step 5: Build config\n\tconst config: DokployDeployConfig = {\n\t\tendpoint,\n\t\tprojectId,\n\t\tapplicationId: application.applicationId,\n\t};\n\n\t// Nothing is written into gkm.config.ts: the ids are rediscovered by name\n\t// on the next deploy and remembered in the state file.\n\tlogger.log(`\\n✅ Dokploy deployment initialized!`);\n\tlogger.log(`\\n📋 Configuration:`);\n\tlogger.log(` Project ID: ${projectId}`);\n\tlogger.log(` Application ID: ${application.applicationId}`);\n\tlogger.log(`\\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);\n\tlogger.log(`\\n📝 Next steps:`);\n\tlogger.log(` 1. Initialize secrets: gkm secrets:init --stage production`);\n\tlogger.log(` 2. Deploy: gkm deploy --stage production`);\n\n\treturn config;\n}\n\n/**\n * List available Dokploy resources\n */\nexport async function deployListCommand(options: {\n\tendpoint?: string;\n\tresource: 'projects' | 'registries';\n}): Promise<void> {\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tconst { resource } = options;\n\n\tif (resource === 'projects') {\n\t\tlogger.log(`\\n📁 Projects in ${endpoint}:`);\n\t\tconst projects = await api.listProjects();\n\n\t\tif (projects.length === 0) {\n\t\t\tlogger.log(' No projects found');\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const project of projects) {\n\t\t\tlogger.log(`\\n ${project.name} (${project.projectId})`);\n\t\t\tif (project.description) {\n\t\t\t\tlogger.log(` ${project.description}`);\n\t\t\t}\n\t\t}\n\t} else if (resource === 'registries') {\n\t\tlogger.log(`\\n🐳 Registries in ${endpoint}:`);\n\t\tconst registries = await api.listRegistries();\n\n\t\tif (registries.length === 0) {\n\t\t\tlogger.log(' No registries configured');\n\t\t\tlogger.log(' Run \"gkm registry:setup\" to configure a registry');\n\t\t\treturn;\n\t\t}\n\n\t\tconst storedRegistryId = await getDokployRegistryId();\n\n\t\tfor (const registry of registries) {\n\t\t\tconst isDefault = registry.registryId === storedRegistryId;\n\t\t\tconst marker = isDefault ? ' (default)' : '';\n\t\t\tlogger.log(\n\t\t\t\t`\\n ${registry.registryName}${marker} (${registry.registryId})`,\n\t\t\t);\n\t\t\tlogger.log(` URL: ${registry.registryUrl}`);\n\t\t\tlogger.log(` Username: ${registry.username}`);\n\t\t\tif (registry.imagePrefix) {\n\t\t\t\tlogger.log(` Prefix: ${registry.imagePrefix}`);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Setup a Docker registry in Dokploy\n */\nexport async function registrySetupCommand(\n\toptions: RegistrySetupOptions,\n): Promise<string> {\n\tconst { registryName, registryUrl, username, password, imagePrefix } =\n\t\toptions;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🐳 Setting up Docker registry in Dokploy...`);\n\tlogger.log(` Endpoint: ${endpoint}`);\n\n\t// Check if registry with same URL already exists\n\tconst existingRegistries = await api.listRegistries();\n\tconst existing = existingRegistries.find(\n\t\t(r) =>\n\t\t\tr.registryUrl === registryUrl ||\n\t\t\tr.registryName.toLowerCase() === registryName.toLowerCase(),\n\t);\n\n\tlet registryId: string;\n\n\tif (existing) {\n\t\tlogger.log(`\\n📋 Found existing registry: ${existing.registryName}`);\n\t\tlogger.log(` Updating credentials...`);\n\n\t\tawait api.updateRegistry(existing.registryId, {\n\t\t\tregistryName,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\timagePrefix,\n\t\t});\n\n\t\tregistryId = existing.registryId;\n\t\tlogger.log(` ✓ Registry updated: ${registryId}`);\n\t} else {\n\t\tlogger.log(`\\n📦 Creating registry: ${registryName}`);\n\n\t\tconst registry = await api.createRegistry(\n\t\t\tregistryName,\n\t\t\tregistryUrl,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\t{ imagePrefix },\n\t\t);\n\n\t\tregistryId = registry.registryId;\n\t\tlogger.log(` ✓ Registry created: ${registryId}`);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\tlogger.log(`\\n💾 Saved registry ID to ~/.gkm/credentials.json`);\n\n\tlogger.log(`\\n✅ Registry setup complete!`);\n\tlogger.log(`\\n📋 Registry Details:`);\n\tlogger.log(` ID: ${registryId}`);\n\tlogger.log(` Name: ${registryName}`);\n\tlogger.log(` URL: ${registryUrl}`);\n\tlogger.log(` Username: ${username}`);\n\tif (imagePrefix) {\n\t\tlogger.log(` Prefix: ${imagePrefix}`);\n\t}\n\n\tlogger.log(\n\t\t`\\n📝 The registry ID is now stored and will be used automatically`,\n\t);\n\tlogger.log(` when deploying with \"gkm deploy --target dokploy\"`);\n\n\treturn registryId;\n}\n\n/**\n * Use an existing registry (set as default)\n */\nexport async function registryUseCommand(options: {\n\tendpoint?: string;\n\tregistryId: string;\n}): Promise<void> {\n\tconst { registryId } = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🔧 Setting default registry...`);\n\n\t// Verify the registry exists\n\ttry {\n\t\tconst registry = await api.getRegistry(registryId);\n\t\tlogger.log(` Found registry: ${registry.registryName}`);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Registry not found: ${registryId}\\n` +\n\t\t\t\t'Run \"gkm deploy:list registries\" to see available registries.',\n\t\t);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\n\tlogger.log(`\\n✅ Default registry set: ${registryId}`);\n\tlogger.log(` This registry will be used for future deployments.`);\n}\n","/**\n * State Management CLI Commands\n *\n * Commands for managing deployment state across local and remote stores.\n *\n * Every command goes through a `StateStore`, the same one deploy writes\n * through: a v1 state is migrated on the way, resource records travel with\n * the state, and a copy is a conditional write — so `state:push` cannot\n * silently replace what a deploy wrote a moment earlier.\n */\n\nimport { loadWorkspaceConfig } from '../config';\nimport type { NormalizedWorkspace } from '../workspace/types';\nimport { LocalStateStore } from './LocalStateStore';\nimport {\n\tcreateStateStore,\n\ttype ResourceRecord,\n\ttype StateStore,\n\ttype StoredStageState,\n} from './StateStore';\nimport type { DokployStageState } from './state';\n\n/** What `state:show` prints in place of a secret. */\nexport const MASKED = '********';\n\n/**\n * A copy of `state` with every secret replaced by `MASKED`: database\n * passwords, generated secrets and the backup IAM keys. `state:show` is run\n * to look up ids, in terminals and CI logs; nothing it prints should be\n * usable as a credential.\n */\nexport function maskStateSecrets(state: DokployStageState): DokployStageState {\n\tconst masked: DokployStageState = structuredClone(state);\n\n\tfor (const credentials of Object.values(masked.appCredentials ?? {})) {\n\t\tcredentials.dbPassword = MASKED;\n\t}\n\tfor (const secrets of Object.values(masked.generatedSecrets ?? {})) {\n\t\tfor (const name of Object.keys(secrets)) {\n\t\t\tsecrets[name] = MASKED;\n\t\t}\n\t}\n\tif (masked.backups) {\n\t\tmasked.backups.iamAccessKeyId = MASKED;\n\t\tmasked.backups.iamSecretAccessKey = MASKED;\n\t}\n\n\treturn masked;\n}\n\nexport interface StateCommandOptions {\n\tstage: string;\n}\n\n/**\n * Pull state from remote to local.\n * `gkm state:pull --stage=<stage>`\n */\nexport async function statePullCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst { local, remote } = await remoteAndLocal(workspace);\n\n\tconsole.log(`Pulling state for stage: ${options.stage}...`);\n\tconst pulled = await copyUnderLock(\n\t\tremote,\n\t\tlocal,\n\t\tlocal,\n\t\toptions.stage,\n\t\t'state:pull',\n\t);\n\n\tif (pulled) {\n\t\tconsole.log('State pulled successfully.');\n\t\tprintStateSummary(pulled.state);\n\t} else {\n\t\tconsole.log('No remote state found for this stage.');\n\t}\n}\n\n/**\n * Push local state to remote.\n * `gkm state:push --stage=<stage>`\n */\nexport async function statePushCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst { local, remote } = await remoteAndLocal(workspace);\n\n\tconsole.log(`Pushing state for stage: ${options.stage}...`);\n\t// Under the remote stage's lock: a push while a deploy of the stage runs\n\t// would replace the state that deploy is journaling into. It gets\n\t// `StateLocked` naming the deploy instead.\n\tconst pushed = await copyUnderLock(\n\t\tlocal,\n\t\tremote,\n\t\tremote,\n\t\toptions.stage,\n\t\t'state:push',\n\t);\n\n\tif (pushed) {\n\t\tconsole.log('State pushed successfully.');\n\t\tprintStateSummary(pushed.state);\n\t} else {\n\t\tconsole.log('No local state found for this stage.');\n\t}\n}\n\n/**\n * Show current state.\n * `gkm state:show --stage=<stage>`\n */\nexport async function stateShowCommand(\n\toptions: StateCommandOptions & { json?: boolean },\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\t// The store deploy writes through — the remote one when there is one, read\n\t// directly, so a stale local copy is never what this shows.\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tconst stored = await store.read(options.stage);\n\n\tif (!stored) {\n\t\tconsole.log(`No state found for stage: ${options.stage}`);\n\t\treturn;\n\t}\n\n\tconst state = maskStateSecrets(stored.state);\n\n\tif (options.json) {\n\t\tconsole.log(JSON.stringify(state, null, 2));\n\t} else {\n\t\tprintStateDetails(state);\n\t\tprintUnfinished(stored.resources);\n\t}\n}\n\n/**\n * Release a stage's deploy lock, whoever holds it.\n * `gkm state:unlock --stage=<stage>`\n *\n * For a run that crashed with the lock held. Releasing a lock a live run\n * holds lets a second run race it, so the holder is printed for the caller\n * to check.\n */\nexport async function stateUnlockCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tconst holder = await store.forceUnlock(options.stage);\n\n\tif (!holder) {\n\t\tconsole.log(`Stage ${options.stage} was not locked.`);\n\t\treturn;\n\t}\n\n\tconsole.log(\n\t\t`Released the lock on stage ${options.stage}, held by ${holder.owner}@${holder.host} (pid ${holder.pid}) since ${holder.acquiredAt}.`,\n\t);\n}\n\n/**\n * Compare local and remote state.\n * `gkm state:diff --stage=<stage>`\n */\nexport async function stateDiffCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst stores = await remoteAndLocal(workspace, [\n\t\t'Diff requires a remote provider to compare against.',\n\t]);\n\n\tconsole.log(`Comparing state for stage: ${options.stage}...\\n`);\n\tconst [localStored, remoteStored] = await Promise.all([\n\t\tstores.local.read(options.stage),\n\t\tstores.remote.read(options.stage),\n\t]);\n\tconst local = localStored?.state ?? null;\n\tconst remote = remoteStored?.state ?? null;\n\n\tif (!local && !remote) {\n\t\tconsole.log('No state found (local or remote).');\n\t\treturn;\n\t}\n\n\tif (!local) {\n\t\tconsole.log('Local: (none)');\n\t} else {\n\t\tconsole.log(`Local: Last deployed ${local.lastDeployedAt}`);\n\t}\n\n\tif (!remote) {\n\t\tconsole.log('Remote: (none)');\n\t} else {\n\t\tconsole.log(`Remote: Last deployed ${remote.lastDeployedAt}`);\n\t}\n\n\tconsole.log('');\n\n\t// Compare applications\n\tconst localApps = local?.applications ?? {};\n\tconst remoteApps = remote?.applications ?? {};\n\tconst allApps = new Set([\n\t\t...Object.keys(localApps),\n\t\t...Object.keys(remoteApps),\n\t]);\n\n\tif (allApps.size > 0) {\n\t\tconsole.log('Applications:');\n\t\tfor (const app of allApps) {\n\t\t\tconst localId = localApps[app];\n\t\t\tconst remoteId = remoteApps[app];\n\n\t\t\tif (localId === remoteId) {\n\t\t\t\tconsole.log(` ${app}: ${localId ?? '(none)'}`);\n\t\t\t} else if (!localId) {\n\t\t\t\tconsole.log(` ${app}: (none) -> ${remoteId} [REMOTE ONLY]`);\n\t\t\t} else if (!remoteId) {\n\t\t\t\tconsole.log(` ${app}: ${localId} -> (none) [LOCAL ONLY]`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ${app}: ${localId} (local) != ${remoteId} (remote) [MISMATCH]`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compare services\n\tconst localServices = local?.services ?? {};\n\tconst remoteServices = remote?.services ?? {};\n\n\tif (\n\t\tObject.keys(localServices).length > 0 ||\n\t\tObject.keys(remoteServices).length > 0\n\t) {\n\t\tconsole.log('\\nServices:');\n\t\tconst serviceKeys = new Set([\n\t\t\t...Object.keys(localServices),\n\t\t\t...Object.keys(remoteServices),\n\t\t]);\n\n\t\tfor (const key of serviceKeys) {\n\t\t\tconst localVal = localServices[key as keyof typeof localServices];\n\t\t\tconst remoteVal = remoteServices[key as keyof typeof remoteServices];\n\n\t\t\tif (localVal === remoteVal) {\n\t\t\t\tconsole.log(` ${key}: ${localVal ?? '(none)'}`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ${key}: ${localVal ?? '(none)'} (local) != ${remoteVal ?? '(none)'} (remote)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Resource records: only where the two disagree, since agreeing records\n\t// repeat the applications and services above.\n\tconst localRecords = localStored?.resources ?? {};\n\tconst remoteRecords = remoteStored?.resources ?? {};\n\tconst differing = [\n\t\t...new Set([...Object.keys(localRecords), ...Object.keys(remoteRecords)]),\n\t].filter(\n\t\t(key) =>\n\t\t\tdescribeRecord(localRecords[key]) !== describeRecord(remoteRecords[key]),\n\t);\n\n\tif (differing.length > 0) {\n\t\tconsole.log('\\nResources:');\n\t\tfor (const key of differing) {\n\t\t\tconsole.log(\n\t\t\t\t` ${key}: ${describeRecord(localRecords[key])} (local) != ${describeRecord(remoteRecords[key])} (remote)`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * The stage's local store and its remote one — or, for a workspace that keeps\n * state only locally, the reason there is nothing to move it between.\n */\nasync function remoteAndLocal(\n\tworkspace: NormalizedWorkspace,\n\thint: readonly string[] = [\n\t\t'Add a remote provider in gkm.config.ts:',\n\t\t' state: { provider: \"ssm\", region: \"us-east-1\" }',\n\t],\n): Promise<{ local: LocalStateStore; remote: StateStore }> {\n\tif (!workspace.state || workspace.state.provider === 'local') {\n\t\tconsole.error('No remote state provider configured.');\n\t\tfor (const line of hint) console.error(line);\n\t\tprocess.exit(1);\n\t}\n\n\treturn {\n\t\tlocal: new LocalStateStore(workspace.root),\n\t\tremote: await createStateStore({\n\t\t\tconfig: workspace.state,\n\t\t\tworkspaceRoot: workspace.root,\n\t\t\tworkspaceName: workspace.name,\n\t\t}),\n\t};\n}\n\n/**\n * Makes `to` hold exactly what `from` holds for `stage` — its state and its\n * resource records — while holding `locked`'s lock for the stage. Every\n * write is conditional on the version just read, so anything that changes\n * `to` mid-copy raises `StateVersionConflict` rather than being overwritten.\n */\nasync function copyUnderLock(\n\tfrom: StateStore,\n\tto: StateStore,\n\tlocked: StateStore,\n\tstage: string,\n\toperation: string,\n): Promise<StoredStageState | null> {\n\tconst lock = await locked.lock(stage, { operation });\n\ttry {\n\t\treturn await copyStage(from, to, stage);\n\t} finally {\n\t\tawait lock.release();\n\t}\n}\n\n/** @internal Exported for testing */\nexport async function copyStage(\n\tfrom: StateStore,\n\tto: StateStore,\n\tstage: string,\n): Promise<StoredStageState | null> {\n\tconst source = await from.read(stage);\n\tif (!source) return null;\n\n\tconst target = await to.read(stage);\n\tlet version = await to.write(stage, source.state, {\n\t\texpectedVersion: target?.version ?? null,\n\t});\n\n\t// The source's records, exactly: one only the target has describes a\n\t// resource the source does not know about, and keeping it would make the\n\t// copy something neither side wrote.\n\tfor (const key of Object.keys(target?.resources ?? {})) {\n\t\tif (key in source.resources) continue;\n\t\tversion = await to.deleteResource(stage, key, {\n\t\t\texpectedVersion: version,\n\t\t});\n\t}\n\tfor (const { updatedAt: _stamped, ...record } of Object.values(\n\t\tsource.resources,\n\t)) {\n\t\tversion = await to.putResource(stage, record, {\n\t\t\texpectedVersion: version,\n\t\t});\n\t}\n\n\treturn source;\n}\n\nfunction describeRecord(record: ResourceRecord | undefined): string {\n\tif (!record) return '(none)';\n\treturn record.id ? `${record.status} ${record.id}` : record.status;\n}\n\n/** Resources a run marked `pending` and never saw created. */\nfunction printUnfinished(resources: Record<string, ResourceRecord>): void {\n\tconst pending = Object.values(resources).filter(\n\t\t(record) => record.status === 'pending',\n\t);\n\tif (pending.length === 0) return;\n\n\tconsole.log('');\n\tconsole.log('Unfinished (a deploy stopped while creating these):');\n\tfor (const record of pending) {\n\t\tconsole.log(` ${record.key}`);\n\t}\n}\n\nfunction printStateSummary(state: DokployStageState): void {\n\tconst appCount = Object.keys(state.applications).length;\n\tconst hasPostgres = !!state.services.postgresId;\n\tconst hasRedis = !!state.services.redisId;\n\n\tconsole.log(` Stage: ${state.stage}`);\n\tconsole.log(` Applications: ${appCount}`);\n\tconsole.log(` Postgres: ${hasPostgres ? 'configured' : 'none'}`);\n\tconsole.log(` Redis: ${hasRedis ? 'configured' : 'none'}`);\n\tconsole.log(` Last deployed: ${state.lastDeployedAt}`);\n}\n\nfunction printStateDetails(state: DokployStageState): void {\n\tconsole.log(`Stage: ${state.stage}`);\n\tconsole.log(`Environment ID: ${state.environmentId}`);\n\tconsole.log(`Last Deployed: ${state.lastDeployedAt}`);\n\tconsole.log('');\n\n\tconsole.log('Applications:');\n\tconst apps = Object.entries(state.applications);\n\tif (apps.length === 0) {\n\t\tconsole.log(' (none)');\n\t} else {\n\t\tfor (const [name, id] of apps) {\n\t\t\tconsole.log(` ${name}: ${id}`);\n\t\t}\n\t}\n\tconsole.log('');\n\n\tconsole.log('Services:');\n\tif (!state.services.postgresId && !state.services.redisId) {\n\t\tconsole.log(' (none)');\n\t} else {\n\t\tif (state.services.postgresId) {\n\t\t\tconsole.log(` Postgres: ${state.services.postgresId}`);\n\t\t}\n\t\tif (state.services.redisId) {\n\t\t\tconsole.log(` Redis: ${state.services.redisId}`);\n\t\t}\n\t}\n\n\tconst credentials = Object.entries(state.appCredentials ?? {});\n\tif (credentials.length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('Database Credentials:');\n\t\tfor (const [app, { dbUser, dbPassword }] of credentials) {\n\t\t\tconsole.log(` ${app}: ${dbUser} / ${dbPassword}`);\n\t\t}\n\t}\n\n\tconst generated = Object.entries(state.generatedSecrets ?? {});\n\tif (generated.length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('Generated Secrets:');\n\t\tfor (const [app, secrets] of generated) {\n\t\t\tfor (const [name, value] of Object.entries(secrets)) {\n\t\t\t\tconsole.log(` ${app}.${name}: ${value}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (state.backups) {\n\t\tconsole.log('');\n\t\tconsole.log('Backups:');\n\t\tconsole.log(` Bucket: ${state.backups.bucketName}`);\n\t\tconsole.log(` IAM User: ${state.backups.iamUserName}`);\n\t\tconsole.log(` IAM Access Key: ${state.backups.iamAccessKeyId}`);\n\t\tconsole.log(` IAM Secret Key: ${state.backups.iamSecretAccessKey}`);\n\t}\n\n\tif (state.dnsVerified && Object.keys(state.dnsVerified).length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('DNS Verified:');\n\t\tfor (const [hostname, info] of Object.entries(state.dnsVerified)) {\n\t\t\tconsole.log(` ${hostname}: ${info.serverIp} (${info.verifiedAt})`);\n\t\t}\n\t}\n}\n","import { randomBytes } from 'node:crypto';\nimport type {\n\tSecretServiceName,\n\tServiceCredentials,\n\tStageSecrets,\n} from './types';\n\n/**\n * Generate a secure random password using URL-safe base64 characters.\n * @param length Password length (default: 32)\n */\nexport function generateSecurePassword(length = 32): string {\n\treturn randomBytes(Math.ceil((length * 3) / 4))\n\t\t.toString('base64url')\n\t\t.slice(0, length);\n}\n\n/** Default service configurations (localhost for local dev via Docker port mapping) */\nconst SERVICE_DEFAULTS: Record<\n\tSecretServiceName,\n\tOmit<ServiceCredentials, 'password'>\n> = {\n\tpostgres: {\n\t\thost: 'localhost',\n\t\tport: 5432,\n\t\tusername: 'app',\n\t\tdatabase: 'app',\n\t},\n\tredis: {\n\t\thost: 'localhost',\n\t\tport: 6379,\n\t\tusername: 'default',\n\t},\n\tminio: {\n\t\thost: 'localhost',\n\t\tport: 9000,\n\t\tusername: 'app',\n\t\tbucket: 'app',\n\t},\n\tmailpit: {\n\t\thost: 'localhost',\n\t\tport: 1025,\n\t\tusername: 'app',\n\t},\n\tlocalstack: {\n\t\thost: 'localhost',\n\t\tport: 4566,\n\t\tusername: 'localstack',\n\t\tregion: 'us-east-1',\n\t},\n};\n\n/** Default credentials for pgboss (not a Docker service, reuses postgres) */\nconst PGBOSS_DEFAULTS: Omit<ServiceCredentials, 'password'> = {\n\thost: 'localhost',\n\tport: 5432,\n\tusername: 'pgboss',\n\tdatabase: 'app',\n};\n\n/**\n * Generate credentials for a specific service.\n */\nexport function generateServiceCredentials(\n\tservice: SecretServiceName,\n): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS[service];\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t};\n}\n\n/**\n * Generate credentials for multiple services.\n */\nexport function generateServicesCredentials(\n\tservices: SecretServiceName[],\n): StageSecrets['services'] {\n\tconst result: StageSecrets['services'] = {};\n\n\tfor (const service of services) {\n\t\tresult[service] = generateServiceCredentials(service);\n\t}\n\n\treturn result;\n}\n\n/**\n * Generate connection URL for PostgreSQL.\n */\nexport function generatePostgresUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, database } = creds;\n\treturn `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;\n}\n\n/**\n * Generate connection URL for Redis.\n */\nexport function generateRedisUrl(creds: ServiceCredentials): string {\n\tconst { password, host, port } = creds;\n\treturn `redis://:${encodeURIComponent(password)}@${host}:${port}`;\n}\n\n/**\n * Generate endpoint URL for MinIO (S3-compatible).\n */\nexport function generateMinioEndpoint(creds: ServiceCredentials): string {\n\tconst { host, port } = creds;\n\treturn `http://${host}:${port}`;\n}\n\n/**\n * Generate a LocalStack-compatible access key ID.\n * Must start with 'LSIA' prefix and be at least 20 characters.\n * @see https://docs.localstack.cloud/aws/capabilities/config/credentials/\n */\nexport function generateLocalStackAccessKeyId(): string {\n\tconst suffix = randomBytes(12).toString('base64url').slice(0, 16);\n\treturn `LSIA${suffix}`;\n}\n\n/**\n * Generate connection URL for pg-boss (uses PostgreSQL protocol).\n * Format: pgboss://user:pass@host:port/db?schema=pgboss\n */\nexport function generatePgBossUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, database } = creds;\n\treturn `pgboss://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}?schema=pgboss`;\n}\n\n/**\n * Generate connection URLs from service credentials.\n */\nexport function generateConnectionUrls(\n\tservices: StageSecrets['services'],\n): StageSecrets['urls'] {\n\tconst urls: StageSecrets['urls'] = {};\n\n\tif (services.postgres) {\n\t\turls.DATABASE_URL = generatePostgresUrl(services.postgres);\n\t}\n\n\tif (services.redis) {\n\t\turls.REDIS_URL = generateRedisUrl(services.redis);\n\t}\n\n\tif (services.minio) {\n\t\turls.STORAGE_ENDPOINT = generateMinioEndpoint(services.minio);\n\t}\n\n\t// A topic's or queue's own broker URL is reconcile's, derived from the\n\t// declaration. This is what a worker's crons schedule through.\n\tif (services.pgboss) {\n\t\turls.EVENT_PUBLISHER_CONNECTION_STRING = generatePgBossUrl(services.pgboss);\n\t}\n\n\tif (services.mailpit) {\n\t\turls.SMTP_HOST = services.mailpit.host;\n\t\turls.SMTP_PORT = String(services.mailpit.port);\n\t}\n\n\treturn urls;\n}\n\n/**\n * Generate LocalStack service credentials with LSIA-prefixed access key.\n */\nexport function generateLocalStackCredentials(): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS.localstack;\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t\taccessKeyId: generateLocalStackAccessKeyId(),\n\t};\n}\n\n/**\n * Create a new StageSecrets object with generated credentials.\n * @param stage - The deployment stage (e.g., 'development', 'production')\n * @param services - List of services to generate credentials for\n * @param options - Optional configuration\n * @param options.projectName - Project name used to derive the database name (e.g., 'myapp' → 'myapp_dev')\n */\nexport function createStageSecrets(\n\tstage: string,\n\tservices: SecretServiceName[],\n\toptions?: { projectName?: string },\n): StageSecrets {\n\tconst now = new Date().toISOString();\n\tconst serviceCredentials = generateServicesCredentials(services);\n\n\t// Override service defaults with project-derived names if provided\n\tif (options?.projectName) {\n\t\tif (serviceCredentials.postgres) {\n\t\t\tserviceCredentials.postgres.database = `${options.projectName.replace(/-/g, '_')}_dev`;\n\t\t}\n\t\tif (serviceCredentials.minio) {\n\t\t\tserviceCredentials.minio.bucket = options.projectName;\n\t\t\tserviceCredentials.minio.username = options.projectName;\n\t\t}\n\t}\n\n\t// Always create pgboss credentials when postgres is available.\n\t// pgboss reuses postgres host/port/database but with a dedicated user,\n\t// so subscribers work out of the box without explicit events config.\n\tif (serviceCredentials.postgres && !serviceCredentials.pgboss) {\n\t\tserviceCredentials.pgboss = {\n\t\t\t...PGBOSS_DEFAULTS,\n\t\t\tpassword: generateSecurePassword(),\n\t\t\thost: serviceCredentials.postgres.host,\n\t\t\tport: serviceCredentials.postgres.port,\n\t\t\tdatabase: serviceCredentials.postgres.database,\n\t\t};\n\t}\n\n\tconst urls = generateConnectionUrls(serviceCredentials);\n\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: serviceCredentials,\n\t\turls,\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Rotate password for a specific service.\n */\nexport function rotateServicePassword(\n\tsecrets: StageSecrets,\n\tservice: SecretServiceName,\n): StageSecrets {\n\tconst currentCreds = secrets.services[service];\n\tif (!currentCreds) {\n\t\tthrow new Error(`Service \"${service}\" not configured in secrets`);\n\t}\n\n\tconst newCreds: ServiceCredentials = {\n\t\t...currentCreds,\n\t\tpassword: generateSecurePassword(),\n\t};\n\n\tconst newServices = {\n\t\t...secrets.services,\n\t\t[service]: newCreds,\n\t};\n\n\treturn {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tservices: newServices,\n\t\turls: generateConnectionUrls(newServices),\n\t};\n}\n","/**\n * What a migration file is called: a UTC timestamp, then a name.\n *\n * Kept apart from the commands so the scaffold can name the migration it\n * writes the same way `gkm migration` does, without loading a migrator.\n */\n\n/** UTC `YYYYMMDDHHmmss` — sorts as text, and reads as a date. */\nexport function stamp(now = new Date()): string {\n\treturn now\n\t\t.toISOString()\n\t\t.replace(/\\.\\d+Z$/, '')\n\t\t.replace(/\\D/g, '');\n}\n\n/** `Add workouts` → `add_workouts`: the part of a file name after its stamp. */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n\t\t.replace(/[^a-zA-Z0-9]+/g, '_')\n\t\t.replace(/^_+|_+$/g, '')\n\t\t.toLowerCase();\n}\n","/**\n * What a scaffolded project declares, and the keys that derive from it.\n *\n * One place, because three generators need the same three facts: the template\n * writes `new KyselyDatabase<Database, 'Acme'>('Acme')`, the test setup reads\n * `ACME_OWNER_URL` to migrate, and Studio reads `ACME_URL` to connect. Deriving\n * all of them from `@geekmidas/manifest`'s own helpers is what keeps a\n * scaffolded project agreeing with the runtime that discovers it — the same\n * reason the constructs own both faces at runtime.\n */\n\nimport { migrationFolder, provideKey, serviceKey } from '@geekmidas/manifest';\nimport { stamp } from '../migrate/names.js';\nimport type { GeneratedFile, RoutesStructure } from './templates/index.js';\n\n/** The glob every generated config points at. One glob, every kind. */\nexport const CONSTRUCTS_GLOB = './src/constructs/**/*.ts';\n\n/**\n * Where a workspace keeps its constructs: at the root, beside the apps that\n * share them, rather than inside any one of them.\n */\nexport const WORKSPACE_CONSTRUCTS_GLOB = './constructs/**/*.ts';\n\n/**\n * Where each routes structure puts an app's handlers, relative to the app.\n *\n * `.ts` only, never `.tsx`: a TanStack site keeps its own `src/routes/`, and\n * this glob must not import a frontend's route components.\n */\nexport function routesGlob(structure: RoutesStructure): string {\n\tswitch (structure) {\n\t\tcase 'centralized-endpoints':\n\t\t\treturn './src/endpoints/**/*.ts';\n\t\tcase 'centralized-routes':\n\t\t\treturn './src/routes/**/*.ts';\n\t\tcase 'domain-based':\n\t\t\treturn './src/**/routes/*.ts';\n\t}\n}\n\nexport interface ScaffoldedConstruct {\n\t/** The canonical id — what the construct is declared under. */\n\tid: string;\n\t/** The key it is reached under in a handler's service record. */\n\tservice: string;\n\t/** The runtime URL key the target publishes. */\n\turlKey: string;\n}\n\nexport interface ScaffoldedDatabase extends ScaffoldedConstruct {\n\t/** The DDL role's URL — what migrations connect as. */\n\townerUrlKey: string;\n}\n\n/**\n * Plain ids — `Database`, not `Shop`.\n *\n * The workspace `name` already scopes every physical name\n * (`production-shop-database`), so an id that carried the project too\n * would say it twice: `production-shop-shop-cache`. Within a\n * workspace the constructs are declared once, at its root, so there is no\n * second app's `Database` to collide with.\n */\nfunction scaffolded(id: string): ScaffoldedConstruct {\n\treturn { id, service: serviceKey(id), urlKey: provideKey(id, 'url') };\n}\n\n/** The database a project declares. */\nexport function databaseFor(): ScaffoldedDatabase {\n\treturn {\n\t\t...scaffolded('Database'),\n\t\townerUrlKey: provideKey('Database', 'ownerUrl'),\n\t};\n}\n\n/** The bucket a project declares. */\nexport const storageFor = (): ScaffoldedConstruct => scaffolded('Uploads');\n\n/** The mail sender a project declares. */\nexport const emailFor = (): ScaffoldedConstruct => scaffolded('Mail');\n\n/** The cache a project declares. */\nexport const cacheFor = (): ScaffoldedConstruct => scaffolded('Cache');\n\n/**\n * The files a project's declared database needs.\n *\n * Shared by every template, so a worker and an API declare the same database\n * the same way — and so the schema type, the migration, and the id the test\n * setup reads all come from one place.\n */\nexport function databaseFiles(): GeneratedFile[] {\n\tconst db = databaseFor();\n\n\treturn [\n\t\t{\n\t\t\tpath: 'src/constructs/database.ts',\n\t\t\tcontent: `import { KyselyDatabase } from '@geekmidas/constructs/database/kysely';\nimport { CamelCasePlugin, type Generated } from 'kysely';\n\n/**\n * Your database schema. Add tables here.\n *\n * camelCase, because of the plugin below: the columns are snake_case in\n * Postgres (\\`created_at\\`), and Kysely maps between the two.\n */\nexport interface Database {\n users: {\n id: Generated<string>;\n name: string;\n email: string;\n createdAt: Generated<Date>;\n };\n}\n\n/**\n * The app's database, declared once.\n *\n * The container, the database inside it, its roles and schema, and\n * \\`${db.urlKey}\\` all derive from this line — \\`gkm dev\\` reconciles them\n * before the server starts, which is why nothing lists \\`postgres\\` anywhere.\n *\n * Both type arguments or neither: TypeScript has no partial type-argument\n * inference, so passing only \\`Database\\` would leave the name at \\`string\\`\n * and widen the service key away from \\`${db.service}\\`.\n */\nexport const database = new KyselyDatabase<Database, '${db.id}'>('${db.id}', {\n // Yours to keep, change or remove. Every connection this construct opens —\n // every endpoint, the tests — uses it.\n plugins: [new CamelCasePlugin()],\n});\n`,\n\t\t},\n\t\tusersMigration(),\n\t];\n}\n\n/**\n * The table the scaffolded endpoints and factories expect.\n *\n * Its own function because a workspace's API needs it without the database\n * construct beside it — that one lives at the workspace root.\n */\nexport function usersMigration(): GeneratedFile {\n\treturn {\n\t\t// The table the scaffolded endpoints and factories expect, in the folder\n\t\t// named by the database construct. Applied by `gkm migrate`, and by the\n\t\t// test setup before any test runs.\n\t\tpath: `${migrationFolder(databaseFor().id)}/${stamp()}_create_users.ts`,\n\t\tcontent: `import type { Kysely } from 'kysely';\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n await db.schema\n .createTable('users')\n .addColumn('id', 'uuid', (col) =>\n col.primaryKey().defaultTo(db.fn('gen_random_uuid')),\n )\n .addColumn('name', 'varchar(255)', (col) => col.notNull())\n .addColumn('email', 'varchar(255)', (col) => col.notNull().unique())\n .addColumn('created_at', 'timestamptz', (col) =>\n col.notNull().defaultTo(db.fn('now')),\n )\n .execute();\n\n await db.schema\n .createIndex('users_email_idx')\n .on('users')\n .column('email')\n .execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n await db.schema.dropTable('users').execute();\n}\n`,\n\t};\n}\n\n/**\n * What a workspace's `constructs` glob reaches: the root constructs, and the\n * handlers of every app laid out the way `init` was told.\n *\n * Every app in `appsDir` (`apps/*`) rather than the API's own directory.\n * Endpoints are split by the surface they were built from, so naming one app\n * here would only decide which apps' endpoints are silently never loaded.\n */\nexport function workspaceConstructsGlobs(\n\tstructure: RoutesStructure,\n\tappsDir: string,\n): string[] {\n\treturn [\n\t\tWORKSPACE_CONSTRUCTS_GLOB,\n\t\t`./${appsDir}/*/${routesGlob(structure).replace(/^\\.\\//, '')}`,\n\t];\n}\n","import { CONSTRUCTS_GLOB, WORKSPACE_CONSTRUCTS_GLOB } from '../constructs.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * `AGENTS.md` and `CLAUDE.md` for a scaffolded project.\n *\n * A generated project is the first thing an agent sees, and without this it\n * sees only the output: a `gkm.config.ts` naming three keys, a `constructs/`\n * directory, and a build step that reads both. None of that says what the\n * shape *is*, so an agent reconstructs it from the framework it recognises —\n * and writes an Express app beside a `RestApi`, or restates in config what a\n * construct already declared, which is the exact mistake v10 exists to make\n * impossible.\n *\n * Instructions live in `AGENTS.md` because that is the file every tool reads.\n * `CLAUDE.md` imports it rather than copying it: two files saying the same\n * thing is two files to keep in step, and the copy that drifts is always the\n * one nobody opened.\n *\n * Content is derived from the same `TemplateOptions` the rest of the scaffold\n * is built from, so a project with no database gets no database section, and a\n * worker gets no endpoint guide. A guide that documents what was not generated\n * teaches the reader to distrust it.\n */\nexport function generateAgentFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\treturn [\n\t\t{ path: 'AGENTS.md', content: agentsContent(options, template) },\n\t\t{ path: 'CLAUDE.md', content: claudeContent() },\n\t];\n}\n\n/**\n * The import.\n *\n * `@AGENTS.md` rather than a link: Claude Code loads an `@` import into context\n * with the file that names it, and follows no links. A link left the\n * conventions one step away from an agent that never took it — it read the\n * pointer and nothing it pointed at.\n *\n * Deliberately not a summary — a summary is a second copy of the conventions\n * that ages independently of the first.\n */\nfunction claudeContent(): string {\n\treturn `# CLAUDE.md\n\n@AGENTS.md\n\nThe conventions for this project live in \\`AGENTS.md\\`, imported above. It is\nthe single copy, kept that way on purpose: anything repeated here would be a\nsecond thing to keep in step, and the stale one is always the copy nobody\nopened.\n`;\n}\n\nfunction agentsContent(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): string {\n\tconst { name, monorepo, telescope, packageManager } = options;\n\tconst { database } = options.constructs;\n\t// A workspace keeps its constructs at the root, beside the apps that share\n\t// them; a single app keeps them under its own `src/`. Writing the wrong one\n\t// here would be the first thing a reader checked and the first thing that\n\t// taught them not to trust the rest.\n\tconst constructsGlob = monorepo ? WORKSPACE_CONSTRUCTS_GLOB : CONSTRUCTS_GLOB;\n\tconst isWorker = template.name === 'worker';\n\tconst isServerless = template.name === 'serverless';\n\tconst run = packageManager === 'npm' ? 'npx' : `${packageManager} exec`;\n\n\tconst sections: string[] = [];\n\n\tsections.push(`# Agent conventions — ${name}\n\nRules for anyone, human or agent, writing code in this project. Built with\n[\\`@geekmidas/toolbox\\`](https://github.com/geekmidas/toolbox).\n\nRead this before adding a file. Most of what follows exists because the obvious\napproach from another framework produces something that compiles, runs, and is\nwrong in a way nothing catches.`);\n\n\tsections.push(`## The one idea\n\n**Constructs declare; config does not restate.**\n\nA construct — a \\`RestApi\\`, a database, a bucket, a topic — is the single\ndeclaration of a thing. The build reads those declarations and derives\neverything downstream from them: which containers exist, which apps get built,\nwhat the OpenAPI spec says, which env vars a process needs.\n\n\\`gkm.config.ts\\` holds only what no construct can answer:\n\n\\`\\`\\`typescript\nexport default defineWorkspace({\n name: '${name}',\n stages: { local: 'dev', deployed: ['staging', 'prod'], protected: ['prod'] },\n constructs: '${constructsGlob}',\n secrets: { enabled: true },\n});\n\\`\\`\\`\n\nIf you find yourself adding a key to config that names something already\ndeclared in a construct — a path, a port, a route, a container — stop. That is\nthe drift this design removes. The second copy is the one that goes wrong.`);\n\n\tsections.push(`## Layout\n\n\\`\\`\\`\n${layoutBlock(options, template)}\n\\`\\`\\`\n\nHandlers are found by **one glob**, and what kind a file exports is decided by\nthe value it exports, not by the directory it sits in.`);\n\n\tsections.push(`## Commands\n\n\\`\\`\\`bash\n${run} gkm dev # dev server, hot reload, services up, secrets injected\n${run} gkm build # production build\n${run} gkm test # tests, with secrets injected\n${run} gkm exec -- <cmd> # run any command with secrets injected\n${run} gkm openapi # regenerate the OpenAPI spec\n\\`\\`\\`\n\nSecrets are encrypted at rest and injected at run time:\n\n\\`\\`\\`bash\n${run} gkm secrets:set DATABASE_URL postgres://...\n${run} gkm secrets:show\n\\`\\`\\`\n\n**Never run a tool that needs project env vars directly.** It will see an empty\nenvironment and fail in a way that looks like a config bug. Go through\n\\`gkm exec --\\`, which is what injects them.`);\n\n\tif (!isWorker) sections.push(endpointSection(options));\n\tif (isWorker || isServerless) sections.push(backgroundSection(template));\n\tif (database)\n\t\tsections.push(databaseSection(), migrationsSection(), queriesSection());\n\n\tsections.push(`## Environment\n\nEnvironment is parsed once, through \\`envkit\\`, and never read from\n\\`process.env\\` directly:\n\n\\`\\`\\`typescript\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { Credentials } from '@geekmidas/envkit/credentials';\n\nexport const envParser = new EnvironmentParser({\n ...process.env,\n ...Credentials,\n});\n\nexport const config = envParser\n .create((get) => ({\n port: get('PORT').string().transform(Number).default(3000),\n }))\n .parse();\n\\`\\`\\`\n\n\\`Credentials\\` is what \\`gkm dev\\` and \\`gkm exec\\` inject. A bare\n\\`process.env.FOO\\` bypasses both the decryption and the validation, so it reads\nas \\`undefined\\` in exactly the environments that matter.`);\n\n\tsections.push(conventionsSection());\n\tsections.push(testingSection(database));\n\n\tif (telescope || database) {\n\t\tconst tools = [\n\t\t\ttelescope &&\n\t\t\t\t'**Telescope** — requests, exceptions and logs as JSON at `/__telescope/api`',\n\t\t\tdatabase &&\n\t\t\t\t'**Database API** — `gkm dev` serves the declared database, read-only, as JSON at `/__gkm/db`',\n\t\t].filter(Boolean);\n\n\t\tsections.push(`## Dev tools\n\n${tools.map((t) => `- ${t}`).join('\\n')}\n\nDerived from declared constructs and served only by \\`gkm dev\\`: nothing to wire up by hand, and no UI — JSON for whatever tool you point at it.`);\n\t}\n\n\tsections.push(`## Before you say it works\n\n\\`\\`\\`bash\n${run} gkm build\n\\`\\`\\`\n\nA build is the only thing that proves the manifest still resolves. Code that\ntypechecks can still declare two constructs with one id, or a handler no glob\nreaches — and neither shows up until something reads the graph.`);\n\n\treturn `${sections.join('\\n\\n')}\\n`;\n}\n\nfunction layoutBlock(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): string {\n\tconst { monorepo, apiPath } = options;\n\tconst { database } = options.constructs;\n\tconst isWorker = template.name === 'worker';\n\n\tif (monorepo) {\n\t\treturn `constructs/ # every construct: the surface, the database, topics\n${database ? 'db/<construct>/ # migrations/ and seeds/, one folder per database construct\\n' : ''}${apiPath}/ # the API app\ngkm.config.ts # name, constructs glob, secrets`;\n\t}\n\n\tconst lines = [\n\t\t'src/constructs/ # the surface, and anything it declares',\n\t\t'src/config/ # env parser, logger',\n\t];\n\n\tif (!isWorker) lines.push('src/endpoints/ # HTTP handlers');\n\tif (isWorker) {\n\t\tlines.push('src/crons/ # scheduled work');\n\t\tlines.push('src/subscribers/ # topic consumers');\n\t}\n\tif (database)\n\t\tlines.push(\n\t\t\t'db/<construct>/ # migrations/ and seeds/, one folder per database construct',\n\t\t);\n\n\tlines.push('gkm.config.ts # name, constructs glob, secrets');\n\n\treturn lines.join('\\n');\n}\n\nfunction endpointSection(options: TemplateOptions): string {\n\tconst { database } = options.constructs;\n\n\treturn `## Adding an endpoint\n\nAn endpoint is built **from the surface that serves it**. That is where its\nlogger, environment parser and authorizers come from, so none of them is passed\nper endpoint:\n\n\\`\\`\\`typescript\nimport { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const createUser = router\n .post('/users')\n .body(z.object({ name: z.string(), email: z.email() }))\n .output(z.object({ id: z.uuid() }))\n .handle(async ({ body, logger${database ? ', db' : ''} }) => {\n logger.info({ name: body.name }, 'creating user');\n${\n\tdatabase\n\t\t? ` const user = await db\n .insertInto('users')\n .values({ name: body.name, email: body.email })\n .returningAll()\n .executeTakeFirstOrThrow();\n\n return { id: user.id };`\n\t\t: ` return { id: crypto.randomUUID() };`\n}\n });\n\\`\\`\\`\n\n**Export it.** An endpoint that is never exported is never found — the glob\nloads the module and filters by value, so a handler assigned to a local\n\\`const\\` simply does not exist as far as the build is concerned.\n\n**Do not write an HTTP server.** No \\`express()\\`, no \\`new Hono()\\`, no\n\\`app.listen\\`. The entry is generated from the surface; a hand-written server\nbeside it is a second app that shadows the real one.\n\n### Branching the factory\n\nShare what a *group* of endpoints needs by branching once, in\n\\`src/router.ts\\`. A branch starts from the surface itself — there is no\nfactory object to reach through first:\n\n\\`\\`\\`typescript\nexport const router = api${database ? '.database(database)' : ''};\nexport const sessionRouter = router.session(/* … */);\n\\`\\`\\`\n\nA branch is a new factory; the surface is untouched, so a route built straight\nfrom \\`api\\` gets none of what the branch added. What one endpoint alone needs —\na bucket, a cache, another construct — goes on that endpoint with\n\\`.dependsOn([...])\\`, and arrives in \\`services\\`.\n\nBranch for a group, never for a single endpoint — a one-endpoint branch is\nindirection with nothing on the other side of it.`;\n}\n\nfunction backgroundSection(template: TemplateConfig): string {\n\tconst isWorker = template.name === 'worker';\n\n\treturn `## Background work\n\nCrons, subscribers and functions are declared the same way endpoints are: as\nexported values the build discovers.\n\n\\`\\`\\`typescript\n// a scheduled job, built from the worker that runs it\nimport { worker } from '../constructs/worker.ts';\n\nexport const cleanup = worker\n .cron('rate(1 day)')\n .handle(async ({ logger }) => {\n logger.info('cleaning up');\n });\n\\`\\`\\`\n\n\\`\\`\\`typescript\n// a topic subscriber\nimport { userEvents } from '../constructs/topics.ts';\nimport { worker } from '../constructs/worker.ts';\n\nexport const onUserCreated = worker\n .topic(userEvents)\n .subscribe(['user.created'])\n .handle(async ({ events, logger }) => {\n logger.info({ count: events.length }, 'handling user events');\n });\n\\`\\`\\`\n\nHandlers receive a **batch**, not one event. Both transports deliver in\nbatches, so a per-event round trip is a round trip per event for no reason.\n\n${\n\tisWorker\n\t\t? `This project is background work and nothing else — there is no HTTP surface\nto add routes to.`\n\t\t: `Declaring a topic is what makes the broker exist. Nothing lists it in config.`\n}`;\n}\n\nfunction databaseSection(): string {\n\treturn `## Database\n\nThe database is a **construct**, not a hand-rolled service. Declaring it is what\nmakes a Postgres exist locally and a database exist on deploy — nothing names\n\\`postgres\\` in config.\n\nThe router in \\`src/router.ts\\` names it — \\`api.database(database)\\` — and\nevery endpoint built from that router gets it as \\`db\\`, typed by the\nconstruct's schema:\n\n\\`\\`\\`typescript\nexport const listUsers = router\n .get('/users')\n .output(z.array(z.object({ id: z.uuid() })))\n .handle(async ({ db }) => {\n return db.selectFrom('users').selectAll().execute();\n });\n\\`\\`\\`\n\nAn endpoint that needs a different database names it itself, and gets that\none as \\`db\\` instead — the router's is unchanged for every other route:\n\n\\`\\`\\`typescript\nexport const monthly = router\n .get('/reports/monthly')\n .database(reports)\n .handle(async ({ db }) => db.selectFrom('totals').selectAll().execute());\n\\`\\`\\`\n\nQueries go through Kysely. Never open your own connection pool — the one the\nconstruct provides is the one that gets credentials, pooling and shutdown.`;\n}\n\nfunction migrationsSection(): string {\n\treturn `## Migrations and seeds\n\nEach database construct has its own folder, named after the construct:\n\\`Database\\` is \\`db/database/\\`, a tenant \\`AuthDatabase\\` is\n\\`db/auth-database/\\`. It holds two folders and nothing else:\n\n\\`\\`\\`\ndb/database/\n migrations/ # the schema's history, applied once each\n seeds/ # the reference data the app needs, run on every pass\n\\`\\`\\`\n\nEach construct keeps its own history, in its own schema, and is migrated and\nseeded as its own **owner** role — the role a handler runs as cannot create a\ntable.\n\n\\`\\`\\`bash\ngkm migration database add_workouts # db/database/migrations/20260930143012_add_workouts.ts\ngkm migration auth # Better Auth's schema change, as SQL\ngkm migrate # apply every construct's migrations, parents first\ngkm migrate database # apply one construct's\ngkm seed # migrate, then run every seed\ngkm dev --migrate # migrate before the apps start\ngkm dev --seed # migrate and seed before the apps start\n\\`\\`\\`\n\n- Migrations are \\`<UTC timestamp>_<name>.ts\\` exporting \\`up\\` (and\n \\`down\\`), or \\`.sql\\`, which runs whole. Never rename or edit one that has\n been applied — it is recorded by name. Change the schema with a new\n migration.\n- Write migrations with \\`Kysely<unknown>\\` and snake_case names: they are the\n SQL, and the camelCase plugin is the app's, not theirs.\n- \\`gkm migration auth\\` compares Better Auth's schema to its tenant and writes\n only the difference. Run it after adding a Better Auth plugin, and commit the\n file.\n- Seeds always run after migrations, never instead of them. Each is a\n \\`.ts\\` exporting \\`seed(db, { stage })\\`, or \\`.sql\\`, run in name\n order, in a transaction of its own.\n- **Seeds run on every stage, production included.** Write them to be safe\n there. A seed that belongs only somewhere checks the stage it is handed:\n \\`if (stage === 'production') return;\\`. A \\`.sql\\` seed has no stage, so\n it must be right everywhere.\n- Tests migrate and seed themselves: the root vitest config's\n \\`globalSetup: ['@geekmidas/cli/vitest']\\` does both for the test stage\n before any test runs. \\`gkm dev\\` without a flag only reports what is\n pending.\n- A deploy migrates before the new version goes live, so the old version runs\n against the new schema until it is replaced. Keep each migration compatible\n with the code before it: add a column in one release, stop using the old one,\n drop it in a later release.\n\n**Migrations hold schema, never data.** Tables, columns, constraints, indexes.\nNo inserts, updates or deletes against the application's rows.\n\n- **Reference data is a seed.** A permission catalogue, the roles and what\n they grant, a list of statuses — rows the app needs in order to run — are\n written by a seed in \\`db/<construct>/seeds/\\`, never by a migration.\n- **A seed is an upsert, run every time.** There is no history: every seed\n runs on every \\`gkm seed\\`, so changing what it writes and running it again\n is how the change is applied. Write \\`onConflict(…).doUpdateSet(…)\\` (or\n \\`doNothing()\\`), never a bare insert.\n- **Define it once, typed, where every app can import it.** A catalogue\n belongs in code, declared \\`as const\\` so its keys are a union type, and the\n seed writes the table from that constant — so the two cannot drift, and no\n test is needed to keep them in step. The API's guards, the web app's gates\n and a mobile app's gates all name the same keys, and a typo — or a removed\n permission still checked somewhere — fails to compile instead of failing\n closed at runtime.\n- **Sample data is factories'.** Demo users, a tournament for a test — those\n come from test factories, never a seed and never a migration.\n- **A backfill is the one data change a migration makes.** When a schema\n change needs existing rows transformed — a new non-null column filled from\n an old one — do it in the same migration, keyed on the rows it transforms.\n It never inserts rows that were not there.`;\n}\n\nfunction queriesSection(): string {\n\treturn `## Writing queries and relations\n\n**Names: snake_case in Postgres, camelCase in TypeScript.** Kysely's\n\\`CamelCasePlugin\\` does the mapping, and it is set where you can see it — on\nthe database construct in \\`constructs/database.ts\\`:\n\n\\`\\`\\`typescript\nexport const database = new KyselyDatabase<Database, 'Database'>('Database', {\n plugins: [new CamelCasePlugin()],\n});\n\\`\\`\\`\n\nIt is the project's plugin, not the toolbox's: keep it, change it, or remove it,\nbut do it there. It applies to every connection the construct opens: every\nendpoint, and the tests, which connect through the construct.\n\n- The \\`Database\\` interface is camelCase: \\`userId\\`, \\`createdAt\\`.\n- Migrations are the SQL, so they spell columns in snake_case.\n- A raw \\`sql\\` fragment is not rewritten. Refer to columns with\n \\`sql.ref('users.createdAt')\\` or \\`eb.ref(…)\\`, never inside the string.\n- A schema tenant takes its own options. Better Auth's tenant gets no plugin —\n its tables are its own.\n\n**Types.** \\`Generated<T>\\` for every column the database fills in (ids,\ndefaults, timestamps). Derive row types with \\`Selectable<Database['users']>\\`,\n\\`Insertable<…>\\` and \\`Updateable<…>\\` rather than writing them again.\n\n**Relations are foreign keys.** Every \\`*_id\\` column references its parent,\nwith its delete rule written out:\n\n\\`\\`\\`typescript\n.addColumn('user_id', 'uuid', (col) =>\n col.notNull().references('users.id').onDelete('cascade'),\n)\n\\`\\`\\`\n\n- \\`restrict\\` by default.\n- \\`cascade\\` only for rows that belong to the parent — a user's notifications.\n- \\`set null\\` for an optional link, on a nullable column.\n- Index every foreign key column. Postgres does not do it for you.\n\n**Reading related rows: one query, nested.** \\`jsonArrayFrom\\` and\n\\`jsonObjectFrom\\` from \\`kysely/helpers/postgres\\` return children already in\nthe shape of the response:\n\n\\`\\`\\`typescript\nimport { jsonArrayFrom } from 'kysely/helpers/postgres';\n\nconst user = await db\n .selectFrom('users')\n .select((eb) => [\n 'users.id',\n 'users.name',\n jsonArrayFrom(\n eb\n .selectFrom('notifications')\n .select(['notifications.id', 'notifications.body', 'notifications.createdAt'])\n .whereRef('notifications.userId', '=', 'users.id')\n .orderBy('notifications.createdAt', 'desc'),\n ).as('notifications'),\n ])\n .where('users.id', '=', id)\n .executeTakeFirstOrThrow();\n\\`\\`\\`\n\n- Never query once per row in a loop.\n- Use joins to filter, or for a flat result — not to build nested ones by hand.\n- Qualify columns (\\`users.id\\`) once a query touches more than one table.\n- Select the columns the response needs. \\`selectAll()\\` only returns a whole\n row.\n- Nested rows come back as JSON: a timestamp inside \\`jsonArrayFrom\\` is a\n string, not a \\`Date\\`. Say so in the output schema (\\`z.coerce.date()\\`).\n\n**Writes that touch several tables run in one transaction.** Use\n\\`withTransaction(db, async (trx) => …)\\` from \\`@geekmidas/db/kysely\\`: it joins\nthe transaction \\`db\\` already is — an endpoint with an auditor, a test —\ninstead of opening a second one.\n\n**Lists paginate by cursor**, with \\`paginatedSearch\\` from\n\\`@geekmidas/db/kysely/pagination\\`, not by offset.`;\n}\n\nfunction conventionsSection(): string {\n\treturn `## Conventions\n\n**Zod formats are top-level schemas.**\n\n\\`\\`\\`typescript\n// yes\nz.email()\nz.url()\nz.uuid()\n\n// no\nz.string().email()\nz.string().url()\n\\`\\`\\`\n\nZod 4 made each format a schema in its own right. The chained form still runs,\nbut it types as a \\`ZodString\\` carrying a check, so it cannot be composed or\nnarrowed — and it emits different JSON Schema, which means a published API\ncontract would depend on which spelling someone reached for.\n\n\\`envkit\\` is not affected: \\`get('ADMIN_EMAIL').string().email()\\` is its own\nbuilder, not Zod's. Leave it alone.\n\n**Style.** Two-space indent, single quotes, semicolons, trailing commas, 80\ncolumns. \\`import type\\` for type-only imports. Run the formatter rather than\nmatching it by hand.\n\n**Construct ids are unique.** Two constructs sharing an id fails discovery for\nthe whole project, not just the second one.`;\n}\n\nfunction testingSection(database: boolean): string {\n\treturn `## Testing\n\n**Integration over unit.** Prefer the real dependency to a mock — a real\ndatabase, a real cache. Mocks are for things you genuinely cannot run:\nthe filesystem, the clock, external HTTP (use MSW for that).\n\n**Test behaviour, not implementation.** Assert what the code did, not which\nfunctions it called on the way.\n\n\\`\\`\\`bash\n${database ? 'gkm test # starts services, injects secrets, then runs vitest' : 'gkm test'}\n\\`\\`\\`\n\nRun tests through \\`gkm test\\`, not \\`vitest\\` directly${\n\t\tdatabase\n\t\t\t? ' — it is what starts the database and injects the secrets the suite needs'\n\t\t\t: ''\n\t}.${\n\t\tdatabase\n\t\t\t? `\n\n**Factories, one per database.** \\`test/factories/<construct>.ts\\` at the\nproject root — \\`database.ts\\` for \\`Database\\` — exports\n\\`createFactory(db)\\`. A feature test gets each by service name, on that\ntest's transaction — the one \\`db.get\\` returns and its endpoints use — so\nask for it rather than importing and building one. Sign in the way a person\ndoes, through \\`browser.signIn\\`:\n\n\\`\\`\\`typescript\nit('reads a user', async ({ browser, db, factories }) => {\n const factory = await factories.get('database');\n const ada = await factory.insert('users', { email: 'ada@example.com' });\n\n await browser.signIn(ada.email);\n // … act through browser.api …\n\n const app = await db.get('database');\n // … assert on what was written …\n});\n\\`\\`\\``\n\t\t\t: ''\n\t}`;\n}\n","/**\n * Every third-party range `gkm init` writes, in one place.\n *\n * Templates used to pin their own copies, and those drifted: below the peer\n * ranges the `@geekmidas` packages declare (`kysely ~0.28` against a `~0.29.6`\n * peer is two copies of Kysely, and a `Kysely<DB>` from one is not assignable\n * to the other's), and below what the rest of the scaffold assumed (`turbo\n * ~2.3.0` ignores `$TURBO_ROOT$`, which the root `turbo.json` relies on). No\n * generator writes a version literal; a scan test holds them to that.\n *\n * Hand-maintained, unlike `versions.ts`, which `sync-versions` rewrites whole.\n * Current as of 2026-09-27, inside every `@geekmidas` peer range.\n */\nexport const DEPENDENCY_VERSIONS = {\n\t// Server\n\t'better-auth': '~1.7.6',\n\thono: '~4.13.9',\n\t// 1.x: 2.x changes the server entry this scaffold writes.\n\t'@hono/node-server': '~1.19.17',\n\tkysely: '~0.29.6',\n\tpg: '~8.23.0',\n\tpino: '~10.3.1',\n\tzod: '~4.6.5',\n\t// `@geekmidas/cloud`'s peer floor.\n\tsst: '~4.17.1',\n\n\t// Frontend\n\tnext: '~16.3.6',\n\treact: '~19.3.0',\n\t'react-dom': '~19.3.0',\n\t'@tanstack/react-query': '~5.104.0',\n\t'@tanstack/react-router': '~1.170.40',\n\t'@tanstack/react-start': '~1.168.59',\n\t'@tanstack/router-plugin': '~1.168.41',\n\ttailwindcss: '~4.3.3',\n\t'@tailwindcss/postcss': '~4.3.3',\n\t'@tailwindcss/vite': '~4.3.3',\n\t'@radix-ui/react-dialog': '~1.1.23',\n\t'@radix-ui/react-label': '~2.1.15',\n\t'@radix-ui/react-separator': '~1.1.15',\n\t'@radix-ui/react-slot': '~1.3.3',\n\t'@radix-ui/react-tabs': '~1.1.21',\n\t'@radix-ui/react-tooltip': '~1.2.16',\n\t'class-variance-authority': '~0.7.1',\n\tclsx: '~2.1.1',\n\t'lucide-react': '~1.48.0',\n\t'tailwind-merge': '~3.7.0',\n\n\t// Tooling\n\t'@biomejs/biome': '~2.5.14',\n\t// What `@geekmidas/testkit` itself depends on, so factories share one copy.\n\t'@faker-js/faker': '~10.6.0',\n\t// 2.4+ is what expands `$TURBO_ROOT$` in the root turbo.json.\n\tturbo: '~2.11.4',\n\n\t// Types. Node's follow the oldest runtime the packages support (22), so\n\t// nothing typechecks against an API that is not there.\n\t'@types/node': '~22.20.4',\n\t'@types/pg': '~8.23.1',\n\t'@types/react': '~19.3.0',\n\t'@types/react-dom': '~19.3.0',\n\t'@types/aws-lambda': '~8.10.163',\n} as const;\n\n/**\n * The build and test toolchain, at the versions the repository itself builds\n * and tests with (scripts/dependency-versions.json), so a scaffold compiles\n * with the compiler its own `@geekmidas` packages were checked against.\n */\nexport const TOOLCHAIN_VERSIONS = {\n\ttypescript: '~7.0.2',\n\ttsx: '~4.23.15',\n\tesbuild: '~0.28.2',\n\t// `@geekmidas/testkit` and `@geekmidas/db` declare this as their peer.\n\tvitest: '~5.0.2',\n\tvite: '~8.3.1',\n\t'@vitejs/plugin-react': '^6.1.1',\n} as const;\n\n/**\n * The Expo app's packages, which track an Expo SDK release (57) rather than\n * their own latest: SDK 57 is tested against exactly these, React Native and\n * React included, so they move when the SDK does.\n */\nexport const EXPO_VERSIONS = {\n\texpo: '~57.0.26',\n\t'expo-constants': '~57.0.20',\n\t'expo-dev-client': '~57.0.19',\n\t'expo-device': '~57.0.2',\n\t'expo-linking': '~57.0.11',\n\t'expo-router': '~57.0.24',\n\t'expo-splash-screen': '~57.0.9',\n\t'expo-status-bar': '~57.0.1',\n\t'expo-secure-store': '~57.0.4',\n\treact: '19.2.3',\n\t'react-dom': '19.2.3',\n\t'react-native': '0.86.3',\n\t'react-native-gesture-handler': '~2.32.0',\n\t'react-native-reanimated': '4.5.1',\n\t// Reanimated 4 runs its worklets on this, pinned by the SDK beside it.\n\t'react-native-worklets': '0.10.1',\n\t'react-native-safe-area-context': '~5.7.0',\n\t'react-native-screens': '~4.26.0',\n\t'react-native-web': '~0.21.0',\n\t'@react-navigation/native': '^7.1.0',\n\t'@babel/core': '^7.25.0',\n\t'@types/react': '~19.2.2',\n\tnativewind: '~4.2.0',\n\t// NativeWind 4 is built on Tailwind 3.\n\ttailwindcss: '~3.4.0',\n} as const;\n\n/**\n * The pnpm a pnpm scaffold runs under, through \\`packageManager\\`.\n *\n * Pinned in every layout. Without it Corepack takes the newest pnpm, and 11\n * fails the first install on dependencies with build scripts (esbuild) until\n * they are approved — a single-app scaffold that did not pin it could not\n * install at all.\n */\nexport const PNPM_VERSION = 'pnpm@10.13.1';\n\n/** The Biome config schema matching the Biome the scaffold installs. */\nexport const BIOME_SCHEMA = `https://biomejs.dev/schemas/${DEPENDENCY_VERSIONS['@biomejs/biome'].replace(/^[~^]/, '')}/schema.json`;\n","import { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n// Load package.json - handles both bundled (flat dist/) and source (nested src/init/)\nfunction loadPackageJson(): { version: string } {\n\ttry {\n\t\t// Try flat dist path first (../package.json from dist/)\n\t\treturn require('../package.json');\n\t} catch {\n\t\t// Fall back to nested source path (../../package.json from src/init/)\n\t\treturn require('../../package.json');\n\t}\n}\n\nconst pkg = loadPackageJson();\n\n/**\n * CLI version resolved from package.json at runtime\n */\nexport const CLI_VERSION = `~${pkg.version}`;\n\n/**\n * Package versions for @geekmidas packages\n *\n * AUTO-GENERATED (except CLI) - Do not edit manually\n * Run: pnpm --filter @geekmidas/cli sync-versions\n */\nexport const GEEKMIDAS_VERSIONS = {\n\t'@geekmidas/audit': '~10.0.0-alpha.76',\n\t'@geekmidas/auth': '~10.0.0-alpha.76',\n\t'@geekmidas/cache': '~10.0.0-alpha.76',\n\t'@geekmidas/client': '~10.0.0-alpha.76',\n\t'@geekmidas/cloud': '~10.0.0-alpha.76',\n\t'@geekmidas/constructs': '~10.0.0-alpha.76',\n\t'@geekmidas/db': '~10.0.0-alpha.76',\n\t'@geekmidas/emailkit': '~10.0.0-alpha.76',\n\t'@geekmidas/envkit': '~10.0.0-alpha.76',\n\t'@geekmidas/errors': '~10.0.0-alpha.76',\n\t'@geekmidas/events': '~10.0.0-alpha.76',\n\t'@geekmidas/logger': '~10.0.0-alpha.76',\n\t'@geekmidas/manifest': '~10.0.0-alpha.76',\n\t'@geekmidas/rate-limit': '~10.0.0-alpha.76',\n\t'@geekmidas/schema': '~10.0.0-alpha.76',\n\t'@geekmidas/services': '~10.0.0-alpha.76',\n\t'@geekmidas/storage': '~10.0.0-alpha.76',\n\t'@geekmidas/telescope': '~10.0.0-alpha.76',\n\t'@geekmidas/testkit': '~10.0.0-alpha.76',\n\t'@geekmidas/cli': CLI_VERSION,\n} as const;\n\nexport type GeekmidasPackage = keyof typeof GEEKMIDAS_VERSIONS;\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate auth app files for fullstack template\n * Uses better-auth with magic link authentication\n */\nexport function generateAuthAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/auth`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\t// package.json for auth app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\t// Both halves are `gkm`'s: the entry is generated from the `BetterAuth`\n\t\t// construct, so there is no source here for `tsc` to build or check.\n\t\tscripts: {\n\t\t\tdev: 'gkm dev',\n\t\t\tbuild: 'gkm build',\n\t\t},\n\t\t// What the generated entry and the construct behind it load. The\n\t\t// container is built from this package, so it names them itself rather\n\t\t// than leaning on the workspace root's.\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],\n\t\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t\t'@geekmidas/db': GEEKMIDAS_VERSIONS['@geekmidas/db'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\t\tkysely: DEPENDENCY_VERSIONS.kysely,\n\t\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/pg': DEPENDENCY_VERSIONS['@types/pg'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// tsconfig.json for auth app\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[`@${options.name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// .gitignore for auth app\n\tconst gitignore = `node_modules/\ndist/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/auth/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t// No `src/`. The auth server used to be a hand-written Hono app here — a\n\t\t// `src/index.ts` that read PORT, split `BETTER_AUTH_TRUSTED_ORIGINS` into\n\t\t// a CORS list, and mounted `/api/auth/*` itself, beside a `src/auth.ts`\n\t\t// that built the Better Auth instance and a `src/config/env.ts` to feed\n\t\t// it. Every line of that is the `BetterAuth` construct's now: the origins\n\t\t// come from whatever declared an edge to it, and the build generates the\n\t\t// entry, because the routes are a wildcard that no glob can find.\n\t\t//\n\t\t// What is left is the package the container is built from.\n\t\t{\n\t\t\tpath: 'apps/auth/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import type { StagesConfig } from '../../workspace/types.js';\n\n/** The `stages` block a generated gkm.config.ts declares, indented two spaces. */\nexport function stagesBlock(stages: StagesConfig): string {\n\tconst list = (names: readonly string[]) =>\n\t\t`[${names.map((name) => `'${name}'`).join(', ')}]`;\n\n\treturn `\n // Named by this project and read by every command: \\`gkm dev\\`, \\`exec\\` and\n // \\`test\\` run as \\`local\\`, and \\`gkm deploy --stage\\` accepts only \\`deployed\\`.\n stages: {\n local: '${stages.local}',\n deployed: ${list(stages.deployed)},${\n\t\t\tstages.protected?.length\n\t\t\t\t? `\n // Retained and protected on removal.\n protected: ${list(stages.protected)},`\n\t\t\t\t: ''\n\t\t}\n },`;\n}\n\n/**\n * The `STAGE` the scaffolded env config parses: one of the declared stages,\n * defaulting to the local one.\n */\nexport function stageEnv(stages: StagesConfig): string {\n\tconst names = [stages.local, ...stages.deployed]\n\t\t.map((name) => `'${name}'`)\n\t\t.join(', ');\n\n\treturn `get('STAGE').enum([${names}]).default('${stages.local}')`;\n}\n","import { CONSTRUCTS_GLOB, routesGlob } from '../constructs.js';\nimport { BIOME_SCHEMA } from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { stagesBlock } from './stages.js';\n\n/**\n * Vitest config for a database-enabled app.\n *\n * On its own, it is the root config and carries gkm's setup: the test stage\n * reconciled and every construct migrated, however the suite starts. In a\n * workspace the root config carries it instead — once, so no project filter\n * can skip it and nothing runs it twice.\n */\nconst vitestConfigFor = (\n\tmonorepo: boolean,\n) => `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n // Vite resolves tsconfig \\`paths\\` itself; no plugin needed.\n resolve: { tsconfigPaths: true },\n test: {\n environment: 'node',${\n\t\t\tmonorepo\n\t\t\t\t? ''\n\t\t\t\t: `\n // The test stage, reconciled and every database construct's migrations\n // applied, before any test runs — whether \\`gkm test\\` or plain\n // \\`vitest\\` started it.\n globalSetup: ['@geekmidas/cli/vitest'],`\n\t\t}\n },\n});\n`;\n\n/**\n * Generate configuration files (gkm.config.ts, tsconfig.json, biome.json, turbo.json)\n */\nexport function generateConfigFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { telescope, routesStructure } = options;\n\tconst isServerless = template.name === 'serverless';\n\tconst hasWorker = template.name === 'worker';\n\tconst isFullstack = options.template === 'fullstack';\n\n\tconst getRoutesGlob = () => routesGlob(routesStructure);\n\n\t// For fullstack template, generate workspace config at root\n\t// Single app config is still generated for non-fullstack monorepo setups\n\tif (isFullstack) {\n\t\t// Workspace config is generated in monorepo.ts for fullstack\n\t\treturn generateSingleAppConfigFiles(options, template, {\n\t\t\ttelescope,\n\t\t\troutesStructure,\n\t\t\tisServerless,\n\t\t\thasWorker,\n\t\t\tgetRoutesGlob,\n\t\t});\n\t}\n\n\t// Build gkm.config.ts for single-app\n\tlet gkmConfig = `import { defineConfig } from '@geekmidas/cli/config';\n\nexport default defineConfig({${stagesBlock(options.stages)}${\n\t\toptions.monorepo\n\t\t\t? ''\n\t\t\t: `\n // One glob, every kind. What reconcile reads to derive the containers this\n // app needs: a declared database is why a Postgres exists at all, so nothing\n // lists \\`postgres\\` anywhere.\n constructs: '${CONSTRUCTS_GLOB}',`\n\t}\n routes: '${getRoutesGlob()}',\n envParser: './src/config/env#envParser',\n logger: './src/config/logger#logger',`;\n\n\tif (isServerless || hasWorker) {\n\t\tgkmConfig += `\n functions: './src/functions/**/*.ts',`;\n\t}\n\n\tif (hasWorker) {\n\t\tgkmConfig += `\n crons: './src/crons/**/*.ts',\n subscribers: './src/subscribers/**/*.ts',`;\n\t}\n\n\tif (telescope) {\n\t\tgkmConfig += `\n telescope: {\n enabled: true,\n path: '/__telescope',\n },`;\n\t}\n\n\t// Always add openapi config: each surface's client is written to the\n\t// workspace root's `.gkm/client/`, imported as `@<name>/client/<surface>`\n\tgkmConfig += `\n openapi: {\n enabled: true,\n },`;\n\n\tgkmConfig += `\n});\n`;\n\n\t// Build tsconfig.json - extends root for monorepo, standalone for non-monorepo\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = options.monorepo\n\t\t? workspaceApiTsConfig(options.name)\n\t\t: {\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\ttarget: 'ES2022',\n\t\t\t\t\tmodule: 'NodeNext',\n\t\t\t\t\tmoduleResolution: 'NodeNext',\n\t\t\t\t\tlib: ['ES2022'],\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tesModuleInterop: true,\n\t\t\t\t\tskipLibCheck: true,\n\t\t\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\t\t\tresolveJsonModule: true,\n\t\t\t\t\tnoEmit: true,\n\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t// The monorepo and fullstack layouts already mapped this; a\n\t\t\t\t\t// single app did not, so every `~/…` import the templates write\n\t\t\t\t\t// — the api's `~/router.ts`, the worker's `~/constructs/worker.ts`\n\t\t\t\t\t// — resolved to nothing and the project failed on first build.\n\t\t\t\t\tpaths: {\n\t\t\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tinclude: ['src/**/*.ts'],\n\t\t\t\texclude: ['node_modules', 'dist'],\n\t\t\t};\n\n\t// Skip biome.json and turbo.json for monorepo (they're at root)\n\tif (options.monorepo) {\n\t\tconst files: GeneratedFile[] = [\n\t\t\t{\n\t\t\t\tpath: 'gkm.config.ts',\n\t\t\t\tcontent: gkmConfig,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: 'tsconfig.json',\n\t\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t\t},\n\t\t];\n\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'vitest.config.ts',\n\t\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t}\n\n\t// Build biome.json\n\tconst biomeConfig = {\n\t\t$schema: BIOME_SCHEMA,\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\t// Biome 2 moved import sorting into the assist, and `files.ignore` into\n\t\t// negated `includes`: the 1.x keys make it refuse the whole config.\n\t\tassist: { actions: { source: { organizeImports: 'on' } } },\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Tailwind v4's `@theme` and `@apply`, which the UI package's CSS uses.\n\t\tcss: { parser: { tailwindDirectives: true } },\n\t\tfiles: {\n\t\t\tincludes: [\n\t\t\t\t'**',\n\t\t\t\t'!**/node_modules',\n\t\t\t\t'!**/dist',\n\t\t\t\t'!**/.gkm',\n\t\t\t\t'!**/coverage',\n\t\t\t],\n\t\t},\n\t};\n\n\t// Build turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['dist/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: gkmConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.constructs.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * Helper to generate config files for API app in fullstack template\n * (workspace config is at root, so no gkm.config.ts for app)\n */\ninterface ConfigHelperOptions {\n\ttelescope: boolean;\n\troutesStructure: string;\n\tisServerless: boolean;\n\thasWorker: boolean;\n\tgetRoutesGlob: () => string;\n}\n\n/**\n * The tsconfig of an API inside a workspace.\n *\n * One definition for both ways of getting one — the fullstack template and\n * `--monorepo` — because the two copies had drifted: only one of them mapped\n * the root constructs, so in the other `@<name>/constructs/api.ts` fell through\n * to the `packages/` mapping and nothing could load the surface.\n */\nfunction workspaceApiTsConfig(name: string) {\n\treturn {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t// Before the wildcard below it: TypeScript takes the longest\n\t\t\t\t// matching prefix, so the constructs at the workspace root win\n\t\t\t\t// over `packages/constructs/src`, which is a different thing\n\t\t\t\t// with a colliding name.\n\t\t\t\t[`@${name}/constructs/*`]: ['../../constructs/*'],\n\t\t\t\t[`@${name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n}\n\nfunction generateSingleAppConfigFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n\t_helpers: ConfigHelperOptions,\n): GeneratedFile[] {\n\t// For fullstack, only generate tsconfig.json for the API app\n\t// The workspace gkm.config.ts is generated in monorepo.ts\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = workspaceApiTsConfig(options.name);\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.constructs.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t});\n\t}\n\n\treturn files;\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate environment-related files (.gitignore only).\n * Note: .env files are no longer generated. Use `gkm secrets:init` to initialize\n * encrypted secrets stored in `.gkm/secrets/{stage}.json` with keys stored at\n * `~/.gkm/keys/{namespace}/{project}/{stage}.key`.\n */\nexport function generateEnvFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tconst files: GeneratedFile[] = [];\n\n\t// Only add .gitignore for non-monorepo (monorepo has it at root)\n\tif (!options.monorepo) {\n\t\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Written by gkm from the constructs; your own docker-compose.yml is not\ndocker-compose.constructs.yml\n\n# Environment (legacy - use gkm secrets instead)\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n`;\n\t\tfiles.push({\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t});\n\t}\n\n\treturn files;\n}\n","/**\n * The GitHub workflows a scaffold ships with.\n *\n * - `ci.yml` — every pull request builds, lints, typechecks and tests.\n * - `release-drafter.yml` — merged pull requests accumulate in a draft\n * release, labelled from their titles.\n * - `deploy.yml` — when a deploy target was picked: a push to main deploys the\n * stages that are not protected, publishing the drafted release deploys the\n * protected ones.\n *\n * The deploy workflow names no stage. It reads `stages` from gkm.config.ts at\n * run time, so the config stays the one place stages are declared and a\n * workflow cannot fall out of step with it.\n */\n\nimport { projectKey } from '../../secrets/keystore.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/** How each package manager is set up, installs, and runs a script. */\nconst TOOLING = {\n\tpnpm: {\n\t\t// The version comes from \\`packageManager\\` in package.json, which only\n\t\t// the workspace scaffold pins; the action refuses both at once.\n\t\tsetup: ` - uses: pnpm/action-setup@v4\nPNPM_VERSION\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: pnpm\n`,\n\t\tinstall: 'pnpm install --frozen-lockfile',\n\t\trun: 'pnpm run',\n\t\texec: 'pnpm exec',\n\t},\n\tnpm: {\n\t\tsetup: ` - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: npm\n`,\n\t\tinstall: 'npm ci',\n\t\trun: 'npm run',\n\t\texec: 'npx --no-install',\n\t},\n\tyarn: {\n\t\tsetup: ` - run: corepack enable\n\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: yarn\n`,\n\t\tinstall: 'yarn install --immutable',\n\t\trun: 'yarn run',\n\t\texec: 'yarn',\n\t},\n\tbun: {\n\t\tsetup: ` - uses: oven-sh/setup-bun@v2\n`,\n\t\tinstall: 'bun install --frozen-lockfile',\n\t\trun: 'bun run',\n\t\texec: 'bunx',\n\t},\n} as const;\n\n/** The package manager's steps, with pnpm pinned where package.json does not. */\nfunction tooling(options: TemplateOptions) {\n\tconst pm = TOOLING[options.packageManager];\n\treturn {\n\t\t...pm,\n\t\tsetup: pm.setup.replace(\n\t\t\t'PNPM_VERSION\\n',\n\t\t\toptions.monorepo ? '' : ' with:\\n version: 10\\n',\n\t\t),\n\t};\n}\n\nfunction ci(options: TemplateOptions): string {\n\tconst pm = tooling(options);\n\n\treturn `name: CI\n\non:\n pull_request:\n branches: [main]\n\nconcurrency:\n group: \\${{ github.workflow }}-\\${{ github.ref }}\n cancel-in-progress: true\n\npermissions:\n contents: read\n\njobs:\n validate:\n name: Validate\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n\n - name: Build\n run: ${pm.run} build\n\n - name: Lint\n run: ${pm.run} lint\n\n - name: Typecheck\n run: ${pm.run} typecheck\n\n # \\`gkm test\\` starts the containers the declared constructs need (the\n # runner has Docker) and, with GKM_AUTO_SETUP, generates throwaway\n # secrets for the test stage — there is no key to share with CI.\n - name: Test\n timeout-minutes: 15\n run: ${pm.run} test:once\n env:\n CI: true\n GKM_AUTO_SETUP: 1\n`;\n}\n\nconst releaseDrafterWorkflow = `name: Release Drafter\n\non:\n push:\n branches: [main]\n pull_request:\n types: [opened, reopened, synchronize, edited]\n\npermissions:\n contents: read\n\njobs:\n draft:\n name: Update release draft\n runs-on: ubuntu-latest\n permissions:\n contents: write\n pull-requests: write\n steps:\n - uses: release-drafter/release-drafter@v6\n with:\n commitish: main\n env:\n GITHUB_TOKEN: \\${{ secrets.GITHUB_TOKEN }}\n`;\n\nfunction releaseDrafterConfig(options: TemplateOptions): string {\n\tconst mobile =\n\t\toptions.frontendFramework === 'expo'\n\t\t\t? ` - title: \"📱 Mobile\"\n labels: [mobile, ios, android]\n collapse-after: 10\n`\n\t\t\t: '';\n\n\treturn `name-template: \"v$RESOLVED_VERSION\"\ntag-template: \"v$RESOLVED_VERSION\"\n\ncategories:\n - title: \"✨ New Features\"\n labels: [feature, enhancement]\n collapse-after: 10\n - title: \"🐛 Bug Fixes\"\n labels: [bug, fix]\n collapse-after: 10\n${mobile} - title: \"🏗 Infrastructure\"\n labels: [infrastructure, ci]\n collapse-after: 10\n - title: \"📦 Dependencies\"\n labels: [dependencies]\n collapse-after: 5\n - title: \"🔒 Security\"\n labels: [security]\n - title: \"🧹 Maintenance\"\n labels: [chore, refactor]\n collapse-after: 5\n\nchange-template: \"- $TITLE @$AUTHOR (#$NUMBER)\"\nchange-title-escapes: '\\\\<*_&'\n\nversion-resolver:\n major:\n labels: [breaking-change, major]\n minor:\n labels: [feature, enhancement, minor]\n patch:\n labels: [bug, fix, chore, dependencies, patch]\n default: patch\n\n# Labelled from the conventional-commit prefix of the pull request title.\nautolabeler:\n - label: feature\n title: [\"/^feat/i\"]\n - label: bug\n title: [\"/^fix/i\"]\n - label: chore\n title: [\"/^chore/i\", \"/^refactor/i\"]\n - label: dependencies\n title: [\"/^deps/i\", \"/^chore\\\\\\\\(deps\\\\\\\\)/i\"]\n - label: ci\n title: [\"/^ci/i\"]\n - label: breaking-change\n title: [\"/^\\\\\\\\w+(\\\\\\\\(.+\\\\\\\\))?!:/\"]\n\ntemplate: |\n ## What's Changed\n\n $CHANGES\n\n **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION\n`;\n}\n\nfunction deploy(options: TemplateOptions): string {\n\tconst pm = tooling(options);\n\tconst sst = options.deployTarget === 'sst';\n\n\tconst credentials = sst\n\t\t? `\n # An IAM role GitHub assumes through OIDC — no long-lived AWS keys. Set\n # AWS_ROLE_ARN as a variable on each environment.\n - uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: \\${{ vars.AWS_ROLE_ARN }}\n aws-region: ${options.region}\n`\n\t\t: '';\n\n\t// A stage's secrets are read from its store by the deploy itself. SSM and\n\t// Secrets Manager need nothing but the role the job already assumed; the local file needs its\n\t// key, and the encrypted file itself, which a checkout of an ignored\n\t// `.gkm/` lacks.\n\t// Where the CLI looks for the stage's key: under the project's identity,\n\t// not under the checkout's folder name, which on a runner is the repo's.\n\tconst keyDir = `~/.gkm/keys/${projectKey({ name: options.name })}`;\n\tconst stageSecrets = sst\n\t\t? credentials\n\t\t: `\n # The stage's secrets are kept in the encrypted .gkm/secrets/<stage>.json,\n # and each environment holds its key as GKM_SECRETS_KEY. .gkm/ is\n # gitignored, so a checkout has the key but not the file: set\n # secrets.store in gkm.config.ts to a store CI can reach before deploying\n # from here.\n # Owner-only, as the CLI writes its own keys. The stage reaches the shell\n # as a variable, never pasted into the script: on a manual run it is\n # whatever was typed.\n - name: Stage secrets key\n run: |\n mkdir -p -m 700 ${keyDir}\n (umask 077 && printf '%s' \"$KEY\" > ${keyDir}/\"$STAGE\".key)\n env:\n KEY: \\${{ secrets.GKM_SECRETS_KEY }}\n STAGE: \\${{ matrix.stage }}\n`;\n\n\tconst deployEnv = sst\n\t\t? ''\n\t\t: `\n DOKPLOY_API_TOKEN: \\${{ secrets.DOKPLOY_API_TOKEN }}\n DOKPLOY_ENDPOINT: \\${{ vars.DOKPLOY_ENDPOINT }}`;\n\n\treturn `name: Deploy\n\n# Which stages exist, and which are protected, is read from \\`stages\\` in\n# gkm.config.ts — nothing here names one:\n#\n# push to main every deployed stage that is not protected\n# release published the protected stages (publish the drafted release)\n# run workflow the one stage you name\non:\n push:\n branches: [main]\n release:\n types: [published]\n workflow_dispatch:\n inputs:\n stage:\n description: A deployed stage from gkm.config.ts\n required: true\n\npermissions:\n contents: read\n id-token: write\n\njobs:\n stages:\n name: Pick stages\n runs-on: ubuntu-latest\n outputs:\n stages: \\${{ steps.pick.outputs.stages }}\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n\n - name: Read stages from gkm.config.ts\n id: pick\n run: |\n ${pm.exec} tsx -e \"\n import config from './gkm.config.ts';\n const { deployed, protected: kept = [] } = config.stages;\n const event = process.env.EVENT;\n if (event === 'workflow_dispatch' && !deployed.includes(process.env.STAGE)) {\n console.error('Not a deployed stage: ' + process.env.STAGE + ' (deployed: ' + deployed.join(', ') + ')');\n process.exit(1);\n }\n const stages =\n event === 'workflow_dispatch' ? [process.env.STAGE]\n : event === 'release' ? kept\n : deployed.filter((stage) => !kept.includes(stage));\n console.log('stages=' + JSON.stringify(stages));\n \" >> \"$GITHUB_OUTPUT\"\n env:\n EVENT: \\${{ github.event_name }}\n STAGE: \\${{ inputs.stage }}\n\n deploy:\n name: Deploy \\${{ matrix.stage }}\n needs: stages\n if: needs.stages.outputs.stages != '[]'\n runs-on: ubuntu-latest\n strategy:\n fail-fast: false\n matrix:\n stage: \\${{ fromJSON(needs.stages.outputs.stages) }}\n # One GitHub environment per stage: its secrets and variables, and any\n # approval rule you put on a protected one.\n environment: \\${{ matrix.stage }}\n concurrency:\n group: deploy-\\${{ matrix.stage }}\n cancel-in-progress: false\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n${stageSecrets}\n # Builds, releases and health-checks the stage through deploy.default\n # in gkm.config.ts, and fails the job if any of it fails.\n - name: Deploy\n run: ${pm.exec} gkm deploy --stage \"$STAGE\"\n env:\n STAGE: \\${{ matrix.stage }}${deployEnv}\n`;\n}\n\nexport function generateGithubFiles(options: TemplateOptions): GeneratedFile[] {\n\tconst files: GeneratedFile[] = [\n\t\t{ path: '.github/workflows/ci.yml', content: ci(options) },\n\t\t{\n\t\t\tpath: '.github/workflows/release-drafter.yml',\n\t\t\tcontent: releaseDrafterWorkflow,\n\t\t},\n\t\t{\n\t\t\tpath: '.github/release-drafter.yml',\n\t\t\tcontent: releaseDrafterConfig(options),\n\t\t},\n\t];\n\n\t// Only where a target was picked, and only for a workspace scaffold: the\n\t// one whose gkm.config.ts says where its stages deploy.\n\tif (options.monorepo && options.deployTarget !== 'none') {\n\t\tfiles.push({\n\t\t\tpath: '.github/workflows/deploy.yml',\n\t\t\tcontent: deploy(options),\n\t\t});\n\t}\n\n\treturn files;\n}\n","import { schemeBase } from '@geekmidas/manifest';\nimport {\n\tDEPENDENCY_VERSIONS,\n\tEXPO_VERSIONS,\n\tTOOLCHAIN_VERSIONS,\n} from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate an Expo mobile app for the fullstack template.\n *\n * Mirrors the structure of rezgo/apps/app: NativeWind for styling,\n * expo-router for navigation, better-auth + magic link, React Query\n * for data, all wired into the toolbox's typed API client.\n */\nexport function generateExpoAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/app`;\n\tconst modelsPackage = `@${options.name}/models`;\n\t// The slug is Expo's project name. The scheme — and the bundle id built on\n\t// it — is not written here: the \\`MobileApp\\` construct resolves it per\n\t// stage, and \\`app.config.ts\\` reads it from \\`APP_SCHEME\\`.\n\tconst slug = options.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\t// What the deployed auth server trusts: the same derivation, not a copy.\n\tconst scheme = schemeBase(options.name);\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tmain: 'expo-router/entry',\n\t\tprivate: true,\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- expo start -c',\n\t\t\tios: 'expo start --ios',\n\t\t\tandroid: 'expo start --android',\n\t\t\tweb: 'expo start --web',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@better-auth/expo': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@react-navigation/native': EXPO_VERSIONS['@react-navigation/native'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\texpo: EXPO_VERSIONS['expo'],\n\t\t\t'expo-constants': EXPO_VERSIONS['expo-constants'],\n\t\t\t'expo-dev-client': EXPO_VERSIONS['expo-dev-client'],\n\t\t\t'expo-device': EXPO_VERSIONS['expo-device'],\n\t\t\t'expo-linking': EXPO_VERSIONS['expo-linking'],\n\t\t\t'expo-router': EXPO_VERSIONS['expo-router'],\n\t\t\t'expo-secure-store': EXPO_VERSIONS['expo-secure-store'],\n\t\t\t'expo-splash-screen': EXPO_VERSIONS['expo-splash-screen'],\n\t\t\t'expo-status-bar': EXPO_VERSIONS['expo-status-bar'],\n\t\t\tnativewind: EXPO_VERSIONS['nativewind'],\n\t\t\treact: EXPO_VERSIONS['react'],\n\t\t\t'react-dom': EXPO_VERSIONS['react-dom'],\n\t\t\t'react-native': EXPO_VERSIONS['react-native'],\n\t\t\t'react-native-gesture-handler':\n\t\t\t\tEXPO_VERSIONS['react-native-gesture-handler'],\n\t\t\t'react-native-reanimated': EXPO_VERSIONS['react-native-reanimated'],\n\t\t\t'react-native-worklets': EXPO_VERSIONS['react-native-worklets'],\n\t\t\t'react-native-safe-area-context':\n\t\t\t\tEXPO_VERSIONS['react-native-safe-area-context'],\n\t\t\t'react-native-screens': EXPO_VERSIONS['react-native-screens'],\n\t\t\t'react-native-web': EXPO_VERSIONS['react-native-web'],\n\t\t\ttailwindcss: EXPO_VERSIONS['tailwindcss'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@babel/core': EXPO_VERSIONS['@babel/core'],\n\t\t\t'@types/react': EXPO_VERSIONS['@types/react'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\tconst appConfig = `import type { ConfigContext, ExpoConfig } from '@expo/config';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\n/**\n * What the app is built with, from the environment \\`gkm\\` injects — the\n * \\`MobileApp\\` construct's \\`.dependsOn([api, auth])\\` is where every value\n * here comes from, so none of it is written down.\n *\n * - \\`APP_SCHEME\\`: the URL scheme — \\`${scheme}\\`, the same on every stage.\n * - \\`EXPO_PUBLIC_API_URL\\` / \\`EXPO_PUBLIC_AUTH_URL\\`: where the servers\n * answer. Locally that is their own port on \\`localhost\\`, which\n * \\`config.ts\\` points at the machine Metro was served from.\n *\n * Read at runtime from \\`Constants.expoConfig.extra.config\\` — see \\`config.ts\\`.\n */\nconst config = new EnvironmentParser({ ...process.env })\n .create((get) => ({\n scheme: get('APP_SCHEME').string(),\n apiUrl: get('EXPO_PUBLIC_API_URL').string(),\n authUrl: get('EXPO_PUBLIC_AUTH_URL').string(),\n }))\n .parse();\n\nexport type Config = typeof config;\n\n// A bundle id and an Android package allow no hyphens; one per scheme, so\n// each stage installs beside the others.\nconst bundleId = \\`com.\\${config.scheme.replace(/[^a-z0-9]/g, '')}.app\\`;\n\nexport default function expoConfig({ config: base }: ConfigContext): ExpoConfig {\n return {\n ...base,\n name: '${options.name}',\n slug: '${slug}',\n version: '0.0.1',\n orientation: 'portrait',\n icon: './assets/icon.png',\n scheme: config.scheme,\n userInterfaceStyle: 'automatic',\n newArchEnabled: true,\n ios: {\n supportsTablet: true,\n bundleIdentifier: bundleId,\n },\n android: {\n package: bundleId,\n adaptiveIcon: {\n foregroundImage: './assets/adaptive-icon.png',\n backgroundColor: '#ffffff',\n },\n edgeToEdgeEnabled: true,\n },\n web: {\n output: 'static',\n },\n plugins: [\n 'expo-router',\n 'expo-secure-store',\n [\n 'expo-splash-screen',\n {\n image: './assets/splash.png',\n imageWidth: 200,\n resizeMode: 'contain',\n backgroundColor: '#ffffff',\n },\n ],\n ],\n experiments: {\n typedRoutes: true,\n },\n extra: { ...base.extra, config },\n };\n}\n`;\n\n\tconst easJson = {\n\t\tcli: {\n\t\t\tversion: '>= 10.2.1',\n\t\t\tappVersionSource: 'remote',\n\t\t},\n\t\tbuild: {\n\t\t\tdev: {\n\t\t\t\tdevelopmentClient: true,\n\t\t\t\tdistribution: 'internal',\n\t\t\t\t// Locally \\`gkm\\` injects the scheme and both URLs from the graph.\n\t\t\t\tenvironment: 'development',\n\t\t\t},\n\t\t\tpreview: {\n\t\t\t\tdistribution: 'internal',\n\t\t\t\tenvironment: 'preview',\n\t\t\t\t// EAS builds outside \\`gkm\\`, so a store build is told its scheme —\n\t\t\t\t// the bare one, which is what the deployed auth server trusts.\n\t\t\t\tenv: {\n\t\t\t\t\tAPP_SCHEME: scheme,\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t\tproduction: {\n\t\t\t\tautoIncrement: true,\n\t\t\t\tenvironment: 'production',\n\t\t\t\t// EAS builds outside \\`gkm\\`, so a store build is told its scheme —\n\t\t\t\t// the bare one, which is what the deployed auth server trusts.\n\t\t\t\tenv: {\n\t\t\t\t\tAPP_SCHEME: scheme,\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n\n\tconst babelConfig = `module.exports = function (api) {\n api.cache(true);\n return {\n presets: [\n ['babel-preset-expo', { jsxImportSource: 'nativewind' }],\n 'nativewind/babel',\n ],\n };\n};\n`;\n\n\tconst metroConfig = `const { getDefaultConfig } = require('expo/metro-config');\nconst { withNativeWind } = require('nativewind/metro');\n\nconst config = getDefaultConfig(__dirname);\n\nmodule.exports = withNativeWind(config, { input: './global.css' });\n`;\n\n\tconst tsConfig = {\n\t\textends: 'expo/tsconfig.base',\n\t\tcompilerOptions: {\n\t\t\tstrict: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\ttypes: ['nativewind/types'],\n\t\t\tpaths: {\n\t\t\t\t'@/*': ['./*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: [\n\t\t\t'**/*.ts',\n\t\t\t'**/*.tsx',\n\t\t\t'.expo/types/**/*.ts',\n\t\t\t'expo-env.d.ts',\n\t\t\t'nativewind-env.d.ts',\n\t\t],\n\t};\n\n\tconst tailwindConfig = `import type { Config } from 'tailwindcss';\n\nexport default {\n content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],\n presets: [require('nativewind/preset')],\n theme: {\n extend: {},\n },\n plugins: [],\n} satisfies Config;\n`;\n\n\tconst globalCss = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`;\n\n\tconst expoEnvDts = `/// <reference types=\"expo/types\" />\\n`;\n\n\tconst nativewindEnvDts = `/// <reference types=\"nativewind/types\" />\\n`;\n\n\tconst configTs = `import Constants from 'expo-constants';\nimport * as Device from 'expo-device';\nimport { Platform } from 'react-native';\n\nimport type { Config } from './app.config.ts';\n\nconst built = Constants.expoConfig?.extra?.config as Config;\n\n/** The host this device loaded the bundle from: Metro's, as the device sees it. */\nconst metro = (Constants.expoConfig?.hostUri ?? '').split(':')[0];\n\n/**\n * A private address on the local network — what a phone on the same Wi-Fi\n * reaches this machine on. A tunnel's \\`*.exp.direct\\` host is not one: a\n * tunnel forwards only Metro, so the servers are not behind it.\n */\nconst isLan = (host: string) =>\n /^10\\\\./.test(host) ||\n /^192\\\\.168\\\\./.test(host) ||\n /^172\\\\.(1[6-9]|2\\\\d|3[01])\\\\./.test(host);\n\n/** \\`localhost\\` from inside the Android emulator is the emulator itself. */\nconst isAndroidEmulator = Platform.OS === 'android' && !Device.isDevice;\n\n/**\n * A server's URL as this device reaches it.\n *\n * Locally the servers are injected as \\`http://localhost:<port>\\`. That is this\n * device only on the iOS simulator. The Android emulator reaches this machine\n * at \\`10.0.2.2\\`, and a phone at the LAN address Metro was served from.\n * Deployed URLs have no \\`localhost\\` in them and pass through untouched.\n */\nexport function reachable(url: string): string {\n const host = isLan(metro) ? metro : isAndroidEmulator ? '10.0.2.2' : undefined;\n if (!host) return url;\n return url.replace(/\\\\/\\\\/(localhost|127\\\\.0\\\\.0\\\\.1)(?=[:/]|$)/, \\`//\\${host}\\`);\n}\n\nexport const config = {\n scheme: built.scheme,\n apiUrl: reachable(built.apiUrl),\n authUrl: reachable(built.authUrl),\n};\n`;\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n});\n`;\n\n\tconst authClientTs = `import { expoClient, getSetCookie } from '@better-auth/expo/client';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport * as Linking from 'expo-linking';\nimport * as SecureStore from 'expo-secure-store';\nimport { useEffect } from 'react';\n\nimport { config } from '@/config.ts';\n\nexport const STORAGE_PREFIX = config.scheme;\nexport const COOKIE_STORE_KEY = \\`\\${STORAGE_PREFIX}_cookie\\`;\n\nexport const authClient = createAuthClient({\n baseURL: config.authUrl,\n plugins: [\n expoClient({\n scheme: config.scheme,\n storagePrefix: STORAGE_PREFIX,\n storage: SecureStore,\n }),\n magicLinkClient(),\n ],\n});\n\nexport const { signIn, useSession } = authClient;\n\n/**\n * Sign in from the emailed link.\n *\n * The link opens in the phone's browser, which is what receives the session\n * cookie — not the app. The auth server's Expo plugin carries the cookie on the\n * redirect back into the app (\\`?cookie=\\`), and this stores it where the\n * Expo client keeps its own, merged with what is already there, then tells the\n * client the session changed. The Expo client does this itself only for a\n * sign-in it opened (social); a link opened from mail arrives as a deep link.\n *\n * Called once, from the root layout.\n */\nexport function useSessionFromLink() {\n const url = Linking.useLinkingURL();\n\n useEffect(() => {\n const cookie = url ? Linking.parse(url).queryParams?.cookie : undefined;\n if (typeof cookie !== 'string') return;\n\n void (async () => {\n const previous = await SecureStore.getItemAsync(COOKIE_STORE_KEY);\n await SecureStore.setItemAsync(\n COOKIE_STORE_KEY,\n getSetCookie(cookie, previous ?? undefined),\n );\n authClient.$store.notify('$sessionSignal');\n })();\n }, [url]);\n}\n\nexport async function signOut() {\n try {\n await authClient.signOut();\n } finally {\n await SecureStore.deleteItemAsync(COOKIE_STORE_KEY);\n }\n}\n`;\n\n\tconst apiTs = `import { createApi } from '@${options.name}/client/api';\n\nimport { config } from '@/config.ts';\nimport { authClient } from './auth-client.ts';\nimport { queryClient } from './query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n return createApi({\n baseURL: config.apiUrl,\n queryClient,\n headers: options?.headers,\n onRequest: (cfg) => {\n const cookie = authClient.getCookie();\n const next = { ...cfg, credentials: 'omit' as const };\n if (cookie) {\n return {\n ...next,\n headers: { ...(next.headers ?? {}), Cookie: cookie },\n };\n }\n return next;\n },\n });\n}\n`;\n\n\tconst apiContextTsx = `import { createContext, type ReactNode, use } from 'react';\nimport type { createAppApi } from './api.ts';\n\nexport type Api = ReturnType<typeof createAppApi>;\n\nconst ApiContext = createContext<Api | null>(null);\n\nexport function ApiProvider({\n api,\n children,\n}: {\n api: Api;\n children: ReactNode;\n}) {\n return <ApiContext.Provider value={api}>{children}</ApiContext.Provider>;\n}\n\nexport function useApi(): Api {\n const api = use(ApiContext);\n if (!api) {\n throw new Error('useApi must be used within an ApiProvider');\n }\n return api;\n}\n`;\n\n\tconst layoutTsx = `import '../global.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { Stack, useRouter, useSegments } from 'expo-router';\nimport { StatusBar } from 'expo-status-bar';\nimport { useEffect, useMemo } from 'react';\nimport 'react-native-reanimated';\n\nimport { authClient, useSessionFromLink } from '@/lib/auth-client.ts';\nimport { ApiProvider } from '@/lib/api-context.tsx';\nimport { createAppApi } from '@/lib/api.ts';\nimport { queryClient } from '@/lib/query-client.ts';\n\nfunction AuthGate({ children }: { children: React.ReactNode }) {\n const router = useRouter();\n const segments = useSegments();\n const { data: session, isPending } = authClient.useSession();\n\n useEffect(() => {\n if (isPending) return;\n const onAuthRoute = segments[0] === 'login';\n if (!session && !onAuthRoute) {\n router.replace('/login');\n } else if (session && onAuthRoute) {\n router.replace('/');\n }\n }, [isPending, session, segments, router]);\n\n return <>{children}</>;\n}\n\nexport default function RootLayout() {\n const api = useMemo(() => createAppApi(), []);\n // The emailed sign-in link comes back as a deep link carrying the session.\n useSessionFromLink();\n\n return (\n <QueryClientProvider client={queryClient}>\n <ApiProvider api={api}>\n <AuthGate>\n <Stack screenOptions={{ headerShown: false }}>\n <Stack.Screen name=\"index\" />\n <Stack.Screen name=\"login\" />\n </Stack>\n </AuthGate>\n <StatusBar style=\"auto\" />\n </ApiProvider>\n </QueryClientProvider>\n );\n}\n`;\n\n\tconst indexTsx = `import { Pressable, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { signOut, useSession } from '@/lib/auth-client.ts';\nimport { useApi } from '@/lib/api-context.tsx';\n\nexport default function Home() {\n const { data: session } = useSession();\n const api = useApi();\n const { data: health } = api.useQuery('GET /health', {});\n\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <View className=\"flex-1 items-center justify-center gap-4 px-6\">\n <Text className=\"text-3xl font-bold text-slate-900\">\n Welcome to ${options.name}\n </Text>\n {session ? (\n <Text className=\"text-sm text-slate-500\">\n Signed in as {session.user.email}\n </Text>\n ) : null}\n {health ? (\n <Text className=\"text-xs text-slate-400\">\n API: {JSON.stringify(health)}\n </Text>\n ) : null}\n <Pressable\n onPress={signOut}\n className=\"mt-4 rounded-lg bg-slate-900 px-6 py-3\"\n >\n <Text className=\"font-semibold text-white\">Sign out</Text>\n </Pressable>\n </View>\n </SafeAreaView>\n );\n}\n`;\n\n\tconst loginTsx = `import * as Linking from 'expo-linking';\nimport { useState } from 'react';\nimport {\n KeyboardAvoidingView,\n Platform,\n Pressable,\n Text,\n TextInput,\n View,\n} from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { authClient } from '@/lib/auth-client.ts';\n\nconst EMAIL_RE = /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/;\n\nexport default function LoginScreen() {\n const [email, setEmail] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function handleSubmit() {\n if (!EMAIL_RE.test(email.trim())) {\n setError('Enter a valid email address');\n return;\n }\n setError(null);\n setSubmitting(true);\n\n const callbackURL = Linking.createURL('/').replace(/^(\\\\w+):\\\\/\\\\/\\\\//, '$1://');\n try {\n const result = await authClient.signIn.magicLink({\n email: email.trim(),\n callbackURL,\n });\n if (result.error) {\n setError(result.error.message ?? 'Could not send magic link');\n return;\n }\n setSent(true);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Something went wrong');\n } finally {\n setSubmitting(false);\n }\n }\n\n if (sent) {\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <View className=\"flex-1 items-center justify-center px-6\">\n <Text className=\"text-2xl font-bold text-slate-900\">\n Check your inbox\n </Text>\n <Text className=\"mt-3 text-center text-slate-500\">\n We sent a sign-in link to {email.trim()}\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <KeyboardAvoidingView\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n className=\"flex-1\"\n >\n <View className=\"flex-1 justify-center px-6\">\n <Text className=\"text-3xl font-bold text-slate-900\">Sign in</Text>\n <Text className=\"mt-1 text-sm text-slate-500\">\n We'll email you a one-time sign-in link.\n </Text>\n\n <Text className=\"mt-6 text-xs font-semibold uppercase text-slate-500\">\n Email\n </Text>\n <TextInput\n value={email}\n onChangeText={(v) => {\n setEmail(v);\n if (error) setError(null);\n }}\n autoCapitalize=\"none\"\n autoCorrect={false}\n keyboardType=\"email-address\"\n placeholder=\"you@example.com\"\n placeholderTextColor=\"#94a3b8\"\n editable={!submitting}\n className=\"mt-2 rounded-lg border border-slate-300 px-4 py-3\"\n />\n {error ? (\n <Text className=\"mt-2 text-sm text-red-600\">{error}</Text>\n ) : null}\n\n <Pressable\n onPress={handleSubmit}\n disabled={submitting}\n className=\"mt-6 items-center rounded-lg bg-slate-900 py-4 disabled:opacity-60\"\n >\n <Text className=\"font-semibold text-white\">\n {submitting ? 'Sending…' : 'Email me a sign-in link'}\n </Text>\n </Pressable>\n </View>\n </KeyboardAvoidingView>\n </SafeAreaView>\n );\n}\n`;\n\n\tconst gitignore = `node_modules/\n.expo/\ndist/\n*.log\n.env*.local\nios/\nandroid/\n.eas/\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/app/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/app.config.ts', content: appConfig },\n\t\t{\n\t\t\tpath: 'apps/app/eas.json',\n\t\t\tcontent: `${JSON.stringify(easJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/babel.config.js', content: babelConfig },\n\t\t{ path: 'apps/app/metro.config.js', content: metroConfig },\n\t\t{\n\t\t\tpath: 'apps/app/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/tailwind.config.ts', content: tailwindConfig },\n\t\t{ path: 'apps/app/global.css', content: globalCss },\n\t\t{ path: 'apps/app/expo-env.d.ts', content: expoEnvDts },\n\t\t{ path: 'apps/app/nativewind-env.d.ts', content: nativewindEnvDts },\n\t\t{ path: 'apps/app/config.ts', content: configTs },\n\t\t{ path: 'apps/app/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/app/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/app/lib/api.ts', content: apiTs },\n\t\t{ path: 'apps/app/lib/api-context.tsx', content: apiContextTsx },\n\t\t{ path: 'apps/app/app/_layout.tsx', content: layoutTsx },\n\t\t{ path: 'apps/app/app/index.tsx', content: indexTsx },\n\t\t{ path: 'apps/app/app/login.tsx', content: loginTsx },\n\t\t{ path: 'apps/app/.gitignore', content: gitignore },\n\t];\n}\n","import { TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/**\n * Generate packages/models for shared Zod schemas (monorepo only)\n */\nexport function generateModelsPackage(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\t// Package name based on project name\n\tconst packageName = `@${options.name}/models`;\n\n\t// package.json for models\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\texports: {\n\t\t\t'./*': './src/*.ts',\n\t\t},\n\t\tscripts: {\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {},\n\t\tdevDependencies: {\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// tsconfig.json for models - extends root config\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// common.ts - shared utility schemas\n\tconst commonTs = `import { z } from 'zod';\n\n// ============================================\n// Common Schemas\n// ============================================\n\nexport const IdSchema = z.uuid();\n\nexport const IdParamsSchema = z.object({\n id: IdSchema,\n});\n\nexport const TimestampsSchema = z.object({\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport const PaginationSchema = z.object({\n page: z.coerce.number().int().positive().default(1),\n limit: z.coerce.number().int().positive().max(100).default(20),\n});\n\nexport const PaginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>\n z.object({\n items: z.array(itemSchema),\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n });\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type Id = z.infer<typeof IdSchema>;\nexport type IdParams = z.infer<typeof IdParamsSchema>;\nexport type Timestamps = z.infer<typeof TimestampsSchema>;\nexport type Pagination = z.infer<typeof PaginationSchema>;\n`;\n\n\t// user.ts - user-related schemas\n\tconst userTs = `import { z } from 'zod';\nimport { IdSchema, TimestampsSchema } from './common.ts';\n\n// ============================================\n// User Schemas\n// ============================================\n\nexport const UserSchema = z.object({\n id: IdSchema,\n email: z.email(),\n name: z.string().min(1).max(100),\n ...TimestampsSchema.shape,\n});\n\nexport const CreateUserSchema = UserSchema.omit({\n id: true,\n createdAt: true,\n updatedAt: true,\n});\n\nexport const UpdateUserSchema = CreateUserSchema.partial();\n\n// ============================================\n// Response Schemas\n// ============================================\n\nexport const UserResponseSchema = UserSchema.pick({\n id: true,\n name: true,\n email: true,\n});\n\nexport const ListUsersResponseSchema = z.object({\n users: z.array(UserSchema.pick({ id: true, name: true })),\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type User = z.infer<typeof UserSchema>;\nexport type CreateUser = z.infer<typeof CreateUserSchema>;\nexport type UpdateUser = z.infer<typeof UpdateUserSchema>;\nexport type UserResponse = z.infer<typeof UserResponseSchema>;\nexport type ListUsersResponse = z.infer<typeof ListUsersResponseSchema>;\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'packages/models/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/common.ts',\n\t\t\tcontent: commonTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/user.ts',\n\t\t\tcontent: userTs,\n\t\t},\n\t];\n}\n","/**\n * What a workspace needs to reach the host it was scaffolded for.\n *\n * The constructs are the same whichever target is picked — a `Database` is a\n * Postgres on Dokploy and an RDS instance on AWS, and nothing in the\n * application says which. What differs is around them: the deploy script, and\n * for SST the config SST runs and the packages that config imports.\n */\n\nimport { canonicalId } from '@geekmidas/manifest';\nimport { databaseFor, emailFor } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\nexport interface DeployPackage {\n\tscripts: Record<string, string>;\n\tdependencies: Record<string, string>;\n\tdevDependencies: Record<string, string>;\n}\n\n/** One `deploy:<stage>` script per deployed stage. */\nconst perStage = (\n\toptions: TemplateOptions,\n\tcommand: (stage: string) => string,\n): Record<string, string> =>\n\tObject.fromEntries(\n\t\toptions.stages.deployed.map((stage) => [`deploy:${stage}`, command(stage)]),\n\t);\n\nexport function deployPackage(options: TemplateOptions): DeployPackage {\n\tswitch (options.deployTarget) {\n\t\tcase 'dokploy':\n\t\t\treturn {\n\t\t\t\tscripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),\n\t\t\t\tdependencies: {},\n\t\t\t\tdevDependencies: {},\n\t\t\t};\n\t\tcase 'sst': {\n\t\t\tconst v = GEEKMIDAS_VERSIONS;\n\t\t\treturn {\n\t\t\t\t// `gkm deploy` builds `.gkm/manifest/aws.ts` — all `sst.config.ts`\n\t\t\t\t// reads; it never imports the application — then runs\n\t\t\t\t// `sst deploy` and checks what it released.\n\t\t\t\tscripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),\n\t\t\t\t// What `@geekmidas/cloud/sst` imports. They are optional peers of\n\t\t\t\t// the cloud package, so nothing installs them unless asked.\n\t\t\t\tdependencies: {\n\t\t\t\t\t'@geekmidas/cloud': v['@geekmidas/cloud'],\n\t\t\t\t\t'@geekmidas/db': v['@geekmidas/db'],\n\t\t\t\t\t'@geekmidas/envkit': v['@geekmidas/envkit'],\n\t\t\t\t\t'@geekmidas/events': v['@geekmidas/events'],\n\t\t\t\t\t'@geekmidas/manifest': v['@geekmidas/manifest'],\n\t\t\t\t\t'@geekmidas/storage': v['@geekmidas/storage'],\n\t\t\t\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t\t\t},\n\t\t\t\tdevDependencies: { sst: DEPENDENCY_VERSIONS.sst },\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn { scripts: {}, dependencies: {}, devDependencies: {} };\n\t}\n}\n\nexport function generateDeployFiles(options: TemplateOptions): GeneratedFile[] {\n\tif (options.deployTarget !== 'sst') return [];\n\tif (!options.region) throw new SstNeedsRegion();\n\n\tconst db = databaseFor();\n\tconst mail = emailFor();\n\tconst hasDatabase = options.constructs.database;\n\n\t// Provider inputs keyed by construct id: the two things a neutral\n\t// declaration cannot carry. `fromManifest` types its overrides from the\n\t// manifest, so leaving either out is a type error in sst.config.ts.\n\tconst inputs = [\n\t\t...(hasDatabase\n\t\t\t? [\n\t\t\t\t\t` // RDS needs a network. Created here rather than assumed, because a\n // VPC with NAT is a monthly cost in an account that may already\n // have one — replace it with \\`sst.aws.Vpc.get(…)\\` if so.\n ${db.id}: { vpc },`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(options.constructs.mail\n\t\t\t? [\n\t\t\t\t\t` // Every provider rejects an unverified sender, so there is no\n // default — \\`fromManifest\\` requires it, by the manifest's types.\n ${mail.id}: { from: process.env.MAIL_FROM as string },`,\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\n\treturn [\n\t\t{\n\t\t\tpath: 'sst.config.ts',\n\t\t\tcontent: `/// <reference path=\"./.sst/platform/config.d.ts\" />\n\n/**\n * ${options.name} on AWS.\n *\n * No bucket, cluster, queue or IAM is listed here: they come from the\n * constructs the application declares, through \\`fromManifest\\`. What is here\n * is what varies by stage, and the inputs a declaration cannot carry.\n *\n * Deploy with \\`gkm deploy --stage <stage>\\`, which builds the manifest first.\n */\nconst region = '${options.region}';\n\n/** From \\`stages.protected\\` in gkm.config.ts. */\nconst PROTECTED: string[] = ${JSON.stringify(options.stages.protected ?? []).replace(/\"/g, \"'\")};\n\nexport default $config({\n app(input) {\n return {\n name: '${options.name}',\n // Any other stage is disposable; a protected one's database should not\n // vanish because somebody removed a stack.\n removal: PROTECTED.includes(input?.stage) ? 'retain' : 'remove',\n protect: PROTECTED.includes(input?.stage),\n home: 'aws',\n providers: { aws: { region } },\n };\n },\n\n async run() {\n const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');\n // Written by \\`gkm build\\`. Imported rather than discovered,\n // so SST's toolchain never evaluates the application's own modules.\n const { backends, constructs } = await import('./.gkm/manifest/aws.js');\n\n${hasDatabase ? \" const vpc = new sst.aws.Vpc('Vpc', { nat: 'ec2' });\\n\\n\" : ''} const app = new App({\n name: $app.name,\n stage: $app.stage,\n domain: '',\n region,\n hostedZoneId: '',\n });\n\n const provisioned = fromManifest(\n new Stack(app, '${canonicalId(options.name)}'),\n constructs,\n {\n${inputs.join('\\n')}\n },\n backends,\n );\n\n // Each surface's URL, by its id: SST prints these and writes them to\n // .sst/outputs.json, where \\`gkm deploy\\` reads them to health-check\n // what it released.\n return Object.fromEntries(\n Object.entries(constructs)\n .filter(([, c]) => c.kind === 'rest-api' || c.kind === 'site')\n .map(([id]) => [id, provisioned[id]!.provides().url]),\n );\n },\n});\n`,\n\t\t},\n\t];\n}\n\n/**\n * An SST scaffold asked for without a region. `init` always resolves one —\n * asked, `--region`, or eu-west-1 under `--yes` — so this is a caller's bug.\n */\nexport class SstNeedsRegion extends Error {\n\tconstructor() {\n\t\tsuper('An SST deploy needs a region: pass --region, e.g. eu-west-1.');\n\t\tthis.name = 'SstNeedsRegion';\n\t}\n}\n","import { dirname } from 'node:path';\nimport {\n\tcacheFor,\n\tdatabaseFor,\n\temailFor,\n\tstorageFor,\n\tusersMigration,\n\tworkspaceConstructsGlobs,\n} from '../constructs.js';\nimport {\n\tBIOME_SCHEMA,\n\tDEPENDENCY_VERSIONS,\n\tEXPO_VERSIONS,\n\tPNPM_VERSION,\n\tTOOLCHAIN_VERSIONS,\n} from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport { deployPackage, generateDeployFiles } from './deploy.js';\nimport { stagesBlock } from './stages.js';\n\n/**\n * What the root `constructs/` folder imports, and the peers each construct\n * needs, for the services this workspace was scaffolded with.\n */\nfunction rootConstructDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\tconst v = GEEKMIDAS_VERSIONS;\n\treturn {\n\t\t'@geekmidas/constructs': v['@geekmidas/constructs'],\n\t\t'@geekmidas/logger': v['@geekmidas/logger'],\n\t\t...(options.loggerType === 'pino'\n\t\t\t? { pino: DEPENDENCY_VERSIONS.pino }\n\t\t\t: {}),\n\t\t// `RestApi` needs Telescope's types; `BetterAuth` needs the auth\n\t\t// package and Better Auth itself.\n\t\t'@geekmidas/telescope': v['@geekmidas/telescope'],\n\t\t'@geekmidas/auth': v['@geekmidas/auth'],\n\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t// `KyselyDatabase`.\n\t\t'@geekmidas/db': v['@geekmidas/db'],\n\t\tkysely: DEPENDENCY_VERSIONS.kysely,\n\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t...(options.constructs.uploads\n\t\t\t? { '@geekmidas/storage': v['@geekmidas/storage'] }\n\t\t\t: {}),\n\t\t...(options.constructs.mail\n\t\t\t? { '@geekmidas/emailkit': v['@geekmidas/emailkit'] }\n\t\t\t: {}),\n\t\t...(options.constructs.cache\n\t\t\t? { '@geekmidas/cache': v['@geekmidas/cache'] }\n\t\t\t: {}),\n\t\t// A mobile app signs in through Better Auth's Expo plugin, which the\n\t\t// auth server loads when one depends on it.\n\t\t...(options.frontendFramework === 'expo'\n\t\t\t? { '@better-auth/expo': DEPENDENCY_VERSIONS['better-auth'] }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * What each API's generated client imports, installed where the client is.\n *\n * The client is written to the root's `.gkm/client/`, so it resolves\n * `@geekmidas/client` and React Query from the root `node_modules` — as the\n * root `constructs/` folder does its imports — not from whichever site imports\n * it.\n *\n * React is pinned here too, because React Query's hooks resolve it from the\n * root, and a frontend running a different React than the one its client's\n * hooks resolve loads two — a broken hook call. So the root's React is the\n * workspace's: every frontend that imports a client runs this one. It starts\n * as the scaffolded frontend's; a frontend added later — a web app beside an\n * Expo app — is kept on the same version, not given its own.\n */\nfunction rootClientDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\treturn {\n\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\treact:\n\t\t\toptions.frontendFramework === 'expo'\n\t\t\t\t? EXPO_VERSIONS.react\n\t\t\t\t: DEPENDENCY_VERSIONS.react,\n\t};\n}\n\n/**\n * What `test/factories/` imports at the root: the factory and faker, and\n * Kysely's types where the root does not already install it for the\n * constructs.\n */\nfunction rootFactoryDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\treturn {\n\t\t'@geekmidas/testkit': GEEKMIDAS_VERSIONS['@geekmidas/testkit'],\n\t\t'@faker-js/faker': DEPENDENCY_VERSIONS['@faker-js/faker'],\n\t\t...(options.template === 'fullstack'\n\t\t\t? {}\n\t\t\t: { kysely: DEPENDENCY_VERSIONS.kysely }),\n\t};\n}\n\n/**\n * Generate monorepo root files (pnpm-workspace.yaml, root package.json, etc.)\n */\nexport function generateMonorepoFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\tconst isFullstack = options.template === 'fullstack';\n\tconst deploy = deployPackage(options);\n\tconst isSst = options.deployTarget === 'sst';\n\n\t// Root package.json for monorepo\n\tconst rootPackageJson = {\n\t\tname: options.name,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tpackageManager: PNPM_VERSION,\n\t\tscripts: {\n\t\t\tdev: isFullstack ? 'gkm dev' : 'turbo dev',\n\t\t\tbuild: isFullstack ? 'gkm build' : 'turbo build',\n\t\t\ttest: isFullstack ? 'gkm test' : 'turbo test',\n\t\t\t'test:once': isFullstack ? 'gkm test --run' : 'turbo test:once',\n\t\t\ttypecheck: 'turbo typecheck',\n\t\t\tlint: 'biome lint .',\n\t\t\tfmt: 'biome format . --write',\n\t\t\t'fmt:check': 'biome format .',\n\t\t\t...deploy.scripts,\n\t\t},\n\t\tdependencies: {\n\t\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t\t\t// The root `constructs/` folder resolves its imports from the root\n\t\t\t// `node_modules`, not from any app's — so what the constructs load,\n\t\t\t// and the peers each of them needs, are installed here.\n\t\t\t...(isFullstack ? rootConstructDependencies(options) : {}),\n\t\t\t...(isFullstack ? rootClientDependencies(options) : {}),\n\t\t\t...deploy.dependencies,\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t\t\t// The test factories live at the root — a factory belongs to a\n\t\t\t// database, not to an app — and resolve their imports from the root\n\t\t\t// `node_modules`, as the constructs do.\n\t\t\t...(options.constructs.database ? rootFactoryDependencies(options) : {}),\n\t\t\t...deploy.devDependencies,\n\t\t},\n\t};\n\n\t// pnpm-workspace.yaml - detect folder structure from apiPath\n\tconst apiPathParts = options.apiPath.split('/');\n\tconst appsFolder = apiPathParts[0] || 'apps';\n\n\tconst pnpmWorkspace = `packages:\n - '${appsFolder}/*'\n - 'packages/*'\n`;\n\n\t// Root biome.json\n\tconst biomeConfig = {\n\t\t$schema: BIOME_SCHEMA,\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\t// Biome 2 moved import sorting into the assist, and `files.ignore` into\n\t\t// negated `includes`: the 1.x keys make it refuse the whole config.\n\t\tassist: { actions: { source: { organizeImports: 'on' } } },\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Tailwind v4's `@theme` and `@apply`, which the UI package's CSS uses.\n\t\tcss: { parser: { tailwindDirectives: true } },\n\t\tfiles: {\n\t\t\tincludes: [\n\t\t\t\t'**',\n\t\t\t\t'!**/node_modules',\n\t\t\t\t'!**/dist',\n\t\t\t\t'!**/.gkm',\n\t\t\t\t'!**/coverage',\n\t\t\t\t...(isSst ? ['!**/.sst', '!sst-env.d.ts'] : []),\n\t\t\t],\n\t\t},\n\t};\n\n\t// Root turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\t// Turbo hashes a package's own files, and an app's constructs and\n\t\t\t\t// the config naming them live above it, at the root. Without these,\n\t\t\t\t// editing a construct replays a stale cached build. Root task config\n\t\t\t\t// applies to every package, so a new app is covered with nothing\n\t\t\t\t// generated. `$TURBO_ROOT$` needs turbo 2.4+.\n\t\t\t\tinputs: [\n\t\t\t\t\t'$TURBO_DEFAULT$',\n\t\t\t\t\t'$TURBO_ROOT$/constructs/**/*.ts',\n\t\t\t\t\t'$TURBO_ROOT$/gkm.config.ts',\n\t\t\t\t],\n\t\t\t\t// A backend's build is under `.gkm/`; a Next.js site's under `.next/`.\n\t\t\t\toutputs: ['dist/**', '.gkm/**', '.next/**', '!.next/cache/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\t// Root .gitignore\n\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Written by gkm from the constructs; your own docker-compose.yml is not\ndocker-compose.constructs.yml\n\n# Environment\n.env\n.env.local\n.env.*.local\ndocker/.env\n\n# IDE\n.idea/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Turbo\n.turbo/\n${isSst ? '\\n# SST\\n.sst/\\n' : ''}`;\n\n\t// Root tsconfig.json - base config for all packages\n\t// Using turbo typecheck to run tsc --noEmit in each app/package\n\tconst tsConfig = {\n\t\tcompilerOptions: {\n\t\t\t// How an app reaches the workspace's constructs without climbing out\n\t\t\t// of its own directory with `../../` — and the manifest `gkm build`\n\t\t\t// writes at the root, for whatever reads what was built.\n\t\t\tpaths: {\n\t\t\t\t...(isFullstack\n\t\t\t\t\t? { [`@${options.name}/constructs/*`]: ['./constructs/*'] }\n\t\t\t\t\t: {}),\n\t\t\t\t[`@${options.name}/manifest`]: [\n\t\t\t\t\t`./.gkm/manifest/${isSst ? 'aws' : 'server'}.ts`,\n\t\t\t\t],\n\t\t\t\t// Each API's typed client, generated beside the manifest.\n\t\t\t\t[`@${options.name}/client/*`]: ['./.gkm/client/*'],\n\t\t\t},\n\t\t\t...(isFullstack\n\t\t\t\t? {\n\t\t\t\t\t\t// The constructs import each other with `.ts` extensions.\n\t\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t\tnoEmit: true,\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\ttarget: 'ES2022',\n\t\t\tmodule: 'NodeNext',\n\t\t\tmoduleResolution: 'NodeNext',\n\t\t\tlib: ['ES2022'],\n\t\t\tstrict: true,\n\t\t\tesModuleInterop: true,\n\t\t\tskipLibCheck: true,\n\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\tresolveJsonModule: true,\n\t\t},\n\t\t// SST typechecks its own config against its own platform types, which\n\t\t// exist only after \\`sst install\\` and are not this project's to check.\n\t\texclude: [\n\t\t\t'node_modules',\n\t\t\t'dist',\n\t\t\t...(isSst ? ['sst.config.ts', '.sst'] : []),\n\t\t],\n\t};\n\n\t// Vitest config for workspace\n\tconst vitestConfig = `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n // The test stage, reconciled and every database construct's migrations\n // applied, before any project's tests start — declared here, once, so no\n // project filter can skip it and nothing runs it twice.\n globalSetup: ['@geekmidas/cli/vitest'],\n // Each app and package is its own project, so its own config — its path\n // aliases — applies to its own tests.\n projects: ['apps/*', 'packages/*'],\n // The shared packages ship without tests of their own.\n passWithNoTests: true,\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json', 'html'],\n exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts'],\n },\n },\n});\n`;\n\n\t// VSCode settings for consistent development experience\n\tconst vscodeSettings = {\n\t\t'search.exclude': {\n\t\t\t'**/.sst': true,\n\t\t\t'**/.gkm': true,\n\t\t\t'**/.turbo': true,\n\t\t},\n\t\t'editor.formatOnSave': true,\n\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t'editor.codeActionsOnSave': {\n\t\t\t'source.fixAll.biome': 'always',\n\t\t\t'source.organizeImports.biome': 'always',\n\t\t\t'source.organizeImports': 'always',\n\t\t},\n\t\t'[typescriptreact]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[typescript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[javascript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[json]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'cSpell.words': [\n\t\t\t'betterauth',\n\t\t\t'dokploy',\n\t\t\t'envkit',\n\t\t\t'geekmidas',\n\t\t\t'healthcheck',\n\t\t\t'kysely',\n\t\t\t'testkit',\n\t\t\t'timestamptz',\n\t\t\t'turborepo',\n\t\t\toptions.name,\n\t\t],\n\t};\n\n\t// VSCode extensions recommendations\n\tconst vscodeExtensions = {\n\t\trecommendations: [\n\t\t\t'biomejs.biome',\n\t\t\t'streetsidesoftware.code-spell-checker',\n\t\t\t'dbaeumer.vscode-eslint',\n\t\t\t'ms-azuretools.vscode-docker',\n\t\t],\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(rootPackageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'pnpm-workspace.yaml',\n\t\t\tcontent: pnpmWorkspace,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfig,\n\t\t},\n\t\t{\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/settings.json',\n\t\t\tcontent: `${JSON.stringify(vscodeSettings, null, '\\t')}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/extensions.json',\n\t\t\tcontent: `${JSON.stringify(vscodeExtensions, null, '\\t')}\\n`,\n\t\t},\n\t\t...generateDeployFiles(options),\n\t];\n\n\t// Add workspace config for fullstack template\n\tif (isFullstack) {\n\t\tfiles.push({\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: generateWorkspaceConfig(options),\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * `gkm.config.ts` for the fullstack workspace.\n *\n * What is *not* here is the point. There is no `apps` block: the apps are the\n * constructs that said they have a process — a `RestApi`, a `BetterAuth`, a\n * `StaticSite` — and naming them again here would be the same sentence written\n * twice with only one copy checked.\n *\n * There is no `services` block either unless something non-default was picked.\n * Every key defaults from the deploy target: on a server target a cache is a\n * table in the database that is already there, storage is MinIO, mail is SES.\n */\nfunction generateWorkspaceConfig(options: TemplateOptions): string {\n\tconst config = `import { defineWorkspace } from '@geekmidas/cli/config';\n\nexport default defineWorkspace({\n // The scope every physical name is built from: \\`Database\\` becomes\n // \\`production-${options.name}-database\\` on Dokploy and on AWS alike.\n name: '${options.name}',\n${stagesBlock(options.stages)}\n${deployBlock(options)}\n // Every kind, in every app. A declared database is why a Postgres exists, a\n // declared bucket is why MinIO does, a declared topic is why a broker does —\n // none of it listed here. It is also where the apps come from: a\n // \\`StaticSite\\` is an app, and so is every \\`RestApi\\`. And it finds each\n // app's endpoints, crons and subscribers: an endpoint belongs to the surface\n // it was built from, not to the directory it sits in.\n constructs: [\n${workspaceConstructsGlobs(options.routesStructure, dirname(options.apiPath))\n\t.map((glob) => ` '${glob}',`)\n\t.join('\\n')}\n ],\n\n secrets: {\n enabled: true,${secretsStore(options)}\n },\n});\n`;\n\n\treturn config;\n}\n\n/**\n * Where it deploys, when that is not the default Dokploy: what a bare\n * `gkm build` builds for, and which backends a cache or a broker resolves to.\n */\nfunction deployBlock(options: TemplateOptions): string {\n\tif (options.deployTarget !== 'sst') return '';\n\treturn `\n // \\`gkm deploy\\` runs \\`sst deploy\\` on the manifest \\`gkm build\\` writes to\n // \\`.gkm/manifest/aws.ts\\`. Each construct becomes a managed AWS resource.\n deploy: { default: 'sst' },\n`;\n}\n\n/**\n * Where a deployed stage's secrets live. On AWS that is SSM in the stage's own\n * account, which the deploy job reaches with the role it already assumed; a\n * server target keeps the encrypted local file, the default.\n */\nfunction secretsStore(options: TemplateOptions): string {\n\tif (options.deployTarget !== 'sst' || !options.region) return '';\n\treturn `\n // Deployed stages keep their secrets in SSM, in the account each stage\n // deploys to: \\`gkm secrets:set <KEY> '…' --stage <stage>\\` writes there.\n // Past 8 KB a stage needs { provider: 'secrets-manager', region } instead.\n store: { provider: 'ssm', region: '${options.region}' },`;\n}\n\n/**\n * The workspace's constructs, at its root rather than inside an app.\n *\n * They outlive the app that used them first: a site depending on the API is a\n * fact about the workspace, and a construct reaching across into a sibling\n * app's `src/` to state it is the shape this layout removes. Apps import them\n * through the `@<name>/constructs/*` path the root tsconfig maps.\n *\n * Every one of these is also an answer config used to give: the database is\n * why a Postgres exists, the surface and the site are the apps, and the edges\n * between them are the CORS origins and the build order.\n */\nexport function generateRootConstructs(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') return [];\n\n\tconst { frontendFramework } = options;\n\tconst { cache, uploads, mail } = options.constructs;\n\tconst db = databaseFor();\n\tconst files: GeneratedFile[] = [];\n\n\tfiles.push({\n\t\tpath: 'constructs/logger.ts',\n\t\tcontent: `import { createLogger } from '@geekmidas/logger/${options.loggerType}';\n\n/**\n * The logger every endpoint runs with.\n *\n * Named once, here, because the surface carries it. It used to be\n * \\`logger: './src/config/logger#logger'\\` in config — a module path the build\n * printed into each generated handler, checked by nothing and wrong the moment\n * the file moved.\n */\nexport const logger = createLogger();\n`,\n\t});\n\n\tfiles.push({\n\t\tpath: 'constructs/database.ts',\n\t\tcontent: `import { KyselyDatabase } from '@geekmidas/constructs/database/kysely';\nimport { CamelCasePlugin, type Generated } from 'kysely';\n\n/**\n * Your database schema. Add tables here.\n *\n * camelCase, because of the plugin below: the columns are snake_case in\n * Postgres (\\`created_at\\`), and Kysely maps between the two.\n */\nexport interface Database {\n users: {\n id: Generated<string>;\n name: string;\n email: string;\n createdAt: Generated<Date>;\n };\n}\n\n/**\n * The database, declared once.\n *\n * The container, the database inside it, its roles and schema, and\n * \\`${db.urlKey}\\` all derive from this line — which is why nothing lists\n * \\`postgres\\` anywhere.\n */\nexport const database = new KyselyDatabase<Database, '${db.id}'>('${db.id}', {\n // Yours to keep, change or remove. Every connection this construct opens —\n // every endpoint, the tests — uses it.\n plugins: [new CamelCasePlugin()],\n});\n\n/**\n * The auth server's own schema in that same Postgres, with its own role.\n *\n * A schema tenant rather than a second database: one container, and a role\n * whose \\`search_path\\` is pinned, so Better Auth's tables cannot collide with\n * the application's. It takes its own options: no plugin, because Better\n * Auth names its own columns.\n */\nexport const authDb = database.schema<Record<string, never>, 'AuthDb'>('AuthDb');\n`,\n\t});\n\n\t// Its migrations beside it, in the folder its name gives.\n\tfiles.push(usersMigration());\n\n\tfiles.push({\n\t\tpath: 'constructs/auth.ts',\n\t\tcontent: `${frontendFramework === 'expo' ? \"import { expo } from '@better-auth/expo';\\n\" : ''}import { BetterAuth } from '@geekmidas/constructs/auth';\nimport { authDb } from './database.ts';\n\n/**\n * The auth server.\n *\n * There is no \\`src/index.ts\\` to go with this, and that is the point: the\n * routes are a wildcard, so no glob finds them and the build generates the\n * entry from this declaration instead. CORS, the trusted origins and the\n * cookie domain come from whatever declared an edge to it — nobody writes an\n * origin down.\n */\nexport const auth = new BetterAuth('Auth', {\n path: 'apps/auth',\n database: authDb,\n basePath: '/api/auth',${\n\t\tfrontendFramework === 'expo'\n\t\t\t? `\n // The mobile app signs in through Better Auth's Expo plugin: it sends its\n // scheme as the origin, and this is what reads it. The construct refuses to\n // start without it once a MobileApp depends on this server.\n options: { plugins: [expo()] },`\n\t\t\t: ''\n\t}\n});\n`,\n\t});\n\n\tfiles.push({\n\t\tpath: 'constructs/api.ts',\n\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { auth } from './auth.ts';\nimport { logger } from './logger.ts';\n\n/**\n * The application's HTTP surface — one RestApi, one container.\n *\n * \\`path\\` is where its app lives. Its handlers are found by the workspace's\n * \\`constructs\\` glob, and belong to it because they were built from it.\n */\nexport const api = new RestApi('Api', {\n path: '${options.apiPath}',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one.\n logger,\n}).auth(auth);\n`,\n\t});\n\n\tconst variant =\n\t\tfrontendFramework === 'tanstack-start'\n\t\t\t? \"{ path: 'apps/web', variant: 'tanstack' }\"\n\t\t\t: frontendFramework === 'expo'\n\t\t\t\t? undefined\n\t\t\t\t: \"{ path: 'apps/web', variant: 'next' }\";\n\n\tif (frontendFramework === 'expo') {\n\t\tfiles.push({\n\t\t\tpath: 'constructs/app.ts',\n\t\t\tcontent: `import { MobileApp } from '@geekmidas/constructs/mobile-app';\nimport { api } from './api.ts';\nimport { auth } from './auth.ts';\n\n/**\n * The mobile app — a construct like a site, which is what makes it an app.\n *\n * \\`.dependsOn()\\` is the single fact behind what a mobile app otherwise has\n * written down by hand: its API and auth URLs, its URL scheme, the\n * scheme in the auth server's trusted origins, Better Auth's Expo plugin, and\n * sign-in links a phone can open.\n */\nexport const app = new MobileApp('App', { path: 'apps/app' }).dependsOn([\n api,\n auth,\n]);\n`,\n\t\t});\n\t}\n\n\tif (variant !== undefined) {\n\t\tfiles.push({\n\t\t\tpath: 'constructs/site.ts',\n\t\t\tcontent: `import { StaticSite } from '@geekmidas/constructs/site';\nimport { api } from './api.ts';\nimport { auth } from './auth.ts';\n\n/**\n * The frontend — a construct like any other, which is what makes it an app.\n *\n * \\`path\\` is where it lives. \\`.dependsOn()\\` is the single fact\n * behind four things that are hand-maintained otherwise: this site's\n * build-time API URL, the API's CORS origins, the auth server's trusted\n * origins, and which generated client lands here.\n */\nexport const web = new StaticSite('Web', ${variant}).dependsOn([api, auth]);\n`,\n\t\t});\n\t}\n\n\tif (uploads) {\n\t\tconst bucket = storageFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/storage.ts',\n\t\t\tcontent: `import { ObjectStorage } from '@geekmidas/constructs/object-storage';\n\n/** A bucket — MinIO locally, S3 deployed, one declaration for both. */\nexport const uploads = new ObjectStorage('${bucket.id}');\n`,\n\t\t});\n\t}\n\n\tif (mail) {\n\t\tconst mail = emailFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/email.ts',\n\t\t\tcontent: `import { Email } from '@geekmidas/constructs/email';\n\n/** Outbound mail — Mailpit locally, SES deployed. */\nexport const email = new Email('${mail.id}', { templates: {} });\n`,\n\t\t});\n\t}\n\n\tif (cache) {\n\t\tconst kv = cacheFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/cache.ts',\n\t\t\tcontent: `import { Cache } from '@geekmidas/constructs/cache';\n\n/**\n * A cache. Which backend serves it follows the deploy target — a table in the\n * database on a server, Upstash on AWS — so nothing here says where it lives.\n */\nexport const cache = new Cache('${kv.id}');\n`,\n\t\t});\n\t}\n\n\treturn files;\n}\n","import { DEPENDENCY_VERSIONS, PNPM_VERSION } from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate package.json with dependencies based on template and options\n */\nexport function generatePackageJson(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { name, telescope, monorepo } = options;\n\tconst { database, cache, uploads, mail } = options.constructs;\n\n\t// Start with template dependencies\n\tconst dependencies = { ...template.dependencies };\n\tconst devDependencies = { ...template.devDependencies };\n\tconst scripts = { ...template.scripts };\n\n\t// The logger the scaffold imports is `@geekmidas/logger/<loggerType>`, and\n\t// only the pino one needs pino installed beside it.\n\tif (options.loggerType === 'pino') {\n\t\tdependencies.pino = DEPENDENCY_VERSIONS.pino;\n\t}\n\n\t// Add optional dependencies based on user choices\n\tif (telescope) {\n\t\tdependencies['@geekmidas/telescope'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/telescope'];\n\t}\n\n\t// Only a project that declares constructs needs them. The workspace path\n\t// still reaches its infrastructure through hand-written services.\n\tconst declares = !monorepo;\n\n\t// Every construct resolves its env key through the manifest, so declaring\n\t// one at all is what needs this — not any particular kind.\n\tif (declares && (database || uploads || cache || mail)) {\n\t\tdependencies['@geekmidas/manifest'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/manifest'];\n\t}\n\n\t// A construct hands back a client from the package that owns it, and each of\n\t// those is an optional peer — an app that declares no bucket resolves no S3\n\t// SDK. Installed here because the app declared one.\n\tif (declares && uploads) {\n\t\tdependencies['@geekmidas/storage'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/storage'];\n\t}\n\n\tif (declares && cache) {\n\t\tdependencies['@geekmidas/cache'] = GEEKMIDAS_VERSIONS['@geekmidas/cache'];\n\t}\n\n\tif (declares && mail) {\n\t\tdependencies['@geekmidas/emailkit'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/emailkit'];\n\t}\n\n\tif (database) {\n\t\tdependencies['@geekmidas/db'] = GEEKMIDAS_VERSIONS['@geekmidas/db'];\n\t\tdependencies.kysely = DEPENDENCY_VERSIONS.kysely;\n\t\tdependencies.pg = DEPENDENCY_VERSIONS.pg;\n\t\tdevDependencies['@types/pg'] = DEPENDENCY_VERSIONS['@types/pg'];\n\t\tdevDependencies['@geekmidas/testkit'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/testkit'];\n\t\tdevDependencies['@faker-js/faker'] = DEPENDENCY_VERSIONS['@faker-js/faker'];\n\t}\n\n\t// For monorepo apps, remove biome/turbo/esbuild (they're at root) and lint/fmt scripts\n\t// zod is at root level for monorepos\n\tif (monorepo) {\n\t\tdelete devDependencies['@biomejs/biome'];\n\t\tdelete devDependencies.turbo;\n\t\tdelete devDependencies.esbuild;\n\t\tdelete dependencies.zod;\n\t\tdelete scripts.lint;\n\t\tdelete scripts.fmt;\n\t\tdelete scripts['fmt:check'];\n\n\t\t// Add models package as dependency\n\t\tdependencies[`@${name}/models`] = 'workspace:*';\n\t}\n\n\t// Sort dependencies alphabetically\n\tconst sortObject = (obj: Record<string, string>) =>\n\t\tObject.fromEntries(\n\t\t\tObject.entries(obj).sort(([a], [b]) => a.localeCompare(b)),\n\t\t);\n\n\t// For monorepo, derive package name from apiPath (e.g., apps/api -> @name/api)\n\tlet packageName = name;\n\tif (monorepo && options.apiPath) {\n\t\tconst pathParts = options.apiPath.split('/');\n\t\tconst appName = pathParts[pathParts.length - 1] || 'api';\n\t\tpackageName = `@${name}/${appName}`;\n\t}\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\t// A workspace's root carries this; a standalone app is its own root.\n\t\t...(!monorepo && options.packageManager === 'pnpm'\n\t\t\t? { packageManager: PNPM_VERSION }\n\t\t\t: {}),\n\t\tscripts,\n\t\tdependencies: sortObject(dependencies),\n\t\tdevDependencies: sortObject(devDependencies),\n\t};\n\n\treturn [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t];\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate source files from template\n */\nexport function generateSourceFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\treturn template.files(options);\n}\n","import { kebabCase, serviceKey } from '@geekmidas/manifest';\nimport { databaseFor } from '../constructs.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate test infrastructure files when database is enabled: the\n * transaction-isolated test config and an example spec, in the app. The\n * factory is the project's — see {@link generateTestFactoryFiles}.\n */\nexport function generateTestFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.constructs.database) {\n\t\treturn [];\n\t}\n\n\t// The keys the declared database publishes. Migrations connect as the owner\n\t// role — the one that may create, alter, and drop; a handler is never given\n\t// it, which is the security property the role split exists for.\n\tconst db = databaseFor();\n\n\t// Single-app projects have no `~/*` alias, so what a test file imports\n\t// depends on where it will sit.\n\tconst declares = !options.monorepo;\n\tconst schema = declares\n\t\t? '../src/constructs/database.ts'\n\t\t: `@${options.name}/constructs/database.ts`;\n\n\t// Both layouts declare the same database, so both publish the same keys. A\n\t// monorepo used to read a per-app secret here instead, and rendered the\n\t// owner key as the runtime one — so its migrations ran as the role that may\n\t// create nothing, and failed on the first table.\n\tconst runtimeUrl = db.urlKey;\n\tconst ownerUrl = db.ownerUrlKey;\n\n\treturn [\n\t\t// test/config.ts - Wraps vitest `it` with transaction auto-rollback\n\t\t{\n\t\t\tpath: 'test/config.ts',\n\t\t\tcontent: `import { it as itVitest } from 'vitest';\nimport { wrapVitestKyselyTransaction } from '@geekmidas/testkit/kysely';\nimport { type Database, database } from '${schema}';\n\nexport const it = wrapVitestKyselyTransaction<Database>(itVitest, {\n // The construct itself, so the tests connect the way the app does — with\n // the plugins it was given, \\`CamelCasePlugin\\` included.\n connection: database,\n});\n`,\n\t\t},\n\n\t\t// test/example.spec.ts - Example test showing usage\n\t\t{\n\t\t\tpath: 'test/example.spec.ts',\n\t\t\tcontent: `import { describe, expect } from 'vitest';\nimport { it } from './config.ts';\n\ndescribe('example', () => {\n it('should have a working test setup', async ({ trx }) => {\n // trx is a Kysely transaction; everything in it is rolled back after the\n // test\n expect(trx).toBeDefined();\n });\n});\n`,\n\t\t},\n\t];\n}\n\n/**\n * The database's test factory, at the project root:\n * `test/factories/<construct>.ts`.\n *\n * A factory belongs to a database, not to an app, so there is one per database\n * for the whole project. `gkm test` finds it by that name and hands every\n * feature test \\`factories.get('database')\\`, built on the test's transaction.\n */\nexport function generateTestFactoryFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.constructs.database) {\n\t\treturn [];\n\t}\n\n\tconst db = databaseFor();\n\t// From the project root. A fullstack monorepo declares its constructs at\n\t// the root and maps them through the root tsconfig; an API monorepo keeps\n\t// them in the app, and a single app under `src/`.\n\tconst schema =\n\t\toptions.monorepo && options.template === 'fullstack'\n\t\t\t? `@${options.name}/constructs/database.ts`\n\t\t\t: options.monorepo\n\t\t\t\t? `../../${options.apiPath}/src/constructs/database.ts`\n\t\t\t\t: '../../src/constructs/database.ts';\n\n\treturn [\n\t\t{\n\t\t\tpath: `test/factories/${kebabCase(db.id)}.ts`,\n\t\t\tcontent: `import type { Kysely } from 'kysely';\nimport { KyselyFactory } from '@geekmidas/testkit/kysely';\nimport type { Database } from '${schema}';\n\nconst usersBuilder = KyselyFactory.createBuilder<Database, 'users'>(\n 'users',\n ({ faker }) => ({\n id: faker.string.uuid(),\n name: faker.person.fullName(),\n email: faker.internet.email(),\n createdAt: new Date(),\n }),\n);\n\nconst builders = { users: usersBuilder };\nconst seeds = {};\n\n/**\n * This database's factory. \\`gkm test\\` builds it on each feature test's\n * transaction and hands it over as \\`factories.get('${serviceKey(db.id)}')\\`.\n */\nexport function createFactory(db: Kysely<Database>) {\n return new KyselyFactory<Database, typeof builders, typeof seeds>(\n builders,\n seeds,\n db,\n );\n}\n\nexport type Factory = ReturnType<typeof createFactory>;\n`,\n\t\t},\n\t];\n}\n","import { DEPENDENCY_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile } from '../templates/index.js';\n\n/**\n * shadcn/ui components, written into the web app that uses them.\n *\n * shadcn is copy-in by design: the components are the app's own source, to\n * edit and add to with `npx shadcn@latest add`. A shared workspace package of\n * them was one more package to build and version for code only the web app\n * imported.\n */\n\n/** What the components below import. */\nexport const SHADCN_DEPENDENCIES = {\n\t'@radix-ui/react-dialog': DEPENDENCY_VERSIONS['@radix-ui/react-dialog'],\n\t'@radix-ui/react-label': DEPENDENCY_VERSIONS['@radix-ui/react-label'],\n\t'@radix-ui/react-separator': DEPENDENCY_VERSIONS['@radix-ui/react-separator'],\n\t'@radix-ui/react-slot': DEPENDENCY_VERSIONS['@radix-ui/react-slot'],\n\t'@radix-ui/react-tabs': DEPENDENCY_VERSIONS['@radix-ui/react-tabs'],\n\t'@radix-ui/react-tooltip': DEPENDENCY_VERSIONS['@radix-ui/react-tooltip'],\n\t'class-variance-authority': DEPENDENCY_VERSIONS['class-variance-authority'],\n\tclsx: DEPENDENCY_VERSIONS['clsx'],\n\t'lucide-react': DEPENDENCY_VERSIONS['lucide-react'],\n\t'tailwind-merge': DEPENDENCY_VERSIONS['tailwind-merge'],\n} as const;\n\n/**\n * Tailwind v4 with the shadcn theme tokens — the stylesheet the app imports\n * once, at its root.\n */\nexport const SHADCN_GLOBALS_CSS = `@import \"tailwindcss\";\n\n@theme {\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 0 0% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 0 0% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 0 0% 3.9%;\n --primary: 160 84% 39%;\n --primary-foreground: 0 0% 98%;\n --secondary: 0 0% 96.1%;\n --secondary-foreground: 0 0% 9%;\n --muted: 0 0% 96.1%;\n --muted-foreground: 0 0% 45.1%;\n --accent: 0 0% 96.1%;\n --accent-foreground: 0 0% 9%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 89.8%;\n --input: 0 0% 89.8%;\n --ring: 160 84% 39%;\n --radius: 0.5rem;\n }\n\n .dark {\n --background: 0 0% 9%;\n --foreground: 0 0% 98%;\n --card: 0 0% 11%;\n --card-foreground: 0 0% 98%;\n --popover: 0 0% 11%;\n --popover-foreground: 0 0% 98%;\n --primary: 160 84% 52%;\n --primary-foreground: 0 0% 9%;\n --secondary: 0 0% 15%;\n --secondary-foreground: 0 0% 98%;\n --muted: 0 0% 15%;\n --muted-foreground: 0 0% 64%;\n --accent: 0 0% 15%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 50.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 18%;\n --input: 0 0% 18%;\n --ring: 160 84% 52%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n`;\n\n/**\n * The components, `cn`, and the `components.json` that tells the shadcn CLI\n * where they live.\n *\n * @param appDir the web app, relative to the workspace root (`apps/web`)\n * @param css the stylesheet holding {@link SHADCN_GLOBALS_CSS}, relative to\n * the app\n * @param options.rsc whether the app renders React Server Components, so\n * `shadcn add` marks what it writes `'use client'`. The radix-based\n * components here carry the directive either way; outside RSC it is inert.\n */\nexport function shadcnFiles(\n\tappDir: string,\n\tcss: string,\n\toptions: { rsc: boolean },\n): GeneratedFile[] {\n\tconst componentsJson = {\n\t\t$schema: 'https://ui.shadcn.com/schema.json',\n\t\tstyle: 'new-york',\n\t\trsc: options.rsc,\n\t\ttsx: true,\n\t\ttailwind: {\n\t\t\tconfig: '',\n\t\t\tcss,\n\t\t\tbaseColor: 'neutral',\n\t\t\tcssVariables: true,\n\t\t\tprefix: '',\n\t\t},\n\t\taliases: {\n\t\t\tcomponents: '~/components',\n\t\t\tutils: '~/lib/utils',\n\t\t\tui: '~/components/ui',\n\t\t\tlib: '~/lib',\n\t\t\thooks: '~/hooks',\n\t\t},\n\t\ticonLibrary: 'lucide',\n\t};\n\tconst utilsTs = `import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`;\n\n\tconst buttonTsx = `import { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n default:\n 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button';\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n`;\n\n\tconst inputTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = 'Input';\n\nexport { Input };\n`;\n\n\tconst cardTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-xl border bg-card text-card-foreground shadow',\n className,\n )}\n {...props}\n />\n));\nCard.displayName = 'Card';\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-1.5 p-6', className)}\n {...props}\n />\n));\nCardHeader.displayName = 'CardHeader';\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-semibold leading-none tracking-tight', className)}\n {...props}\n />\n));\nCardTitle.displayName = 'CardTitle';\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n));\nCardDescription.displayName = 'CardDescription';\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />\n));\nCardContent.displayName = 'CardContent';\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center p-6 pt-0', className)}\n {...props}\n />\n));\nCardFooter.displayName = 'CardFooter';\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };\n`;\n\n\tconst labelTsx = `'use client';\n\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(labelVariants(), className)}\n {...props}\n />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n`;\n\n\tconst badgeTsx = `import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst badgeVariants = cva(\n 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',\n {\n variants: {\n variant: {\n default:\n 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',\n secondary:\n 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',\n destructive:\n 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',\n outline: 'text-foreground',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\nfunction Badge({ className, variant, ...props }: BadgeProps) {\n return (\n <div className={cn(badgeVariants({ variant }), className)} {...props} />\n );\n}\n\nexport { Badge, badgeVariants };\n`;\n\n\tconst separatorTsx = `'use client';\n\nimport * as SeparatorPrimitive from '@radix-ui/react-separator';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Separator = React.forwardRef<\n React.ElementRef<typeof SeparatorPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(\n (\n { className, orientation = 'horizontal', decorative = true, ...props },\n ref,\n ) => (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative={decorative}\n orientation={orientation}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className,\n )}\n {...props}\n />\n ),\n);\nSeparator.displayName = SeparatorPrimitive.Root.displayName;\n\nexport { Separator };\n`;\n\n\tconst tabsTsx = `'use client';\n\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Tabs = TabsPrimitive.Root;\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n 'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n className,\n )}\n {...props}\n />\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n`;\n\n\tconst tooltipTsx = `'use client';\n\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n`;\n\n\tconst dialogTsx = `'use client';\n\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { X } from 'lucide-react';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Dialog = DialogPrimitive.Root;\n\nconst DialogTrigger = DialogPrimitive.Trigger;\n\nconst DialogPortal = DialogPrimitive.Portal;\n\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n className,\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',\n className,\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n 'flex flex-col space-y-1.5 text-center sm:text-left',\n className,\n )}\n {...props}\n />\n);\nDialogHeader.displayName = 'DialogHeader';\n\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n className,\n )}\n {...props}\n />\n);\nDialogFooter.displayName = 'DialogFooter';\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-lg font-semibold leading-none tracking-tight',\n className,\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogTrigger,\n DialogClose,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n};\n`;\n\n\tconst components: Record<string, string> = {\n\t\tbutton: buttonTsx,\n\t\tinput: inputTsx,\n\t\tcard: cardTsx,\n\t\tlabel: labelTsx,\n\t\tbadge: badgeTsx,\n\t\tseparator: separatorTsx,\n\t\ttabs: tabsTsx,\n\t\ttooltip: tooltipTsx,\n\t\tdialog: dialogTsx,\n\t};\n\n\treturn [\n\t\t{\n\t\t\tpath: `${appDir}/components.json`,\n\t\t\tcontent: `${JSON.stringify(componentsJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: `${appDir}/src/lib/utils.ts`, content: utilsTs },\n\t\t...Object.entries(components).map(([name, content]) => ({\n\t\t\tpath: `${appDir}/src/components/ui/${name}.tsx`,\n\t\t\tcontent,\n\t\t})),\n\t];\n}\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport {\n\tSHADCN_DEPENDENCIES,\n\tSHADCN_GLOBALS_CSS,\n\tshadcnFiles,\n} from './shadcn.js';\n\n/**\n * Generate Next.js web app files for fullstack template\n */\nexport function generateWebAppFiles(options: TemplateOptions): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\t// package.json for web app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- next dev --turbopack',\n\t\t\tbuild: 'gkm exec -- next build',\n\t\t\tstart: 'next start',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t...SHADCN_DEPENDENCIES,\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\tnext: DEPENDENCY_VERSIONS['next'],\n\t\t\treact: DEPENDENCY_VERSIONS['react'],\n\t\t\t'react-dom': DEPENDENCY_VERSIONS['react-dom'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/postcss': DEPENDENCY_VERSIONS['@tailwindcss/postcss'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/react': DEPENDENCY_VERSIONS['@types/react'],\n\t\t\t'@types/react-dom': DEPENDENCY_VERSIONS['@types/react-dom'],\n\t\t\ttailwindcss: DEPENDENCY_VERSIONS['tailwindcss'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// next.config.ts\n\tconst nextConfig = `import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n output: 'standalone',\n reactStrictMode: true,\n transpilePackages: ['${modelsPackage}'],\n};\n\nexport default nextConfig;\n`;\n\n\t// postcss.config.mjs for Tailwind v4\n\tconst postcssConfig = `export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n};\n`;\n\n\t// tsconfig.json for Next.js\n\t// Note: Next.js handles compilation, so noEmit: true\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\tplugins: [\n\t\t\t\t{\n\t\t\t\t\tname: 'next',\n\t\t\t\t},\n\t\t\t],\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t\t[`${modelsPackage}`]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],\n\t\texclude: ['node_modules'],\n\t\t// No project `references`: the `paths` above already point at the\n\t\t// sources, and a reference to a project that is not `composite` makes\n\t\t// `tsc --noEmit` — the app's `typecheck` — an error.\n\t};\n\n\t// Query client singleton for browser, fresh instance for server\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n if (typeof window === 'undefined') {\n // Server: always make a new query client\n return makeQueryClient();\n }\n // Browser: reuse existing query client\n if (!browserQueryClient) browserQueryClient = makeQueryClient();\n return browserQueryClient;\n}\n`;\n\n\t// Client config - NEXT_PUBLIC_* vars (available in browser)\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - only NEXT_PUBLIC_* vars (available in browser)\n// These values are inlined at build time by Next.js\nconst envParser = new EnvironmentParser({\n NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,\n NEXT_PUBLIC_AUTH_URL: process.env.NEXT_PUBLIC_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n .create((get) => ({\n apiUrl: get('NEXT_PUBLIC_API_URL').string(),\n authUrl: get('NEXT_PUBLIC_AUTH_URL').string(),\n }))\n .parse();\n`;\n\n\t// Server config - server-only vars (not available in browser)\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser)\n// Access these only in Server Components, Route Handlers, or Server Actions\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n .create((get) => ({\n // Add server-only secrets here\n // Example: stripeSecretKey: get('STRIPE_SECRET_KEY').string(),\n }))\n .parse();\n`;\n\n\t// Auth client for better-auth\n\tconst authClientTs = `import { createAuthClient } from 'better-auth/react';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n baseURL: clientConfig.authUrl,\n plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\t// Providers using shared QueryClient\n\tconst providersTsx = `'use client';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n const queryClient = getQueryClient();\n\n return (\n <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n );\n}\n`;\n\n\t// API client setup - imports directly from the API package export\n\tconst apiIndexTs = `import { createApi } from '@${options.name}/client/api';\nimport { getQueryClient } from '~/lib/query-client.ts';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const api = createApi({\n baseURL: clientConfig.apiUrl,\n queryClient: getQueryClient(),\n});\n`;\n\n\t// App layout\n\tconst layoutTsx = `import type { Metadata } from 'next';\nimport { Providers } from './providers.tsx';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n title: '${options.name}',\n description: 'Created with gkm init',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"en\">\n <body>\n <Providers>{children}</Providers>\n </body>\n </html>\n );\n}\n`;\n\n\t// Home page with API example using the app's own shadcn components\n\tconst pageTsx = `import { api } from '~/api/index.ts';\nimport { Button } from '~/components/ui/button.tsx';\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '~/components/ui/card.tsx';\n\nexport default async function Home() {\n // Type-safe API call using the generated client\n const health = await api('GET /health').catch(() => null);\n\n return (\n <main className=\"min-h-screen bg-background p-8\">\n <div className=\"mx-auto max-w-4xl space-y-8\">\n <div className=\"space-y-2\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Welcome to ${options.name}</h1>\n <p className=\"text-muted-foreground\">Your fullstack application is ready.</p>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>API Status</CardTitle>\n <CardDescription>Connection to your backend API</CardDescription>\n </CardHeader>\n <CardContent>\n {health ? (\n <pre className=\"rounded-lg bg-muted p-4 text-sm\">\n {JSON.stringify(health, null, 2)}\n </pre>\n ) : (\n <p className=\"text-destructive\">Unable to connect to API</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Next Steps</CardTitle>\n <CardDescription>Get started with your project</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <ul className=\"list-inside list-disc space-y-2 text-muted-foreground\">\n <li>Run <code className=\"rounded bg-muted px-1\">gkm openapi</code> to generate typed API client</li>\n <li>Edit <code className=\"rounded bg-muted px-1\">apps/web/src/app/page.tsx</code> to customize this page</li>\n <li>Add API routes in <code className=\"rounded bg-muted px-1\">apps/api/src/endpoints/</code></li>\n <li>Add UI components with <code className=\"rounded bg-muted px-1\">npx shadcn@latest add</code> in apps/web</li>\n </ul>\n <div className=\"flex gap-4\">\n <Button>Get Started</Button>\n <Button variant=\"outline\">Documentation</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n </main>\n );\n}\n`;\n\n\t// .gitignore for Next.js\n\tconst gitignore = `.next/\nnode_modules/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/next.config.ts',\n\t\t\tcontent: nextConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/postcss.config.mjs',\n\t\t\tcontent: postcssConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/globals.css',\n\t\t\tcontent: SHADCN_GLOBALS_CSS,\n\t\t},\n\t\t...shadcnFiles('apps/web', 'src/app/globals.css', { rsc: true }),\n\t\t{\n\t\t\tpath: 'apps/web/src/app/layout.tsx',\n\t\t\tcontent: layoutTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/providers.tsx',\n\t\t\tcontent: providersTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/page.tsx',\n\t\t\tcontent: pageTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/client.ts',\n\t\t\tcontent: clientConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/server.ts',\n\t\t\tcontent: serverConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/query-client.ts',\n\t\t\tcontent: queryClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/auth-client.ts',\n\t\t\tcontent: authClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/api/index.ts',\n\t\t\tcontent: apiIndexTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport {\n\tSHADCN_DEPENDENCIES,\n\tSHADCN_GLOBALS_CSS,\n\tshadcnFiles,\n} from './shadcn.js';\n\n/**\n * Generate TanStack Start web app files for the fullstack template.\n *\n * Mirrors the Next.js scaffold (apps/web) but on Vite + TanStack Start +\n * TanStack Router with the `VITE_` env-var convention.\n */\nexport function generateTanStackWebFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- vite dev',\n\t\t\tbuild: 'gkm exec -- vite build',\n\t\t\tstart: 'node .output/server/index.mjs',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t...SHADCN_DEPENDENCIES,\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'@tanstack/react-router': DEPENDENCY_VERSIONS['@tanstack/react-router'],\n\t\t\t'@tanstack/react-start': DEPENDENCY_VERSIONS['@tanstack/react-start'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\treact: DEPENDENCY_VERSIONS['react'],\n\t\t\t'react-dom': DEPENDENCY_VERSIONS['react-dom'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/vite': DEPENDENCY_VERSIONS['@tailwindcss/vite'],\n\t\t\t'@tanstack/router-plugin': DEPENDENCY_VERSIONS['@tanstack/router-plugin'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/react': DEPENDENCY_VERSIONS['@types/react'],\n\t\t\t'@types/react-dom': DEPENDENCY_VERSIONS['@types/react-dom'],\n\t\t\t'@vitejs/plugin-react': TOOLCHAIN_VERSIONS['@vitejs/plugin-react'],\n\t\t\ttailwindcss: DEPENDENCY_VERSIONS['tailwindcss'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t\tvite: TOOLCHAIN_VERSIONS['vite'],\n\t\t},\n\t};\n\n\tconst viteConfig = `import { Credentials } from '@geekmidas/envkit/credentials';\nimport tailwindcss from '@tailwindcss/vite';\nimport { tanstackStart } from '@tanstack/react-start/plugin/vite';\nimport viteReact from '@vitejs/plugin-react';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n // Vite resolves tsconfig \\`paths\\` itself; no plugin needed.\n resolve: { tsconfigPaths: true },\n server: {\n port: Number(Credentials.PORT ?? 3001),\n },\n // VITE_* vars are inlined automatically; no manual loadEnv needed.\n envPrefix: 'VITE_',\n plugins: [\n tailwindcss(),\n tanstackStart(),\n viteReact(),\n ],\n});\n`;\n\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\ttypes: ['vite/client'],\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['**/*.ts', '**/*.tsx', 'src/routeTree.gen.ts'],\n\t\texclude: ['node_modules', '.output', '.vinxi', 'dist'],\n\t};\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n if (typeof window === 'undefined') {\n return makeQueryClient();\n }\n if (!browserQueryClient) browserQueryClient = makeQueryClient();\n return browserQueryClient;\n}\n`;\n\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - VITE_* vars are inlined at build time.\nconst envParser = new EnvironmentParser({\n VITE_API_URL: import.meta.env.VITE_API_URL,\n VITE_AUTH_URL: import.meta.env.VITE_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n .create((get) => ({\n apiUrl: get('VITE_API_URL').string(),\n authUrl: get('VITE_AUTH_URL').string(),\n }))\n .parse();\n`;\n\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser).\n// Access these only in TanStack Start server functions / server routes.\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n .create((_get) => ({\n // Add server-only secrets here\n // Example: stripeSecretKey: _get('STRIPE_SECRET_KEY').string(),\n }))\n .parse();\n`;\n\n\tconst authClientTs = `import { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n baseURL: clientConfig.authUrl,\n plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\tconst apiIndexTs = `import { createApi } from '@${options.name}/client/api';\nimport { clientConfig } from '~/config/client.ts';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n return createApi({\n baseURL: clientConfig.apiUrl,\n queryClient: getQueryClient(),\n headers: options?.headers,\n onRequest: (config) => ({ ...config, credentials: 'include' }),\n });\n}\n\nexport const api = createAppApi();\n`;\n\n\tconst routerTs = `import { createRouter } from '@tanstack/react-router';\nimport { routeTree } from './routeTree.gen.ts';\n\nexport function getRouter() {\n return createRouter({\n routeTree,\n scrollRestoration: true,\n defaultPreload: 'intent',\n });\n}\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: ReturnType<typeof getRouter>;\n }\n}\n`;\n\n\t// Placeholder routeTree.gen — TanStack's plugin regenerates this on dev.\n\tconst routeTreeGen = `// This file is auto-generated by @tanstack/router-plugin.\n// It will be overwritten on the next \\`vite dev\\` run.\nimport { rootRouteWithContext } from '@tanstack/react-router';\n\nexport const routeTree = rootRouteWithContext()({\n // Routes are populated by the plugin from src/routes/**.tsx\n} as never);\n`;\n\n\tconst rootRouteTsx = `/// <reference types=\"vite/client\" />\nimport '~/styles/globals.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport {\n HeadContent,\n Outlet,\n Scripts,\n createRootRoute,\n} from '@tanstack/react-router';\nimport type { ReactNode } from 'react';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport const Route = createRootRoute({\n head: () => ({\n meta: [\n { charSet: 'utf-8' },\n { name: 'viewport', content: 'width=device-width, initial-scale=1' },\n { title: '${options.name}' },\n ],\n }),\n component: RootComponent,\n});\n\nfunction RootComponent() {\n const queryClient = getQueryClient();\n return (\n <RootDocument>\n <QueryClientProvider client={queryClient}>\n <Outlet />\n </QueryClientProvider>\n </RootDocument>\n );\n}\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n return (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n {children}\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n\n\tconst indexRouteTsx = `import { createFileRoute } from '@tanstack/react-router';\nimport { api } from '~/api/index.ts';\n\nexport const Route = createFileRoute('/')({\n component: HomeComponent,\n});\n\nfunction HomeComponent() {\n const { data: health } = api.useQuery('GET /health', {});\n\n return (\n <main className=\"min-h-screen bg-background p-8\">\n <div className=\"mx-auto max-w-4xl space-y-8\">\n <div className=\"space-y-2\">\n <h1 className=\"text-4xl font-bold tracking-tight\">\n Welcome to ${options.name}\n </h1>\n <p className=\"text-muted-foreground\">\n Your TanStack Start app is ready.\n </p>\n </div>\n\n <section className=\"rounded-lg border p-6\">\n <h2 className=\"text-xl font-semibold\">API Status</h2>\n {health ? (\n <pre className=\"mt-4 rounded bg-muted p-4 text-sm\">\n {JSON.stringify(health, null, 2)}\n </pre>\n ) : (\n <p className=\"mt-2 text-muted-foreground\">Connecting…</p>\n )}\n </section>\n </div>\n </main>\n );\n}\n`;\n\n\tconst globalsCss = `${SHADCN_GLOBALS_CSS}\n@source \"../..\";\n`;\n\n\tconst gitignore = `.output/\n.vinxi/\nnode_modules/\n.env.local\n*.log\nsrc/routeTree.gen.ts\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/vite.config.ts', content: viteConfig },\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/src/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/web/src/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/web/src/config/client.ts', content: clientConfigTs },\n\t\t{ path: 'apps/web/src/config/server.ts', content: serverConfigTs },\n\t\t{ path: 'apps/web/src/api/index.ts', content: apiIndexTs },\n\t\t{ path: 'apps/web/src/router.tsx', content: routerTs },\n\t\t{ path: 'apps/web/src/routeTree.gen.ts', content: routeTreeGen },\n\t\t{ path: 'apps/web/src/routes/__root.tsx', content: rootRouteTsx },\n\t\t{ path: 'apps/web/src/routes/index.tsx', content: indexRouteTsx },\n\t\t{ path: 'apps/web/src/styles/globals.css', content: globalsCss },\n\t\t...shadcnFiles('apps/web', 'src/styles/globals.css', { rsc: false }),\n\t\t{ path: 'apps/web/.gitignore', content: gitignore },\n\t];\n}\n","import {\n\tcacheFor,\n\tdatabaseFiles,\n\tdatabaseFor,\n\temailFor,\n\tstorageFor,\n} from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const apiTemplate: TemplateConfig = {\n\tname: 'api',\n\tdescription: 'Full API with auth, database, services',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@geekmidas/services': GEEKMIDAS_VERSIONS['@geekmidas/services'],\n\t\t'@geekmidas/errors': GEEKMIDAS_VERSIONS['@geekmidas/errors'],\n\t\t'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure, monorepo, name } = options;\n\t\tconst { cache, uploads, mail: sendsMail } = options.constructs;\n\n\t\t// The ids and env keys the scaffolded constructs own. Derived, so the\n\t\t// files below and the runtime that discovers them cannot disagree.\n\t\tconst bucket = storageFor();\n\t\tconst kv = cacheFor();\n\t\tconst db = databaseFor();\n\t\tconst mail = emailFor();\n\n\t\t// Every layout's tsconfig maps `~/*` to `src/*`, so a generated file\n\t\t// imports through it wherever it sits. A single app wrote `./router.ts`\n\t\t// from `src/endpoints/…`, which named a file that is not there.\n\t\tconst src = (path: string) => `~/${path}`;\n\n\t\t// Whether this app declares its infrastructure.\n\t\t//\n\t\t// Single-app projects do: the config gets a `constructs` glob, reconcile\n\t\t// derives their containers, and the handler reaches them by edge. The\n\t\t// fullstack workspace does not yet — its auth app's database role is\n\t\t// created by `docker/postgres/init.sh` and its URL comes from a\n\t\t// per-app secret, neither of which reconcile knows about, so declaring\n\t\t// only the API's half would leave auth pointing at a container that is\n\t\t// no longer the one running.\n\t\t// In a workspace the constructs live at its root — `generateRootConstructs`\n\t\t// writes them — so the app declares none of its own and imports them\n\t\t// through the `@<name>/constructs/*` alias instead. A single-app project\n\t\t// has no root above it, so they stay in `src/constructs/`.\n\t\tconst declares = !monorepo;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Models package import path for monorepo\n\t\tconst modelsImport = monorepo ? `@${name}/models` : null;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based': {\n\t\t\t\t\tconst parts = file.split('/');\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t\t\t}\n\t\t\t\t\treturn `src/${parts[0]}/routes/${parts.slice(1).join('/')}`;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\t/**\n\t\t * Where a file at the app's `src/` root reaches a construct.\n\t\t *\n\t\t * A workspace keeps them at its own root, so the app goes through the\n\t\t * `@<name>/constructs/*` alias rather than climbing out with `../../`.\n\t\t */\n\t\tconst constructsImport = (file: string) =>\n\t\t\tmonorepo ? `@${name}/constructs/${file}.ts` : `./constructs/${file}.ts`;\n\n\t\tconst apiImport = monorepo\n\t\t\t? `@${name}/constructs/api.ts`\n\t\t\t: routesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t//\n\t\t\t// A workspace declares it at its root instead, beside the site and the\n\t\t\t// auth server that depend on it.\n\t\t\t...(declares\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: monorepo\n\t\t\t\t\t? `import { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const healthEndpoint = router\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const healthEndpoint = router\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n\t\t\t},\n\n\t\t\t// users endpoints\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/list.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { ListUsersResponseSchema } from '${modelsImport}/user';\nimport { router } from '${src('router.ts')}';\n\nexport const listUsersEndpoint = router\n .get('/users')\n .output(ListUsersResponseSchema)\n${\n\toptions.constructs.database\n\t\t? ` // \\`db\\` is here because the router named the database construct.\n .handle(async ({ db }) => ({\n users: await db.selectFrom('users').select(['id', 'name']).execute(),\n }));\n`\n\t\t: ` .handle(async () => ({\n users: [\n { id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },\n { id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },\n ],\n }));\n`\n}`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '${src('router.ts')}';\n\nconst UserSchema = z.object({\n id: z.string(),\n name: z.string(),\n});\n\nexport const listUsersEndpoint = router\n .get('/users')\n .output(z.object({\n users: z.array(UserSchema),\n }))\n${\n\toptions.constructs.database\n\t\t? ` // \\`db\\` is here because the router named the database construct.\n .handle(async ({ db }) => ({\n users: await db.selectFrom('users').select(['id', 'name']).execute(),\n }));\n`\n\t\t: ` .handle(async () => ({\n users: [\n { id: '1', name: 'Alice' },\n { id: '2', name: 'Bob' },\n ],\n }));\n`\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/get.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { IdParamsSchema } from '${modelsImport}/common';\nimport { UserResponseSchema } from '${modelsImport}/user';\nimport { router } from '${src('router.ts')}';\n\nexport const getUserEndpoint = router\n .get('/users/:id')\n .params(IdParamsSchema)\n .output(UserResponseSchema)\n .handle(async ({ params }) => ({\n id: params.id,\n name: 'Alice',\n email: 'alice@example.com',\n }));\n`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '${src('router.ts')}';\n\nexport const getUserEndpoint = router\n .get('/users/:id')\n .params(z.object({ id: z.string() }))\n .output(z.object({\n id: z.string(),\n name: z.string(),\n email: z.email(),\n }))\n .handle(async ({ params }) => ({\n id: params.id,\n name: 'Alice',\n email: 'alice@example.com',\n }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The monorepo router: the API names the auth construct (`.auth(auth)` at\n\t\t// the root), so the session comes from it rather than a service that\n\t\t// fetches the auth server by hand.\n\t\tif (options.monorepo) {\n\t\t\t// Add router with session\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/router.ts',\n\t\t\t\tcontent: `import { UnauthorizedError } from '@geekmidas/errors';\nimport { api } from '${constructsImport('api')}';${\n\t\t\t\t\toptions.constructs.database\n\t\t\t\t\t\t? `\nimport { database } from '${constructsImport('database')}';`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\n\n/**\n * The shared endpoint factory — no session required.\n *${\n\t\toptions.constructs.database\n\t\t\t? `\n * Naming the database construct is what puts \\`db\\` in every handler built from\n * this router. Depend on other constructs per endpoint with \\`.dependsOn([…])\\`.`\n\t\t\t: `\n * Depend on constructs per endpoint with \\`.dependsOn([…])\\`.`\n }\n */\nexport const router = api${options.constructs.database ? '.database(database)' : ''};\n\n/**\n * Requires an active session — throws when there is none.\n *\n * \\`auth\\` is the construct named in \\`.auth()\\` on the API, bound to this\n * request: it asks the auth server whose cookie this is. Handlers built from\n * this router get whatever this returns as \\`session\\`.\n */\nexport const sessionRouter = router.session(async ({ auth }) => {\n const session = await auth.getSession();\n\n if (!session) {\n throw new UnauthorizedError('No active session');\n }\n\n return session;\n});\n`,\n\t\t\t});\n\n\t\t\t// Add protected endpoint example\n\t\t\tfiles.push({\n\t\t\t\tpath: getRoutePath('profile.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { sessionRouter } from '~/router.ts';\n\nexport const profileEndpoint = sessionRouter\n .get('/profile')\n .output(z.object({\n id: z.string(),\n email: z.string(),\n name: z.string(),\n }))\n .handle(async ({ session }) => session.user);\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The non-monorepo router. The monorepo one is written above, with the\n\t\t// session extractor its auth app needs.\n\t\tif (!monorepo) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/router.ts',\n\t\t\t\tcontent: `import { api } from '${constructsImport('api')}';${\n\t\t\t\t\toptions.constructs.database\n\t\t\t\t\t\t? `\nimport { database } from '${constructsImport('database')}';`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\n\n/**\n * The shared endpoint factory.\n *${\n\t\toptions.constructs.database\n\t\t\t? `\n * Naming the database construct is what puts \\`db\\` in every handler built from\n * this router. Depend on other constructs per endpoint with \\`.dependsOn([…])\\`.`\n\t\t\t: `\n * Depend on constructs per endpoint with \\`.dependsOn([…])\\`.`\n }\n */\nexport const router = api${options.constructs.database ? '.database(database)' : ''};\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The database — a construct, not a hand-written service. A workspace\n\t\t// declares it, and keeps its migrations, at its root.\n\t\tif (options.constructs.database && declares) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Object storage — MinIO locally, S3 deployed, one declaration for both.\n\t\tif (uploads && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/storage.ts',\n\t\t\t\tcontent: `import { ObjectStorage } from '@geekmidas/constructs/object-storage';\n\n/**\n * A bucket, declared once.\n *\n * Reach it from an endpoint with \\`.dependsOn([uploads])\\`, which is what makes\n * \\`services.${bucket.service}\\` exist and type — and what tells the deploy\n * target to grant that handler S3 access, and nothing else.\n */\nexport const uploads = new ObjectStorage('${bucket.id}');\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Mail. Mailpit locally, SES/Resend/SMTP deployed — one client either\n\t\t// way, because every backend speaks SMTP.\n\t\tif (sendsMail && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/email.ts',\n\t\t\t\tcontent: `import { Email } from '@geekmidas/constructs/email';\n\n/**\n * Outbound mail, declared once.\n *\n * Add React templates to \\`templates\\` and \\`sendTemplate\\` becomes typed\n * against them. Reach it with \\`.dependsOn([email])\\` for\n * \\`services.${mail.service}\\`. Who delivers it is whichever provider the\n * stage's \\`${mail.urlKey}\\` points at — every one of them speaks SMTP.\n */\nexport const email = new Email('${mail.id}', { templates: {} });\n`,\n\t\t\t});\n\t\t}\n\n\t\t// A cache. Where it lives when deployed follows from the deploy target;\n\t\t// the application code is the same either way.\n\t\tif (cache && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/cache.ts',\n\t\t\t\tcontent: `import { Cache } from '@geekmidas/constructs/cache';\n\n/**\n * A cache, declared once.\n *\n * Reach it with \\`.dependsOn([cache])\\` for \\`services.${kv.service}\\`. This\n * form says the app caches and leaves *where* to the deployment: Upstash on\n * AWS, a table in the database on a server — the same code caches into\n * either.\n *\n * To say it caches in a particular database instead, declare it from that\n * database — \\`database.cache()\\` — and entries become a table in it, in its\n * schema and reached by its role, whatever the target.\n */\nexport const cache = new Cache('${kv.id}');\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles, databaseFor } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const minimalTemplate: TemplateConfig = {\n\tname: 'minimal',\n\tdescription: 'Basic health endpoint',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure, name } = options;\n\n\t\t// The id and env keys the scaffolded database owns.\n\t\tconst db = databaseFor();\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\tconst apiImport =\n\t\t\troutesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { api } from '${apiImport}';\n\nexport const healthEndpoint = api\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The database — a construct, not a hand-written service.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const serverlessTemplate: TemplateConfig = {\n\tname: 'serverless',\n\tdescription: 'AWS Lambda handlers',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/cloud': GEEKMIDAS_VERSIONS['@geekmidas/cloud'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/aws-lambda': DEPENDENCY_VERSIONS['@types/aws-lambda'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build --provider aws',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\tconst apiImport =\n\t\t\troutesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { api } from '${apiImport}';\n\nexport const healthEndpoint = api\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n region: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n region: process.env.AWS_REGION || 'local',\n }));\n`,\n\t\t\t},\n\n\t\t\t// src/functions/hello.ts\n\t\t\t{\n\t\t\t\tpath: 'src/functions/hello.ts',\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { worker } from '~/constructs/worker.ts';\n\nexport const helloFunction = worker\n .input(z.object({ name: z.string() }))\n .output(z.object({ message: z.string() }))\n .handle(async ({ input }) => ({\n message: \\`Hello, \\${input.name}!\\`,\n }));\n`,\n\t\t\t},\n\t\t\t// The process the functions run in. A function says which one runs it\n\t\t\t// the same way an endpoint says which surface serves it.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/worker.ts',\n\t\t\t\tcontent: `import { Worker } from '@geekmidas/constructs/worker';\nimport { logger } from '../config/logger.ts';\n\nexport const worker = new Worker('Jobs', { logger });\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The database, when this project has one. A `pgboss` events backend\n\t\t// implies one, which is why a worker gets here without asking for it.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\n// Note: For production Lambda, consider using a persistent storage\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 50 }),\n enabled: process.env.STAGE === '${options.stages.local}',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\n/**\n * A project that is background work and nothing else.\n *\n * It used to scaffold a `RestApi` with no endpoints on it — an HTTP surface\n * declared by a project whose premise is that nothing calls it over HTTP —\n * because a surface was the only construct that made an app exist and the only\n * way to get a logger into the generated runtime. `Worker` is the construct\n * that was missing: it takes no authorizer, publishes no address, and hands out\n * factories already carrying its logger.\n *\n * It scaffolds a cron when the project has a database, and not otherwise. A\n * server fires its own crons, and the schedule lives in Postgres so that\n * running more than one replica still fires each job once — so a worker names\n * the database it keeps schedules in. Without one there is nowhere to keep\n * them, and an example that could not run is worse than none.\n */\nexport const workerTemplate: TemplateConfig = {\n\tname: 'worker',\n\tdescription: 'Background job processing',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, name } = options;\n\t\tconst { database } = options.constructs;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The process this project *is*: one with no port.\n\t\t\t//\n\t\t\t// Everything built from it carries this logger, so a subscriber file\n\t\t\t// opens with what it subscribes to rather than with an import of a\n\t\t\t// logger it has to know the path to.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/worker.ts',\n\t\t\t\tcontent: `import { Worker } from '@geekmidas/constructs/worker';\nimport { logger } from '../config/logger.ts';${database ? \"\\nimport { database } from './database.ts';\" : ''}\n\nexport const worker = new Worker('Jobs', { logger })${database ? '.database(database)' : ''};\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// The topic this worker subscribes to. Declaring it is what puts a\n\t\t\t// broker in the plan — no service names one, and nothing reads a\n\t\t\t// broker URL by hand.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/topics.ts',\n\t\t\t\tcontent: `import { Topic } from '@geekmidas/constructs/topic';\nimport { z } from 'zod';\n\n/**\n * The \\`users\\` topic: pub/sub fan-out, any number of subscribers.\n *\n * The event map is the contract. It types every \\`.event(users, …)\\` that\n * publishes to it and every subscriber that binds with \\`worker.topic(users)\\`,\n * so an event cannot be published in one shape and read in another.\n */\nexport const users = new Topic('users', {\n events: {\n 'user.created': z.object({ userId: z.string(), email: z.email() }),\n 'user.updated': z.object({\n userId: z.string(),\n changes: z.record(z.string(), z.unknown()),\n }),\n },\n});\n`,\n\t\t\t},\n\n\t\t\t// src/subscribers/user-events.ts\n\t\t\t{\n\t\t\t\tpath: 'src/subscribers/user-events.ts',\n\t\t\t\tcontent: `import { users } from '~/constructs/topics.ts';\nimport { worker } from '~/constructs/worker.ts';\n\n// Bound to the topic, not handed its publisher: a subscriber consumes.\nexport const userEventsSubscriber = worker\n .topic(users)\n .subscribe(['user.created', 'user.updated'])\n .handle(async ({ events, logger }) => {\n // A batch, not a single event. Both transports deliver in batches, so\n // handling them one at a time is a round trip per event for no reason.\n logger.info({ count: events.length }, 'Processing user events');\n\n for (const event of events) {\n switch (event.type) {\n case 'user.created':\n logger.info({ userId: event.payload.userId }, 'New user created');\n break;\n case 'user.updated':\n logger.info({ userId: event.payload.userId }, 'User updated');\n break;\n }\n }\n });\n`,\n\t\t\t},\n\t\t];\n\n\t\t// A cron, now that a server target runs one. The schedule lives in the\n\t\t// database the worker named; on AWS it becomes an EventBridge rule and\n\t\t// none of that is consulted.\n\t\tif (database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/crons/cleanup.ts',\n\t\t\t\tcontent: `import { worker } from '~/constructs/worker.ts';\n\nexport const cleanup = worker\n .cron('rate(1 day)')\n .handle(async ({ logger }) => {\n logger.info('Running cleanup');\n\n // Delete old sessions, clear temp files, whatever falls out of date.\n\n logger.info('Cleanup complete');\n });\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The database, when this project has one. A `pgboss` events backend\n\t\t// implies one, which is why a worker gets here without asking for it.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import type { StagesConfig } from '../../workspace/types.js';\nimport { apiTemplate } from './api.js';\nimport { minimalTemplate } from './minimal.js';\nimport { serverlessTemplate } from './serverless.js';\nimport { workerTemplate } from './worker.js';\n\n/**\n * OpenAPI output path (fixed, not configurable)\n */\n\n/**\n * Endpoints output path (generated by gkm dev/build)\n */\n\n/**\n * Logger implementation type\n */\nexport type LoggerType = 'pino' | 'console';\n\n/**\n * Routes structure pattern\n */\nexport type RoutesStructure =\n\t| 'centralized-endpoints'\n\t| 'centralized-routes'\n\t| 'domain-based';\n\n/**\n * Package manager type\n */\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\n/**\n * Deploy target type\n */\nexport type DeployTarget = 'dokploy' | 'sst' | 'none';\n\n/**\n * The constructs a scaffold declares.\n *\n * Constructs, not containers: `Database` is a `KyselyDatabase`, `Uploads` an\n * `ObjectStorage`. Which container runs each locally, and which backend serves\n * it deployed, follow from the declaration and the deploy target — nothing\n * here names a Postgres or a Redis.\n */\nexport interface ScaffoldedConstructs {\n\tdatabase: boolean;\n\tcache: boolean;\n\tuploads: boolean;\n\tmail: boolean;\n}\n\n/**\n * Frontend framework for the fullstack template's client app.\n * Limited to the three with first-class scaffolds; the wider\n * `FrontendFramework` type also covers `vite` and `remix` which\n * users can configure manually after init.\n */\nexport type FullstackFrontendFramework = 'nextjs' | 'tanstack-start' | 'expo';\n\n/**\n * Options collected from user prompts\n */\nexport interface TemplateOptions {\n\tname: string;\n\ttemplate: TemplateName;\n\ttelescope: boolean;\n\tloggerType: LoggerType;\n\troutesStructure: RoutesStructure;\n\tmonorepo: boolean;\n\t/** Path for the API app in monorepo (e.g., 'apps/api') */\n\tapiPath: string;\n\t/** Selected package manager */\n\tpackageManager: PackageManager;\n\t/** Deploy target */\n\tdeployTarget: DeployTarget;\n\t/** The AWS region, when `deployTarget` is `sst` */\n\tregion?: string;\n\t/** The project's stages, written to gkm.config.ts and read from it */\n\tstages: StagesConfig;\n\t/** The constructs this scaffold declares */\n\tconstructs: ScaffoldedConstructs;\n\t/** Frontend framework (fullstack template only) */\n\tfrontendFramework?: FullstackFrontendFramework;\n}\n\n/**\n * A file to be generated\n */\nexport interface GeneratedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/**\n * Template configuration\n */\nexport interface TemplateConfig {\n\tname: TemplateName;\n\tdescription: string;\n\tdependencies: Record<string, string>;\n\tdevDependencies: Record<string, string>;\n\tscripts: Record<string, string>;\n\tfiles: (options: TemplateOptions) => GeneratedFile[];\n}\n\nexport type TemplateName =\n\t| 'minimal'\n\t| 'api'\n\t| 'serverless'\n\t| 'worker'\n\t| 'fullstack';\n\n/**\n * All available templates\n */\nexport const templates: Record<\n\tExclude<TemplateName, 'fullstack'>,\n\tTemplateConfig\n> = {\n\tminimal: minimalTemplate,\n\tapi: apiTemplate,\n\tserverless: serverlessTemplate,\n\tworker: workerTemplate,\n};\n\n/**\n * Template choices for prompts (Story 1.11 simplified to api + fullstack)\n */\nexport const templateChoices = [\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Single backend API with endpoints',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n];\n\n/**\n * All template choices (includes advanced options)\n */\nexport const allTemplateChoices = [\n\t{\n\t\ttitle: 'Minimal',\n\t\tvalue: 'minimal' as TemplateName,\n\t\tdescription: 'Basic health endpoint',\n\t},\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Full API with auth, database, services',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n\t{\n\t\ttitle: 'Serverless',\n\t\tvalue: 'serverless' as TemplateName,\n\t\tdescription: 'AWS Lambda handlers',\n\t},\n\t{\n\t\ttitle: 'Worker',\n\t\tvalue: 'worker' as TemplateName,\n\t\tdescription: 'Background job processing',\n\t},\n];\n\n/**\n * Frontend framework choices for the fullstack template prompt.\n */\nexport const frontendFrameworkChoices = [\n\t{\n\t\ttitle: 'Next.js',\n\t\tvalue: 'nextjs' as FullstackFrontendFramework,\n\t\tdescription: 'React server components, app router (default)',\n\t},\n\t{\n\t\ttitle: 'TanStack Start',\n\t\tvalue: 'tanstack-start' as FullstackFrontendFramework,\n\t\tdescription: 'File-based router on Vite + Nitro',\n\t},\n\t{\n\t\ttitle: 'Expo',\n\t\tvalue: 'expo' as FullstackFrontendFramework,\n\t\tdescription: 'React Native mobile app (iOS + Android)',\n\t},\n];\n\n/**\n * Logger type choices for prompts\n */\nexport const loggerTypeChoices = [\n\t{\n\t\ttitle: 'Pino',\n\t\tvalue: 'pino' as LoggerType,\n\t\tdescription: 'Fast JSON logger for production (recommended)',\n\t},\n\t{\n\t\ttitle: 'Console',\n\t\tvalue: 'console' as LoggerType,\n\t\tdescription: 'Simple console logger for development',\n\t},\n];\n\n/**\n * Routes structure choices for prompts\n */\nexport const routesStructureChoices = [\n\t{\n\t\ttitle: 'Centralized (endpoints)',\n\t\tvalue: 'centralized-endpoints' as RoutesStructure,\n\t\tdescription: 'src/endpoints/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Centralized (routes)',\n\t\tvalue: 'centralized-routes' as RoutesStructure,\n\t\tdescription: 'src/routes/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Domain-based',\n\t\tvalue: 'domain-based' as RoutesStructure,\n\t\tdescription: 'src/**/routes/*.ts (e.g., src/users/routes/list.ts)',\n\t},\n];\n\n/**\n * Package manager choices for prompts\n */\nexport const packageManagerChoices = [\n\t{\n\t\ttitle: 'pnpm',\n\t\tvalue: 'pnpm' as PackageManager,\n\t\tdescription: 'Fast, disk space efficient (recommended)',\n\t},\n\t{\n\t\ttitle: 'npm',\n\t\tvalue: 'npm' as PackageManager,\n\t\tdescription: 'Node.js default package manager',\n\t},\n\t{\n\t\ttitle: 'yarn',\n\t\tvalue: 'yarn' as PackageManager,\n\t\tdescription: 'Yarn package manager',\n\t},\n\t{\n\t\ttitle: 'bun',\n\t\tvalue: 'bun' as PackageManager,\n\t\tdescription: 'Fast JavaScript runtime and package manager',\n\t},\n];\n\n/**\n * Deploy target choices for prompts\n */\nexport const deployTargetChoices = [\n\t{\n\t\ttitle: 'Dokploy',\n\t\tvalue: 'dokploy' as DeployTarget,\n\t\tdescription: 'Deploy to Dokploy (Docker-based hosting)',\n\t},\n\t{\n\t\ttitle: 'AWS (SST)',\n\t\tvalue: 'sst' as DeployTarget,\n\t\tdescription: 'Deploy to your AWS account through SST',\n\t},\n\t{\n\t\ttitle: 'Configure later',\n\t\tvalue: 'none' as DeployTarget,\n\t\tdescription: 'Skip deployment setup for now',\n\t},\n];\n\n/**\n * Which constructs to declare.\n *\n * The containers that run them locally and the backends that serve them\n * deployed are derived from these, so the prompt names only what the code\n * will say.\n */\nexport const constructChoices: {\n\ttitle: string;\n\tvalue: keyof ScaffoldedConstructs;\n\tdescription: string;\n}[] = [\n\t{\n\t\ttitle: 'Database',\n\t\tvalue: 'database',\n\t\tdescription: 'KyselyDatabase — Postgres',\n\t},\n\t{\n\t\ttitle: 'Cache',\n\t\tvalue: 'cache',\n\t\tdescription: 'Cache — backed by what the deploy target implies',\n\t},\n\t{\n\t\ttitle: 'Uploads',\n\t\tvalue: 'uploads',\n\t\tdescription: 'ObjectStorage — a bucket',\n\t},\n\t{\n\t\ttitle: 'Mail',\n\t\tvalue: 'mail',\n\t\tdescription: 'Email — outbound mail over SMTP',\n\t},\n];\n\n/**\n * Get a template by name\n */\nexport function getTemplate(name: TemplateName): TemplateConfig | null {\n\tif (name === 'fullstack') {\n\t\t// Fullstack template is handled specially, uses api template as base\n\t\treturn templates.api;\n\t}\n\tconst template = templates[name];\n\tif (!template) {\n\t\tthrow new Error(`Unknown template: ${name}`);\n\t}\n\treturn template;\n}\n\n/**\n * Check if a template is the fullstack monorepo template\n */\nexport function isFullstackTemplate(name: TemplateName): boolean {\n\treturn name === 'fullstack';\n}\n","import { execSync } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport prompts from 'prompts';\nimport { FileSecretsStore } from '../secrets/file.js';\nimport { createStageSecrets } from '../secrets/generator.js';\nimport { getKeyPath, projectKey } from '../secrets/keystore.js';\nimport {\n\tdeployedProblems,\n\tInvalidStages,\n\tstageProblems,\n} from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\nimport { generateAgentFiles } from './generators/agents.js';\nimport { generateAuthAppFiles } from './generators/auth.js';\nimport { generateConfigFiles } from './generators/config.js';\nimport { generateEnvFiles } from './generators/env.js';\nimport { generateGithubFiles } from './generators/github.js';\nimport { generateExpoAppFiles } from './generators/mobile-expo.js';\nimport { generateModelsPackage } from './generators/models.js';\nimport {\n\tgenerateMonorepoFiles,\n\tgenerateRootConstructs,\n} from './generators/monorepo.js';\nimport { generatePackageJson } from './generators/package.js';\nimport { generateSourceFiles } from './generators/source.js';\nimport {\n\tgenerateTestFactoryFiles,\n\tgenerateTestFiles,\n} from './generators/test.js';\nimport { generateWebAppFiles } from './generators/web.js';\nimport { generateTanStackWebFiles } from './generators/web-tanstack.js';\nimport {\n\tconstructChoices,\n\ttype DeployTarget,\n\tdeployTargetChoices,\n\ttype FullstackFrontendFramework,\n\tfrontendFrameworkChoices,\n\tgetTemplate,\n\tisFullstackTemplate,\n\tloggerTypeChoices,\n\ttype PackageManager,\n\tpackageManagerChoices,\n\troutesStructureChoices,\n\ttype TemplateName,\n\ttype TemplateOptions,\n\ttemplateChoices,\n} from './templates/index.js';\nimport {\n\tcheckDirectoryExists,\n\tdetectPackageManager,\n\tgetExecCommand,\n\tgetInstallCommand,\n\tgetRunCommand,\n\tvalidateProjectName,\n} from './utils.js';\n\nexport interface InitOptions {\n\t/** Project name */\n\tname?: string;\n\t/** Template to use */\n\ttemplate?: TemplateName;\n\t/** Skip dependency installation */\n\tskipInstall?: boolean;\n\t/** Use defaults for all prompts */\n\tyes?: boolean;\n\t/** Force monorepo setup (deprecated, use fullstack template) */\n\tmonorepo?: boolean;\n\t/** API app path in monorepo */\n\tapiPath?: string;\n\t/** Package manager to use */\n\tpm?: PackageManager;\n\t/** Where the project deploys: `dokploy`, `sst`, or `none` */\n\tdeploy?: DeployTarget;\n\t/** The AWS region an SST deploy goes to, e.g. `eu-west-1` */\n\tregion?: string;\n\t/** Deployed stage names, comma-separated, e.g. `staging,prod` */\n\tstages?: string;\n\t/** Which deployed stage is production: retained and protected */\n\tprotectedStage?: string;\n\t/** What `gkm dev`, `exec` and `test` run as, e.g. `dev` */\n\tlocalStage?: string;\n}\n\n/** `' staging, prod '` → `['staging', 'prod']`. */\nconst stageList = (value: string): string[] =>\n\tvalue\n\t\t.split(',')\n\t\t.map((name) => name.trim())\n\t\t.filter(Boolean);\n\n/** `eu-west-1`, `us-gov-west-1`, `ap-southeast-2`. */\nconst AWS_REGION = /^[a-z]{2}(-gov)?-[a-z]+-\\d$/;\n\n/**\n * Main init command - scaffolds a new project\n */\nexport async function initCommand(\n\tprojectName?: string,\n\toptions: InitOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst detectedPkgManager = detectPackageManager(cwd);\n\n\tif (\n\t\toptions.deploy &&\n\t\t!deployTargetChoices.some((choice) => choice.value === options.deploy)\n\t) {\n\t\tthrow new UnknownDeployTarget(\n\t\t\toptions.deploy,\n\t\t\tdeployTargetChoices.map((c) => c.value),\n\t\t);\n\t}\n\n\tif (options.region && !AWS_REGION.test(options.region)) {\n\t\tthrow new NotAnAwsRegion(options.region);\n\t}\n\n\t// Flags are checked before anything is asked or written, the same rules\n\t// gkm.config.ts is held to.\n\tif (options.stages || options.localStage || options.protectedStage) {\n\t\tconst deployed = stageList(options.stages ?? '');\n\t\tconst problems = [\n\t\t\t...deployedProblems(deployed),\n\t\t\t...(options.localStage\n\t\t\t\t? stageProblems({ local: options.localStage, deployed })\n\t\t\t\t: []),\n\t\t\t...(options.protectedStage && !deployed.includes(options.protectedStage)\n\t\t\t\t? [`--protected-stage \"${options.protectedStage}\" is not in --stages`]\n\t\t\t\t: []),\n\t\t];\n\t\tif (problems.length) throw new InvalidStages([...new Set(problems)]);\n\t}\n\n\tlet deployedSoFar: string[] = [];\n\n\t// Handle Ctrl+C gracefully\n\tprompts.override({});\n\tconst onCancel = () => {\n\t\tprocess.exit(0);\n\t};\n\n\t// Gather answers via prompts\n\tconst answers = await prompts(\n\t\t[\n\t\t\t{\n\t\t\t\ttype: projectName || options.name ? null : 'text',\n\t\t\t\tname: 'name',\n\t\t\t\tmessage: 'Project name:',\n\t\t\t\tinitial: 'my-app',\n\t\t\t\tvalidate: (value: string) => {\n\t\t\t\t\tconst nameValid = validateProjectName(value);\n\t\t\t\t\tif (nameValid !== true) return nameValid;\n\t\t\t\t\tconst dirValid = checkDirectoryExists(value, cwd);\n\t\t\t\t\tif (dirValid !== true) return dirValid;\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.template || options.yes ? null : 'select',\n\t\t\t\tname: 'template',\n\t\t\t\tmessage: 'Template:',\n\t\t\t\tchoices: templateChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'multiselect',\n\t\t\t\tname: 'constructs',\n\t\t\t\tmessage: 'Constructs to declare (space to select, enter to confirm):',\n\t\t\t\tchoices: constructChoices.map((c) => ({ ...c, selected: true })),\n\t\t\t\thint: '- Space to select. Return to submit',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'packageManager',\n\t\t\t\tmessage: 'Package manager:',\n\t\t\t\tchoices: packageManagerChoices,\n\t\t\t\tinitial: packageManagerChoices.findIndex(\n\t\t\t\t\t(c) => c.value === detectedPkgManager,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes || options.deploy ? null : 'select',\n\t\t\t\tname: 'deployTarget',\n\t\t\t\tmessage: 'Deployment target:',\n\t\t\t\tchoices: deployTargetChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\t!options.yes &&\n\t\t\t\t\t!options.region &&\n\t\t\t\t\t(options.deploy ?? values.deployTarget) === 'sst'\n\t\t\t\t\t\t? 'text'\n\t\t\t\t\t\t: null,\n\t\t\t\tname: 'region',\n\t\t\t\tmessage: 'AWS region (e.g. eu-west-1):',\n\t\t\t\tvalidate: (value: string) =>\n\t\t\t\t\tAWS_REGION.test(value.trim()) || 'An AWS region, like eu-west-1',\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Named by the project, not picked from a list: whatever the team\n\t\t\t\t// already calls its environments.\n\t\t\t\ttype: options.yes || options.stages ? null : 'text',\n\t\t\t\tname: 'deployedStages',\n\t\t\t\tmessage: 'Deployed stages, comma-separated (e.g. staging, prod):',\n\t\t\t\tvalidate: (value: string) => {\n\t\t\t\t\tconst deployed = stageList(value);\n\t\t\t\t\tif (deployed.length === 0) return 'At least one stage';\n\t\t\t\t\treturn deployedProblems(deployed)[0] ?? true;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\toptions.yes || options.protectedStage\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: stageList(options.stages ?? values.deployedStages ?? '').length >\n\t\t\t\t\t\t\t\t1\n\t\t\t\t\t\t\t? 'select'\n\t\t\t\t\t\t\t: null,\n\t\t\t\tname: 'protectedStage',\n\t\t\t\tmessage: 'Which one is production (retained and protected)?',\n\t\t\t\tchoices: (_prev, values) =>\n\t\t\t\t\tstageList(options.stages ?? values.deployedStages ?? '').map(\n\t\t\t\t\t\t(name) => ({ title: name, value: name }),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\t// \\`validate\\` is not handed the earlier answers, and the local stage\n\t\t\t\t// is only valid relative to the deployed ones — so they are read\n\t\t\t\t// here, where \\`type\\` is.\n\t\t\t\ttype: (_prev, values) => {\n\t\t\t\t\tdeployedSoFar = stageList(\n\t\t\t\t\t\toptions.stages ?? values.deployedStages ?? '',\n\t\t\t\t\t);\n\t\t\t\t\treturn options.yes || options.localStage ? null : 'text';\n\t\t\t\t},\n\t\t\t\tname: 'localStage',\n\t\t\t\tmessage: 'Local stage, what gkm dev runs as (e.g. dev):',\n\t\t\t\tvalidate: (value: string) =>\n\t\t\t\t\tstageProblems({ local: value.trim(), deployed: deployedSoFar })[0] ??\n\t\t\t\t\ttrue,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'confirm',\n\t\t\t\tname: 'telescope',\n\t\t\t\tmessage: 'Include Telescope (request, exception and log recording)?',\n\t\t\t\tinitial: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'loggerType',\n\t\t\t\tmessage: 'Logger:',\n\t\t\t\tchoices: loggerTypeChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'routesStructure',\n\t\t\t\tmessage: 'Routes structure:',\n\t\t\t\tchoices: routesStructureChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Only prompt for frontend framework on the fullstack template.\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\t!options.yes &&\n\t\t\t\t\t(options.template === 'fullstack' || values.template === 'fullstack')\n\t\t\t\t\t\t? 'select'\n\t\t\t\t\t\t: null,\n\t\t\t\tname: 'frontendFramework',\n\t\t\t\tmessage: 'Frontend framework:',\n\t\t\t\tchoices: frontendFrameworkChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t],\n\t\t{ onCancel },\n\t);\n\n\t// Build final options\n\tconst name = projectName || options.name || answers.name;\n\tif (!name) {\n\t\tconsole.error('Project name is required');\n\t\tprocess.exit(1);\n\t}\n\n\t// Validate name if provided via argument\n\tif (projectName || options.name) {\n\t\tconst nameToValidate = projectName || options.name!;\n\t\tconst nameValid = validateProjectName(nameToValidate);\n\t\tif (nameValid !== true) {\n\t\t\tconsole.error(nameValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconst dirValid = checkDirectoryExists(nameToValidate, cwd);\n\t\tif (dirValid !== true) {\n\t\t\tconsole.error(dirValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst template: TemplateName = options.template || answers.template || 'api';\n\tconst isFullstack = isFullstackTemplate(template);\n\n\t// For fullstack, force monorepo mode\n\t// For api template, monorepo is optional (via --monorepo flag)\n\tconst monorepo = isFullstack || options.monorepo || false;\n\n\t// Which constructs to declare. Everything that runs them — the containers\n\t// locally, the backends deployed — is derived from these and the target.\n\tconst chosen: string[] = options.yes\n\t\t? constructChoices.map((c) => c.value)\n\t\t: answers.constructs || [];\n\tconst constructs = {\n\t\t// A fullstack workspace always has a database: its auth server's\n\t\t// tenant lives in it.\n\t\tdatabase: isFullstack || chosen.includes('database'),\n\t\tcache: chosen.includes('cache'),\n\t\tuploads: chosen.includes('uploads'),\n\t\tmail: chosen.includes('mail'),\n\t};\n\n\tconst pkgManager: PackageManager = options.pm\n\t\t? options.pm\n\t\t: options.yes\n\t\t\t? 'pnpm'\n\t\t\t: (answers.packageManager ?? detectedPkgManager);\n\n\t// `--yes` picks no host rather than one: a default that scaffolds one\n\t// provider's deploy script commits every unattended project to it.\n\tconst deployTarget: DeployTarget =\n\t\toptions.deploy ?? (options.yes ? 'none' : (answers.deployTarget ?? 'none'));\n\n\tconst frontendFramework: FullstackFrontendFramework | undefined = isFullstack\n\t\t? options.yes\n\t\t\t? 'nextjs'\n\t\t\t: (answers.frontendFramework ?? 'nextjs')\n\t\t: undefined;\n\tconst templateOptions: TemplateOptions = {\n\t\tname,\n\t\ttemplate,\n\t\ttelescope: options.yes ? true : (answers.telescope ?? true),\n\t\tloggerType: options.yes ? 'pino' : (answers.loggerType ?? 'pino'),\n\t\troutesStructure: options.yes\n\t\t\t? 'centralized-endpoints'\n\t\t\t: (answers.routesStructure ?? 'centralized-endpoints'),\n\t\tmonorepo,\n\t\tapiPath: monorepo ? (options.apiPath ?? 'apps/api') : '',\n\t\tpackageManager: pkgManager,\n\t\tdeployTarget,\n\t\tstages: resolveStages(options, answers),\n\t\t...(deployTarget === 'sst'\n\t\t\t? {\n\t\t\t\t\t// Asked when there is someone to ask; \\`--yes\\` takes eu-west-1.\n\t\t\t\t\tregion:\n\t\t\t\t\t\toptions.region ??\n\t\t\t\t\t\t(options.yes ? 'eu-west-1' : answers.region?.trim()),\n\t\t\t\t}\n\t\t\t: {}),\n\t\tconstructs,\n\t\tfrontendFramework,\n\t};\n\n\tconst targetDir = join(cwd, name);\n\tconst baseTemplate = getTemplate(templateOptions.template);\n\n\tconst isMonorepo = templateOptions.monorepo;\n\tconst apiPath = templateOptions.apiPath;\n\n\tconsole.log('\\n🚀 Creating your project...\\n');\n\n\t// Create project directory\n\tawait mkdir(targetDir, { recursive: true });\n\n\t// For monorepo, app files go in the specified apiPath (e.g., apps/api)\n\tconst appDir = isMonorepo ? join(targetDir, apiPath) : targetDir;\n\tif (isMonorepo) {\n\t\tawait mkdir(appDir, { recursive: true });\n\t}\n\n\t// Collect app files (backend/api)\n\t// Note: Docker files go to root for monorepo, so exclude them here\n\tconst appFiles = baseTemplate\n\t\t? [\n\t\t\t\t...generatePackageJson(templateOptions, baseTemplate),\n\t\t\t\t...generateConfigFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateEnvFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateSourceFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateTestFiles(templateOptions, baseTemplate),\n\t\t\t]\n\t\t: [];\n\n\t// Collect root monorepo files (includes packages/models)\n\tconst rootFiles = baseTemplate\n\t\t? [\n\t\t\t\t// At the project root in both layouts: an agent opening the repo\n\t\t\t\t// reads the root, not the app directory it has not found yet.\n\t\t\t\t...generateAgentFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateGithubFiles(templateOptions),\n\t\t\t\t...generateMonorepoFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateRootConstructs(templateOptions),\n\t\t\t\t...generateModelsPackage(templateOptions),\n\t\t\t\t// The project's, like its migrations: a factory belongs to a\n\t\t\t\t// database, and every app's tests are handed it.\n\t\t\t\t...generateTestFactoryFiles(templateOptions),\n\t\t\t]\n\t\t: [];\n\n\t// Collect frontend app files for fullstack template, dispatched by framework\n\tconst webAppFiles = isFullstack\n\t\t? frontendFramework === 'tanstack-start'\n\t\t\t? generateTanStackWebFiles(templateOptions)\n\t\t\t: frontendFramework === 'expo'\n\t\t\t\t? generateExpoAppFiles(templateOptions)\n\t\t\t\t: generateWebAppFiles(templateOptions)\n\t\t: [];\n\n\t// Collect auth app files for fullstack template\n\tconst authAppFiles = isFullstack ? generateAuthAppFiles(templateOptions) : [];\n\n\t// Write root files (for monorepo)\n\tfor (const { path, content } of rootFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write app files (backend)\n\tfor (const { path, content } of appFiles) {\n\t\tconst fullPath = join(appDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write web app files (frontend)\n\tfor (const { path, content } of webAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write auth app files (authentication service)\n\tfor (const { path, content } of authAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Initialize encrypted secrets for the local stage\n\tconsole.log('🔐 Initializing encrypted secrets...\\n');\n\t// No container credentials: the containers are derived from the declared\n\t// constructs, and reconcile provisions their roles and passwords.\n\tconst local = templateOptions.stages.local;\n\tconst devSecrets = createStageSecrets(local, [], { projectName: name });\n\n\t// Add common custom secrets. No `NODE_ENV`: the command decides that, and\n\t// `gkm exec` injects secrets over the environment — so one stored here made\n\t// every `gkm exec -- next build` a development build, which Next refuses\n\t// to prerender.\n\tconst customSecrets: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (isFullstack) {\n\t\t// Auth service secrets (better-auth)\n\t\tcustomSecrets.AUTH_PORT = '3002';\n\t\tcustomSecrets.AUTH_URL = 'http://localhost:3002'; // For API app to call auth service\n\t\tcustomSecrets.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\t\tcustomSecrets.BETTER_AUTH_URL = 'http://localhost:3002';\n\t\tcustomSecrets.BETTER_AUTH_TRUSTED_ORIGINS =\n\t\t\t'http://localhost:3000,http://localhost:3001';\n\t}\n\n\tdevSecrets.custom = customSecrets;\n\n\t// The local stage's store is always the file.\n\t// Keyed by the project's identity, which is what the generated config's\n\t// `name` makes it — not the folder it happens to be created in.\n\tconst keys = { key: projectKey({ name }), legacy: [basename(targetDir)] };\n\tawait new FileSecretsStore(targetDir, keys).write(local, devSecrets);\n\tconst keyPath = getKeyPath(local, keys);\n\tconsole.log(` Secrets: .gkm/secrets/${local}.json (encrypted)`);\n\tconsole.log(` Key: ${keyPath}\\n`);\n\n\t// Install dependencies\n\tif (!options.skipInstall) {\n\t\tconsole.log('\\n📦 Installing dependencies...\\n');\n\t\ttry {\n\t\t\texecSync(getInstallCommand(pkgManager), {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\tconsole.error('Failed to install dependencies');\n\t\t}\n\n\t\t// The generators write JSON-style double quotes; the project's own\n\t\t// biome.json says single. \\`check --write\\` formats, sorts imports and\n\t\t// applies safe fixes. It was \\`format --write --unsafe\\`, which Biome 2\n\t\t// rejects outright — and the error was swallowed, so nothing was ever\n\t\t// formatted.\n\t\ttry {\n\t\t\texecSync(getExecCommand(pkgManager, 'biome check --write .'), {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t`\\n⚠️ Formatting did not finish cleanly. Run ${getRunCommand(pkgManager, 'fmt')} to see why.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Initialize git repository\n\tconsole.log('\\n📦 Initializing git repository...\\n');\n\ttry {\n\t\texecSync('git init', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git branch -M main', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git add .', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git commit -m \"🎉 Project created with @geekmidas/toolbox\"', {\n\t\t\tcwd: targetDir,\n\t\t\tstdio: 'pipe',\n\t\t});\n\t\tconsole.log(' Initialized git repository on branch main');\n\t} catch {\n\t\tconsole.log(\n\t\t\t' Could not initialize git repository (git may not be installed)',\n\t\t);\n\t}\n\n\t// Print success message with next steps\n\tprintNextSteps(name, templateOptions, pkgManager);\n}\n\n/**\n * Print success message with next steps\n */\nfunction printNextSteps(\n\tprojectName: string,\n\toptions: TemplateOptions,\n\tpkgManager: PackageManager,\n): void {\n\tconst devCommand = getRunCommand(pkgManager, 'dev');\n\tconst cdCommand = `cd ${projectName}`;\n\n\tconsole.log(`\\n${'─'.repeat(50)}`);\n\tconsole.log('\\n✅ Project created successfully!\\n');\n\n\tconsole.log('Next steps:\\n');\n\tconsole.log(` ${cdCommand}`);\n\n\t// A project that declares its infrastructure starts nothing by hand:\n\t// `gkm dev` reconciles the containers its constructs imply first.\n\tconsole.log(` ${devCommand}`);\n\n\tif (options.constructs.database) {\n\t\tconsole.log('');\n\t\tconsole.log(\n\t\t\t\" # Apply each database construct's db/<construct>/ migrations:\",\n\t\t);\n\t\tconsole.log(' gkm migrate');\n\t\tif (options.monorepo) {\n\t\t\tconsole.log(\" # Better Auth's tables, as its tenant's first migration:\");\n\t\t\tconsole.log(' gkm migration auth && gkm migrate');\n\t\t}\n\t}\n\tconsole.log('');\n\n\tif (options.monorepo) {\n\t\tconsole.log('📁 Project structure:');\n\t\tconsole.log(` ${projectName}/`);\n\t\tconsole.log(` ├── apps/`);\n\t\tconsole.log(` │ ├── api/ # Backend API`);\n\t\tif (isFullstackTemplate(options.template)) {\n\t\t\tconsole.log(` │ ├── auth/ # Auth service (better-auth)`);\n\t\t\tswitch (options.frontendFramework) {\n\t\t\t\tcase 'tanstack-start':\n\t\t\t\t\tconsole.log(` │ └── web/ # TanStack Start frontend`);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'expo':\n\t\t\t\t\tconsole.log(` │ └── app/ # Expo (React Native) app`);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(` │ └── web/ # Next.js frontend`);\n\t\t\t}\n\t\t}\n\t\tconsole.log(` ├── packages/`);\n\t\tconsole.log(` │ └── models/ # Shared Zod schemas`);\n\t\tconsole.log(` ├── .gkm/secrets/ # Encrypted secrets`);\n\t\tconsole.log(` ├── gkm.config.ts # Workspace config`);\n\t\tconsole.log(` └── turbo.json # Turbo config`);\n\t\tconsole.log('');\n\t}\n\n\tconst { local, deployed } = options.stages;\n\tconsole.log('🔐 Secrets management:');\n\tconsole.log(` gkm secrets:show --stage ${local} # View secrets`);\n\tconsole.log(` gkm secrets:set KEY VALUE --stage ${local} # Add secret`);\n\tfor (const stage of deployed) {\n\t\tconsole.log(\n\t\t\t` gkm secrets:init --stage ${stage} # Create ${stage} secrets`,\n\t\t);\n\t}\n\tconsole.log('');\n\n\tif (options.deployTarget === 'dokploy') {\n\t\tconsole.log('🚀 Deployment:');\n\t\tfor (const stage of deployed) {\n\t\t\tconsole.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)}`);\n\t\t}\n\t\tconsole.log('');\n\t}\n\n\tif (options.deployTarget === 'sst') {\n\t\tconsole.log('🚀 Deployment (AWS, through SST):');\n\t\tfor (const stage of deployed) {\n\t\t\tconsole.log(\n\t\t\t\t` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm deploy: build, sst deploy, health checks`,\n\t\t\t);\n\t\t}\n\t\tconsole.log(` Uses your AWS credentials, in ${options.region}.`);\n\t\tif (options.constructs.mail) {\n\t\t\tconsole.log(' Set MAIL_FROM to a sender verified in SES first.');\n\t\t}\n\t\tconsole.log('');\n\t}\n\n\tconsole.log('📚 Documentation: https://geekmidas.github.io/toolbox/');\n\tconsole.log('');\n}\n\n/**\n * The stages the project declares, from the answers or the flags.\n *\n * `--yes` with no stage flags has nobody to ask and needs an answer, so it\n * takes `local`, and one deployed stage, `production`, that is protected.\n */\nfunction resolveStages(\n\toptions: InitOptions,\n\tanswers: {\n\t\tdeployedStages?: string;\n\t\tprotectedStage?: string;\n\t\tlocalStage?: string;\n\t},\n): StagesConfig {\n\tconst deployed = stageList(\n\t\toptions.stages ??\n\t\t\tanswers.deployedStages ??\n\t\t\t(options.yes ? 'production' : ''),\n\t);\n\tconst kept =\n\t\toptions.protectedStage ??\n\t\tanswers.protectedStage ??\n\t\t(deployed.length === 1 || options.yes ? deployed[0] : undefined);\n\tconst local = (\n\t\toptions.localStage ??\n\t\tanswers.localStage ??\n\t\t(options.yes ? 'local' : '')\n\t).trim();\n\n\tconst stages: StagesConfig = {\n\t\tlocal,\n\t\tdeployed,\n\t\t...(kept ? { protected: [kept] } : {}),\n\t};\n\tconst problems = stageProblems(stages);\n\tif (problems.length) throw new InvalidStages(problems);\n\treturn stages;\n}\n\n/** `--deploy` naming a target init has no scaffold for. */\nexport class UnknownDeployTarget extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(`Unknown deploy target \"${target}\". Use ${known.join(', ')}.`);\n\t\tthis.name = 'UnknownDeployTarget';\n\t}\n}\n\n/** `--region` that is not shaped like one, e.g. `europe` for `eu-west-1`. */\nexport class NotAnAwsRegion extends Error {\n\tconstructor(readonly region: string) {\n\t\tsuper(`\"${region}\" is not an AWS region. Use one like eu-west-1.`);\n\t\tthis.name = 'NotAnAwsRegion';\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { generateSecurePassword } from '../secrets/generator.js';\nimport type { StageSecrets } from '../secrets/types.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/**\n * Generate a secure random password for database users.\n * Uses a combination of timestamp and random bytes for uniqueness.\n */\nexport function generateDbPassword(): string {\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Generate database URL for an app.\n * All apps connect to the same database, but use different users/schemas.\n */\nexport function generateDbUrl(\n\tappName: string,\n\tpassword: string,\n\tprojectName: string,\n\thost = 'localhost',\n\tport = 5432,\n): string {\n\tconst userName = appName.replace(/-/g, '_');\n\tconst dbName = `${projectName.replace(/-/g, '_')}_dev`;\n\treturn `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;\n}\n\n/**\n * Generate fullstack-aware custom secrets for a workspace.\n *\n * Generates:\n * - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command\n * decides that; see `gkm init`)\n * - Per-app database passwords and URLs for backend apps with db service\n * - Better-auth secrets for apps using the better-auth framework\n */\nexport function generateFullstackCustomSecrets(\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): Record<string, string> {\n\t// A Postgres exists because something declared a database, not because\n\t// config carried a flag saying so.\n\tconst hasDb = containers.includes('postgres');\n\tconst customs: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (!hasDb) {\n\t\treturn customs;\n\t}\n\n\t// Collect all frontend ports for trusted origins\n\tconst frontendPorts: number[] = [];\n\n\tfor (const [appName, appConfig] of Object.entries(workspace.apps)) {\n\t\tif (appConfig.type === 'web') {\n\t\t\tfrontendPorts.push(appConfig.port);\n\t\t\tconst upperName = appName.toUpperCase();\n\t\t\tcustoms[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mobile apps (Expo, etc.) don't run on a host port the backend\n\t\t// cares about for CORS, and don't need DB credentials.\n\t\tif (appConfig.type === 'mobile') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Backend apps with database: generate per-app DB passwords and URLs\n\t\tconst password = generateDbPassword();\n\t\tconst upperName = appName.toUpperCase();\n\n\t\tcustoms[`${upperName}_DATABASE_URL`] = generateDbUrl(\n\t\t\tappName,\n\t\t\tpassword,\n\t\t\tworkspace.name,\n\t\t);\n\t\tcustoms[`${upperName}_DB_PASSWORD`] = password;\n\n\t\t// Better-auth framework secrets\n\t\tif (appConfig.framework === 'better-auth') {\n\t\t\tcustoms.AUTH_PORT = String(appConfig.port);\n\t\t\tcustoms.AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t\tcustoms.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${generateSecurePassword(16)}`;\n\t\t\tcustoms.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t}\n\t}\n\n\t// Generate trusted origins for better-auth (all app ports)\n\tif (customs.BETTER_AUTH_SECRET) {\n\t\tconst allPorts = Object.values(workspace.apps).map((a) => a.port);\n\t\tcustoms.BETTER_AUTH_TRUSTED_ORIGINS = allPorts\n\t\t\t.map((p) => `http://localhost:${p}`)\n\t\t\t.join(',');\n\t}\n\n\treturn customs;\n}\n\n/**\n * Extract *_DB_PASSWORD keys from secrets and write docker/.env.\n *\n * The docker/.env file contains database passwords that the PostgreSQL\n * init script reads to create per-app database users.\n */\nexport async function writeDockerEnvFromSecrets(\n\tsecrets: StageSecrets,\n\tworkspaceRoot: string,\n): Promise<void> {\n\tconst dbPasswordEntries = Object.entries(secrets.custom).filter(([key]) =>\n\t\tkey.endsWith('_DB_PASSWORD'),\n\t);\n\n\t// Always include pgboss password when pgboss credentials exist\n\tif (\n\t\tsecrets.services.pgboss &&\n\t\t!dbPasswordEntries.some(([key]) => key === 'PGBOSS_DB_PASSWORD')\n\t) {\n\t\tdbPasswordEntries.push([\n\t\t\t'PGBOSS_DB_PASSWORD',\n\t\t\tsecrets.services.pgboss.password,\n\t\t]);\n\t}\n\n\tif (dbPasswordEntries.length === 0) {\n\t\treturn;\n\t}\n\n\tconst envContent = `# Auto-generated docker environment file\n# Contains database passwords for docker-compose postgres init\n# This file is gitignored - do not commit to version control\n${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join('\\n')}\n`;\n\n\tconst envPath = join(workspaceRoot, 'docker', '.env');\n\tawait mkdir(dirname(envPath), { recursive: true });\n\tawait writeFile(envPath, envContent);\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport {\n\tConfigNotFound,\n\tloadWorkspaceConfig,\n\tloadWorkspaceSettings,\n} from '../config';\nimport { constructGlobs } from '../reconcile/workspace';\nimport { generateFullstackCustomSecrets } from '../setup/fullstack-secrets';\nimport { CredentialsInvalid, loadCredentialSchemas } from './credentialSchemas';\nimport { FileSecretsStore } from './file.js';\nimport { createStageSecrets, rotateServicePassword } from './generator';\nimport { maskPassword, withCustomSecret } from './storage';\nimport { type SecretsStore, secretsStoreFor } from './store.js';\nimport type { SecretServiceName } from './types';\n\nconst logger = console;\n\n/**\n * The store the stage named on the command line keeps its secrets in — SSM or\n * Secrets Manager in its account, for a deployed stage kept there. Outside any workspace nothing\n * names a store, so it is the file.\n */\nasync function storeFor(stage: string): Promise<SecretsStore> {\n\ttry {\n\t\treturn await secretsStoreFor(await loadWorkspaceSettings(), stage);\n\t} catch (error) {\n\t\tif (error instanceof ConfigNotFound) {\n\t\t\treturn new FileSecretsStore(process.cwd());\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport interface SecretsInitOptions {\n\tstage: string;\n\tforce?: boolean;\n}\n\nexport interface SecretsSetOptions {\n\tstage: string;\n}\n\nexport interface SecretsShowOptions {\n\tstage: string;\n\treveal?: boolean;\n}\n\nexport interface SecretsRotateOptions {\n\tstage: string;\n\tservice?: SecretServiceName;\n}\n\nexport interface SecretsImportOptions {\n\tstage: string;\n\t/** Merge with existing secrets (default: true) */\n\tmerge?: boolean;\n}\n\n/**\n * Initialize secrets for a stage.\n * Generates secure random passwords for configured services.\n */\nexport async function secretsInitCommand(\n\toptions: SecretsInitOptions,\n): Promise<void> {\n\tconst { stage, force } = options;\n\n\tconst store = await storeFor(stage);\n\n\t// Check if secrets already exist\n\tif (!force && (await store.read(stage))) {\n\t\tlogger.error(\n\t\t\t`Secrets already exist for stage \"${stage}\". Use --force to overwrite.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Detect workspace mode for project name and fullstack secrets\n\tlet projectName: string | undefined;\n\tlet workspaceSecrets: Record<string, string> | undefined;\n\ttry {\n\t\tconst loaded = await loadWorkspaceConfig();\n\t\tprojectName = loaded.workspace.name;\n\t\tconst isMultiApp = Object.keys(loaded.workspace.apps).length > 1;\n\n\t\tif (isMultiApp) {\n\t\t\tworkspaceSecrets = generateFullstackCustomSecrets(loaded.workspace);\n\t\t\tlogger.log(' Detected workspace mode — generating per-app secrets');\n\t\t}\n\t} catch {\n\t\t// Not a workspace — single-app mode, skip custom secrets\n\t}\n\n\t// Generate secrets (with project name so DATABASE_URL matches app-specific URLs)\n\t// No container credentials: the containers are derived from the declared\n\t// constructs, and reconcile provisions their roles and passwords.\n\tconst secrets = createStageSecrets(stage, [], { projectName });\n\n\tif (workspaceSecrets) {\n\t\tsecrets.custom = workspaceSecrets;\n\t}\n\n\tawait store.write(stage, secrets);\n\n\tlogger.log(`\\n✓ Secrets initialized for stage \"${stage}\"`);\n\tlogger.log(` Store: ${store.name}`);\n\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(`\\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\tif (Object.keys(secrets.custom).length > 0) {\n\t\tlogger.log(`\\n Custom secrets: ${Object.keys(secrets.custom).length}`);\n\t}\n\n\tlogger.log(`\\n Use \"gkm secrets:show --stage ${stage}\" to view secrets`);\n\tlogger.log(\n\t\t' Use \"gkm secrets:set <KEY> <VALUE> --stage ' +\n\t\t\tstage +\n\t\t\t'\" to add custom secrets',\n\t);\n}\n\n/**\n * Read all data from stdin.\n */\nasync function readStdin(): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\n\tfor await (const chunk of process.stdin) {\n\t\tchunks.push(chunk);\n\t}\n\n\treturn Buffer.concat(chunks).toString('utf-8').trim();\n}\n\n/**\n * Set a custom secret.\n * If value is not provided, reads from stdin.\n */\nexport async function secretsSetCommand(\n\tkey: string,\n\tvalue: string | undefined,\n\toptions: SecretsSetOptions,\n): Promise<void> {\n\tconst { stage } = options;\n\n\t// Read from stdin if value not provided\n\tlet secretValue = value;\n\tif (!secretValue) {\n\t\tif (process.stdin.isTTY) {\n\t\t\tlogger.error(\n\t\t\t\t'No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>',\n\t\t\t);\n\t\t\tlogger.error(\n\t\t\t\t'Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsecretValue = await readStdin();\n\t\tif (!secretValue) {\n\t\t\tlogger.error('No value received from stdin');\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tawait assertCredentialValue(key, secretValue, stage);\n\n\tawait store.write(stage, withCustomSecret(secrets, key, secretValue));\n\tlogger.log(`\\n✓ Secret \"${key}\" set for stage \"${stage}\" (${store.name})`);\n}\n\n/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them before they are stored — what the app would otherwise\n * refuse as it starts. Only a `<ID>_CREDENTIALS` key in a workspace is\n * looked at, so setting anything else loads no construct.\n *\n * @throws {CredentialsInvalid} listing each issue; nothing is saved\n */\nasync function assertCredentialValue(\n\tkey: string,\n\tvalue: string,\n\tstage: string,\n): Promise<void> {\n\tif (!key.endsWith('_CREDENTIALS')) return;\n\n\tlet workspace: Awaited<ReturnType<typeof loadWorkspaceSettings>>;\n\ttry {\n\t\tworkspace = await loadWorkspaceSettings();\n\t} catch (error) {\n\t\tif (error instanceof ConfigNotFound) return;\n\t\tthrow error;\n\t}\n\n\tconst schemas = await loadCredentialSchemas({\n\t\troot: workspace.root,\n\t\tpatterns: constructGlobs(workspace),\n\t});\n\tconst check = await schemas.check(key, value);\n\tif (!check.ok) {\n\t\tthrow new CredentialsInvalid(stage, [{ key, issues: check.issues }], 'set');\n\t}\n}\n\n/**\n * Show secrets for a stage.\n */\nexport async function secretsShowCommand(\n\toptions: SecretsShowOptions,\n): Promise<void> {\n\tconst { stage, reveal } = options;\n\n\tconst secrets = await (await storeFor(stage)).read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tlogger.log(`\\nSecrets for stage \"${stage}\":`);\n\tlogger.log(` Created: ${secrets.createdAt}`);\n\tlogger.log(` Updated: ${secrets.updatedAt}`);\n\n\t// Show service credentials\n\tlogger.log('\\nService Credentials:');\n\tfor (const [service, creds] of Object.entries(secrets.services)) {\n\t\tif (creds) {\n\t\t\tlogger.log(`\\n ${service}:`);\n\t\t\tlogger.log(` host: ${creds.host}`);\n\t\t\tlogger.log(` port: ${creds.port}`);\n\t\t\tlogger.log(` username: ${creds.username}`);\n\t\t\tlogger.log(\n\t\t\t\t` password: ${reveal ? creds.password : maskPassword(creds.password)}`,\n\t\t\t);\n\t\t\tif (creds.database) {\n\t\t\t\tlogger.log(` database: ${creds.database}`);\n\t\t\t}\n\t\t\tif (creds.bucket) {\n\t\t\t\tlogger.log(` bucket: ${creds.bucket}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Show URLs\n\tlogger.log('\\nConnection URLs:');\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(\n\t\t\t` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(\n\t\t\t` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\t// Show custom secrets\n\tconst customKeys = Object.keys(secrets.custom);\n\tif (customKeys.length > 0) {\n\t\tlogger.log('\\nCustom Secrets:');\n\t\tfor (const [key, value] of Object.entries(secrets.custom)) {\n\t\t\tlogger.log(` ${key}: ${reveal ? value : maskPassword(value)}`);\n\t\t}\n\t}\n\n\tif (!reveal) {\n\t\tlogger.log('\\nUse --reveal to show actual values');\n\t}\n}\n\n/**\n * Rotate passwords for services.\n */\nexport async function secretsRotateCommand(\n\toptions: SecretsRotateOptions,\n): Promise<void> {\n\tconst { stage, service } = options;\n\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tif (service) {\n\t\t// Rotate specific service\n\t\tif (!secrets.services[service]) {\n\t\t\tlogger.error(`Service \"${service}\" not configured in stage \"${stage}\"`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst updated = rotateServicePassword(secrets, service);\n\t\tawait store.write(stage, updated);\n\t\tlogger.log(`\\n✓ Password rotated for ${service} in stage \"${stage}\"`);\n\t} else {\n\t\t// Rotate all services\n\t\tlet updated = secrets;\n\t\tconst services = Object.keys(secrets.services) as SecretServiceName[];\n\n\t\tfor (const svc of services) {\n\t\t\tupdated = rotateServicePassword(updated, svc);\n\t\t}\n\n\t\tawait store.write(stage, updated);\n\t\tlogger.log(\n\t\t\t`\\n✓ Passwords rotated for all services in stage \"${stage}\": ${services.join(', ')}`,\n\t\t);\n\t}\n\n\tlogger.log(`\\nUse \"gkm secrets:show --stage ${stage}\" to view new values`);\n}\n\n/**\n * Import secrets from a JSON file.\n */\nexport async function secretsImportCommand(\n\tfile: string,\n\toptions: SecretsImportOptions,\n): Promise<void> {\n\tconst { stage, merge = true } = options;\n\n\t// Check if file exists\n\tif (!existsSync(file)) {\n\t\tlogger.error(`File not found: ${file}`);\n\t\tprocess.exit(1);\n\t}\n\n\t// Read and parse JSON file\n\tlet importedSecrets: Record<string, string>;\n\ttry {\n\t\tconst content = await readFile(file, 'utf-8');\n\t\timportedSecrets = JSON.parse(content);\n\n\t\t// Validate it's a flat object with string values\n\t\tif (typeof importedSecrets !== 'object' || importedSecrets === null) {\n\t\t\tthrow new Error('JSON must be an object');\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(importedSecrets)) {\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Value for \"${key}\" must be a string, got ${typeof value}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Failed to parse JSON file: ${error instanceof Error ? error.message : 'Invalid JSON'}`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Check if secrets exist for stage\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Merge or replace custom secrets\n\tconst updatedCustom = merge\n\t\t? { ...secrets.custom, ...importedSecrets }\n\t\t: importedSecrets;\n\n\tconst updated = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: updatedCustom,\n\t};\n\n\tawait store.write(stage, updated);\n\n\tconst importedCount = Object.keys(importedSecrets).length;\n\tconst totalCount = Object.keys(updatedCustom).length;\n\n\tlogger.log(`\\n✓ Imported ${importedCount} secrets for stage \"${stage}\"`);\n\n\tif (merge && totalCount > importedCount) {\n\t\tlogger.log(` Total custom secrets: ${totalCount}`);\n\t}\n\n\tlogger.log('\\n Imported keys:');\n\tfor (const key of Object.keys(importedSecrets)) {\n\t\tlogger.log(` - ${key}`);\n\t}\n}\n\n/**\n * Mask password in a URL for display.\n */\nexport function maskUrl(url: string): string {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tif (parsed.password) {\n\t\t\tparsed.password = maskPassword(parsed.password);\n\t\t}\n\t\treturn parsed.toString();\n\t} catch {\n\t\treturn url;\n\t}\n}\n","import { loadWorkspaceConfig } from '../config.js';\nimport { describeServices } from '../reconcile/containers.js';\nimport {\n\tderivedContainers,\n\treconcileWorkspace,\n} from '../reconcile/workspace.js';\nimport {\n\tcreateStageSecrets,\n\tgenerateConnectionUrls,\n\tgenerateSecurePassword,\n\tgenerateServiceCredentials,\n} from '../secrets/generator.js';\nimport { secretsStoreFor } from '../secrets/store.js';\nimport type { SecretServiceName, StageSecrets } from '../secrets/types.js';\nimport { ensureTrusted } from '../trust/index.js';\nimport type { LoadedConfig, NormalizedWorkspace } from '../workspace/types.js';\nimport {\n\tgenerateFullstackCustomSecrets,\n\twriteDockerEnvFromSecrets,\n} from './fullstack-secrets.js';\n\nconst logger = console;\n\nexport interface SetupOptions {\n\tstage?: string;\n\tforce?: boolean;\n\tskipDocker?: boolean;\n\tyes?: boolean;\n}\n\n/**\n * Setup development environment.\n *\n * Orchestrates:\n * 1. Load workspace config\n * 2. Resolve secrets (local → the stage's store → generate fresh)\n * 3. Write docker/.env from secrets\n * 4. Start Docker services\n */\nexport async function setupCommand(options: SetupOptions = {}): Promise<void> {\n\tlogger.log('\\n🔧 Setting up the local environment...\\n');\n\n\t// 1. Load workspace config\n\tlet loadedConfig: LoadedConfig;\n\ttry {\n\t\tloadedConfig = await loadWorkspaceConfig();\n\t} catch {\n\t\tlogger.error(\n\t\t\t'❌ No gkm.config.ts found. Run this command from a workspace root.',\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tconst stage = options.stage ?? loadedConfig.workspace.stages.local;\n\n\tconst { workspace } = loadedConfig;\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\n\tlogger.log(`📦 Workspace: ${workspace.name}`);\n\tlogger.log(`📱 Apps: ${Object.keys(workspace.apps).join(', ')}`);\n\tlogger.log(`🔑 Stage: ${stage}\\n`);\n\n\t// 2. Resolve secrets\n\tconst secrets = await resolveSecrets(stage, workspace, options);\n\n\tif (!secrets) {\n\t\tlogger.error('❌ Failed to resolve secrets. Exiting.');\n\t\tprocess.exit(1);\n\t}\n\n\t// 3. Write docker/.env from secrets (always regenerated as derived file)\n\tconst containers = await derivedContainers(workspace, stage);\n\n\tif (isMultiApp && containers.includes('postgres')) {\n\t\tawait writeDockerEnvFromSecrets(secrets, workspace.root);\n\t\tlogger.log('📄 Generated docker/.env with database passwords');\n\t}\n\n\t// 4. Reconcile the local target: derive containers, allocate ports, start.\n\tif (!options.skipDocker) {\n\t\tlogger.log('');\n\n\t\tawait reconcileLocal(workspace, stage, options);\n\t}\n\n\t// Print summary\n\tprintSummary(workspace, stage);\n}\n\n/**\n * Converge this machine on what the manifest declares.\n *\n * Says what it did in one line and stays silent when it did nothing, because\n * reconciling on every start is only tolerable if the converged case is both\n * free and quiet.\n */\nasync function reconcileLocal(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\toptions: SetupOptions,\n): Promise<void> {\n\tconst result = await reconcileWorkspace(workspace, { stage });\n\n\tif (result.plan.containers.length === 0) {\n\t\tlogger.log('🐳 No containers declared');\n\t\treturn;\n\t}\n\n\tif (!result.changed) {\n\t\tlogger.log('🐳 Services already up to date');\n\t\treturn;\n\t}\n\n\tlogger.log('🐳 Services');\n\tfor (const line of describeServices(result.services)) {\n\t\tlogger.log(line);\n\t}\n\n\t// Only where something actually answers on https. A project with no edge has\n\t// no authority to trust and should never be asked about one. Every app\n\t// behind the edge answers there — not only a file server, which used to be\n\t// the only one asked about, so a workspace of APIs and sites never was.\n\tconst url = result.plan.resources\n\t\t.filter(\n\t\t\t(r) =>\n\t\t\t\tr.kind === 'rest-api' || r.kind === 'site' || r.kind === 'file-server',\n\t\t)\n\t\t.map((r) => result.env[r.envKey])\n\t\t.find((address) => address?.startsWith('https://'));\n\n\tif (url) {\n\t\tawait ensureTrusted(workspace.root, url, {\n\t\t\t...(options.yes ? { assumeYes: true } : {}),\n\t\t});\n\t}\n}\n\n/**\n * Resolve secrets with priority:\n * 1. Local secrets exist → use them (preserves manual additions)\n * 2. A deployed stage whose store has secrets → pull and use\n * 3. Neither → generate fresh secrets\n *\n * --force skips checks 1 and 2 and always regenerates.\n */\nasync function resolveSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n\toptions: SetupOptions,\n) {\n\t// Force regeneration\n\tif (options.force) {\n\t\tlogger.log('🔐 Generating fresh secrets (--force)...');\n\t\treturn generateFreshSecrets(stage, workspace);\n\t}\n\n\t// The stage's own store — SSM or Secrets Manager in its account, for a\n\t// stage kept there\n\tconst store = await secretsStoreFor(workspace, stage);\n\tconst secrets = await store.read(stage);\n\tif (secrets) {\n\t\tlogger.log('🔐 Using existing secrets');\n\t\t// Reconcile: add any missing workspace-derived keys without overwriting\n\t\tconst reconciled = reconcileSecrets(\n\t\t\tsecrets,\n\t\t\tworkspace,\n\t\t\tawait derivedContainers(workspace, stage),\n\t\t);\n\t\tif (reconciled) {\n\t\t\tawait store.write(stage, reconciled);\n\t\t}\n\t\treturn reconciled ?? secrets;\n\t}\n\n\t// Generate fresh secrets\n\tlogger.log('🔐 Generating fresh development secrets...');\n\treturn generateFreshSecrets(stage, workspace);\n}\n\n/**\n * Reconcile existing secrets with expected workspace-derived keys.\n * Adds missing keys (e.g. BETTER_AUTH_*) without overwriting existing values.\n * Returns the updated secrets if changes were made, or null if no changes needed.\n * @internal Exported for testing\n */\n/**\n * Which containers hold a credential worth generating.\n *\n * Reconcile's container names, mapped to the service a credential is stored\n * under. `redis-http` is the Upstash-protocol proxy in front of Redis and holds\n * no credential of its own — its token is derived — so it maps to nothing, and\n * `caddy` is an edge with nothing to log into.\n */\nfunction credentialedServices(\n\tcontainers: readonly string[],\n): SecretServiceName[] {\n\tconst byContainer: Readonly<Record<string, SecretServiceName>> = {\n\t\tpostgres: 'postgres',\n\t\tredis: 'redis',\n\t\tminio: 'minio',\n\t\tmailpit: 'mailpit',\n\t\tlocalstack: 'localstack',\n\t\t// No `rabbitmq`: the container runs as the local user, and a topic's\n\t\t// \\`rabbitmq://\\` URL is reconcile's. A generated password matched\n\t\t// nothing, and the \\`RABBITMQ_URL\\` built from it could never connect.\n\t};\n\n\treturn [\n\t\t...new Set(\n\t\t\tcontainers\n\t\t\t\t.map((container) => byContainer[container])\n\t\t\t\t.filter((name): name is SecretServiceName => Boolean(name)),\n\t\t),\n\t];\n}\n\nexport function reconcileSecrets(\n\tsecrets: StageSecrets,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): StageSecrets | null {\n\tlet changed = false;\n\tlet result = { ...secrets };\n\n\t// Reconcile service credentials: add missing services\n\tfor (const name of credentialedServices(containers)) {\n\t\tif (!result.services[name]) {\n\t\t\tconst creds = generateServiceCredentials(name);\n\t\t\t// Override defaults with project-derived names\n\t\t\tif (name === 'minio') {\n\t\t\t\tcreds.bucket = workspace.name;\n\t\t\t\tcreds.username = workspace.name;\n\t\t\t}\n\t\t\tresult = {\n\t\t\t\t...result,\n\t\t\t\tservices: { ...result.services, [name]: creds },\n\t\t\t};\n\t\t\tresult.urls = generateConnectionUrls(result.services);\n\t\t\tlogger.log(` 🔄 Adding missing service credentials: ${name}`);\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// Always add pgboss credentials when postgres is available\n\tif (result.services.postgres && !result.services.pgboss) {\n\t\tresult = {\n\t\t\t...result,\n\t\t\tservices: {\n\t\t\t\t...result.services,\n\t\t\t\tpgboss: {\n\t\t\t\t\thost: result.services.postgres.host,\n\t\t\t\t\tport: result.services.postgres.port,\n\t\t\t\t\tusername: 'pgboss',\n\t\t\t\t\tpassword: generateSecurePassword(),\n\t\t\t\t\tdatabase: result.services.postgres.database ?? 'app',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\tresult.urls = generateConnectionUrls(result.services);\n\t\tlogger.log(' 🔄 Adding missing service credentials: pgboss');\n\t\tchanged = true;\n\t}\n\n\t// Reconcile custom secrets for multi-app workspaces\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (isMultiApp) {\n\t\tconst expected = generateFullstackCustomSecrets(workspace, containers);\n\t\tconst missing: Record<string, string> = {};\n\n\t\tfor (const [key, value] of Object.entries(expected)) {\n\t\t\tif (!(key in result.custom)) {\n\t\t\t\tmissing[key] = value;\n\t\t\t}\n\t\t}\n\n\t\tif (Object.keys(missing).length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t` 🔄 Adding missing secrets: ${Object.keys(missing).join(', ')}`,\n\t\t\t);\n\t\t\tresult = {\n\t\t\t\t...result,\n\t\t\t\tcustom: { ...result.custom, ...missing },\n\t\t\t};\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (!changed) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\t...result,\n\t\tupdatedAt: new Date().toISOString(),\n\t};\n}\n\n/**\n * Build a fresh StageSecrets object for a workspace: service credentials,\n * connection URLs, and custom secrets. Pure — does not write to disk or touch\n * any store. Service passwords are freshly randomized, so the result must be the same\n * one used to start the matching Docker containers.\n * @internal Exported for reuse by `gkm test` auto-setup.\n */\nexport function createFreshWorkspaceSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): StageSecrets {\n\t// Which services need a credential is which containers exist, and that is\n\t// the manifest's answer. It used to be a boolean per service read from\n\t// config, which generated a Postgres password for a project with no\n\t// database and none for a project that declared one and set no flag.\n\tconst serviceNames = credentialedServices(containers);\n\n\t// Create base secrets with service credentials\n\t// No events backend: whether there are events is a declared `Topic` or\n\t// `Queue`, and reconcile derives their connection strings from those.\n\t// Passing the target's broker here would demand broker credentials from a\n\t// project that declared no queue at all.\n\tconst secrets = createStageSecrets(stage, serviceNames, {\n\t\tprojectName: workspace.name,\n\t});\n\n\t// Generate fullstack-aware custom secrets\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (isMultiApp) {\n\t\tsecrets.custom = generateFullstackCustomSecrets(workspace, containers);\n\t} else {\n\t\t// No `NODE_ENV`, for the reason `gkm init` gives: `gkm exec` injects\n\t\t// secrets over the environment, so a stored one made every\n\t\t// `gkm exec -- next build` a development build.\n\t\tsecrets.custom = {\n\t\t\tPORT: '3000',\n\t\t\tLOG_LEVEL: 'debug',\n\t\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t\t};\n\t}\n\n\treturn secrets;\n}\n\n/**\n * Ensure a usable secret set exists for a stage, generating a fresh one from the\n * workspace config when none is present. No-op if secrets already exist.\n *\n * Powers `gkm test --auto-setup` / `GKM_AUTO_SETUP`: CI can run without a\n * committed secrets file or a shared encryption key — the stage is regenerated\n * from the committed `gkm.config.ts`, and the file store mints a local key.\n *\n * @returns true if fresh secrets were generated, false if existing ones were kept\n */\nexport async function ensureStageSecrets(\n\tstage: string,\n\tcwd: string = process.cwd(),\n): Promise<boolean> {\n\tconst { workspace } = await loadWorkspaceConfig(cwd);\n\n\tconst store = await secretsStoreFor(workspace, stage);\n\tif (await store.read(stage)) {\n\t\treturn false;\n\t}\n\n\tconst secrets = createFreshWorkspaceSecrets(\n\t\tstage,\n\t\tworkspace,\n\t\tawait derivedContainers(workspace, stage),\n\t);\n\tawait store.write(stage, secrets);\n\treturn true;\n}\n\n/**\n * Generate fresh secrets for the workspace.\n */\nasync function generateFreshSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n) {\n\tconst secrets = createFreshWorkspaceSecrets(\n\t\tstage,\n\t\tworkspace,\n\t\tawait derivedContainers(workspace, stage),\n\t);\n\n\t// Straight to the stage's store, where a deploy from anywhere reads them.\n\tconst store = await secretsStoreFor(workspace, stage);\n\tawait store.write(stage, secrets);\n\tlogger.log(` Secrets written to the \"${stage}\" store (${store.name})`);\n\n\treturn secrets;\n}\n\n/**\n * Print setup summary with next steps.\n */\nfunction printSummary(workspace: NormalizedWorkspace, stage: string): void {\n\tlogger.log(`\\n${'─'.repeat(50)}`);\n\tlogger.log('\\n✅ Development environment ready!\\n');\n\n\tlogger.log('📋 Apps:');\n\tfor (const [name, app] of Object.entries(workspace.apps)) {\n\t\tconst icon =\n\t\t\tapp.type === 'web' ? '🌐' : app.type === 'mobile' ? '📱' : '🔧';\n\t\tlogger.log(` ${icon} ${name} → http://localhost:${app.port}`);\n\t}\n\n\tlogger.log('\\n🚀 Next steps:');\n\tlogger.log(' gkm dev # Start all apps');\n\tlogger.log(` gkm secrets:show --stage ${stage} # View secrets`);\n\tlogger.log('');\n}\n","/**\n * Dropping the test stage's databases when a suite ends.\n *\n * Reconcile never drops — the line it draws is at data. The test stage's data\n * is the exception: every test runs in a transaction rolled back after it, so\n * nothing in these databases is anyone's, and a database kept between runs is\n * one whose migrations already ran — an edited migration is never applied to\n * it again. So each run starts from a database it created, and drops it when\n * the suite ends: the Vitest global setup's teardown.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pgClient } from '../reconcile/clients';\nimport type { SqlClient } from '../reconcile/provision';\nimport { quoteIdentifier } from '../reconcile/provision';\nimport { forgetState } from '../reconcile/state';\nimport { TEST_STAGE } from '../workspace/stages';\nimport { TEST_READY_FILE, type TestReady } from './ready';\n\n/**\n * Drop the databases the last setup recorded, and forget the test stage's\n * reconcile, so the next run provisions them from nothing.\n *\n * A no-op when nothing is recorded — no run yet, or one already torn down —\n * so running it twice, or before a setup, is harmless.\n */\nexport async function dropTestDatabases(\n\t/** Where `gkm test` ran — its ready file is under it. */\n\tcwd: string,\n\t/** The workspace root, which holds the reconcile state. */\n\troot: string,\n\tsql: (port: number) => SqlClient = pgClient,\n): Promise<string[]> {\n\tconst readyPath = join(cwd, TEST_READY_FILE);\n\tconst ready = await readReady(readyPath);\n\tconst recorded = ready?.databases;\n\tif (!ready || !recorded) return [];\n\n\tconst client = sql(recorded.port);\n\tfor (const name of recorded.names) {\n\t\t// Recorded from the test stage's plan, so always suffixed — checked\n\t\t// anyway: the container is shared with the local stage, and this is the\n\t\t// one statement in the toolbox that deletes a developer's data.\n\t\tif (!name.endsWith(`_${TEST_STAGE}`)) {\n\t\t\tthrow new NotATestDatabase(name);\n\t\t}\n\t\t// FORCE: a connection left open by the suite — a pool not yet ended —\n\t\t// would otherwise keep the database alive.\n\t\tawait client.query(\n\t\t\tundefined,\n\t\t\t`DROP DATABASE IF EXISTS ${quoteIdentifier(name)} WITH (FORCE)`,\n\t\t);\n\t}\n\n\tawait forgetState(root, TEST_STAGE);\n\tconst { databases: _dropped, ...rest } = ready;\n\tawait writeFile(readyPath, JSON.stringify(rest, null, 2));\n\n\treturn recorded.names;\n}\n\nasync function readReady(path: string): Promise<TestReady | undefined> {\n\ttry {\n\t\treturn JSON.parse(await readFile(path, 'utf-8')) as TestReady;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** A name recorded for the test stage without the test stage's suffix. */\nexport class NotATestDatabase extends Error {\n\tconstructor(readonly database: string) {\n\t\tsuper(\n\t\t\t`Refusing to drop '${database}': only the test stage's databases (named ` +\n\t\t\t\t`'…_${TEST_STAGE}') are dropped after a suite. Delete ` +\n\t\t\t\t`${TEST_READY_FILE} if it was edited by hand.`,\n\t\t);\n\t\tthis.name = 'NotATestDatabase';\n\t}\n}\n","import { spawn } from 'node:child_process';\nimport { writeFile } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nimport { loadWorkspaceConfig } from '../config';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { sniffAppEnvironment } from '../deploy/sniffer';\nimport { primaryPortKey } from '../reconcile/containers';\nimport type { ReconcileResult } from '../reconcile/index.js';\nimport { postgresDatabaseNames } from '../reconcile/provision.js';\nimport { backendsOf, constructGlobs } from '../reconcile/workspace.js';\nimport { TEST_STAGE } from '../workspace/stages';\nimport {\n\tDEFAULT_FACTORIES_DIR,\n\tTEST_MANIFEST_ENV,\n\twriteTestHarness,\n} from './harness';\nimport { TEST_READY_ENV, TEST_READY_FILE, type TestReady } from './ready';\nimport { dropTestDatabases } from './teardown';\n\nexport interface TestOptions {\n\t/** Stage to load secrets from (default: development) */\n\tstage?: string;\n\t/** Run tests once without watch mode */\n\trun?: boolean;\n\t/** Enable watch mode */\n\twatch?: boolean;\n\t/** Generate coverage report */\n\tcoverage?: boolean;\n\t/** Open Vitest UI */\n\tui?: boolean;\n\t/** Pattern to filter tests */\n\tpattern?: string;\n\t/**\n\t * Generate a fresh stage (secrets + encryption key) from the workspace config\n\t * when none exists, instead of requiring committed secrets / a shared key.\n\t * Intended for CI. Also enabled by the GKM_AUTO_SETUP env var.\n\t */\n\tautoSetup?: boolean;\n\t/**\n\t * Write the test manifest and the harness generated from it, then stop —\n\t * no containers started, no suite run. What typechecking a suite needs:\n\t * `#test` is generated, so a typecheck that runs before `gkm test` has\n\t * nothing to resolve it to without this.\n\t */\n\tprepare?: boolean;\n\t/**\n\t * Everything the suite needs, then stop: the stage reconciled, its\n\t * databases migrated, the harness and credentials written. What the Vitest\n\t * global setup (`@geekmidas/cli/vitest`) runs, so a suite started by plain\n\t * `vitest` — or an editor — gets the same stage `gkm test` would give it.\n\t */\n\tsetup?: boolean;\n\t/**\n\t * Drop the test stage's databases the last setup created, then stop — what\n\t * the Vitest global setup's teardown runs when the suite ends.\n\t */\n\tteardown?: boolean;\n}\n\n/**\n * Run tests with secrets, dependency URLs, and .env files loaded.\n * Environment variables are sniffed to inject only what the app needs.\n */\nexport async function testCommand(options: TestOptions = {}): Promise<void> {\n\tconst cwd = process.cwd();\n\t// The project's local stage unless one was named: \\`gkm test\\` reads the\n\t// secrets a developer's own \\`gkm dev\\` does.\n\tconst stage =\n\t\toptions.stage ??\n\t\t(await loadWorkspaceConfig(cwd)\n\t\t\t.then((loaded) => loaded.workspace.stages.local)\n\t\t\t.catch(() => undefined));\n\tif (options.teardown) {\n\t\tawait teardown(cwd);\n\t\treturn;\n\t}\n\n\tif (!stage) {\n\t\tthrow new NoStageToTest();\n\t}\n\n\tconsole.log(`\\n🧪 Running tests with ${stage} environment...\\n`);\n\n\t// 0. Auto-setup (CI): regenerate a fresh stage from the workspace config when\n\t// none exists, so tests run without committed secrets or a shared key.\n\tconst autoSetup = options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP);\n\tif (autoSetup) {\n\t\tconst { ensureStageSecrets } = await import('../setup/index.js');\n\t\tconst generated = await ensureStageSecrets(stage, cwd);\n\t\tif (generated) {\n\t\t\tconsole.log(` 🔐 Generated fresh ${stage} secrets (auto-setup)`);\n\t\t}\n\t}\n\n\t// 1. Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tconsole.log(` 📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// A run killed before its teardown left its databases behind, migrated —\n\t// so an edited migration would not run again. Dropped before reconciling,\n\t// which then creates them afresh.\n\tif (!options.prepare) {\n\t\tawait teardown(cwd);\n\t}\n\n\t// 2. Prepare credentials: loads secrets and reconciles the test stage —\n\t// starts its containers and resolves every declared address\n\tconst result = await prepareEntryCredentials({\n\t\tstage,\n\t\t// Preparing writes files; it has no suite to start containers for.\n\t\tstartDocker: !options.prepare,\n\t\tsecretsFileName: 'test-secrets.json',\n\t\t// The same reconcile `gkm dev` runs, differing only in what the resources\n\t\t// are called: one container and one role pair serve both stages, so the\n\t\t// suffix is the whole of the isolation.\n\t\treconcileStage: 'test',\n\t});\n\n\tlet finalCredentials = { ...result.credentials };\n\n\t// 3. Sniff env vars to filter only what the app needs (workspace only)\n\tif (result.appInfo) {\n\t\tconst sniffed = await sniffAppEnvironment(\n\t\t\tresult.appInfo.app,\n\t\t\tresult.appInfo.appName,\n\t\t\tresult.appInfo.workspaceRoot,\n\t\t\t{ logWarnings: false },\n\t\t);\n\n\t\tif (sniffed.requiredEnvVars.length > 0) {\n\t\t\t// Sniffed *plus* declared. A construct reads its own key inside\n\t\t\t// `@geekmidas/constructs` rather than in application code, so a walk of\n\t\t\t// the app finds no `get('MAIL_URL')` and sniffing alone reports it as\n\t\t\t// unneeded — which is how a suite that resolved 25 declared URLs\n\t\t\t// started with 13 and failed on the first construct to look for one of\n\t\t\t// the other 12.\n\t\t\tconst needed = new Set([\n\t\t\t\t...sniffed.requiredEnvVars,\n\t\t\t\t...result.declaredKeys,\n\t\t\t]);\n\t\t\tconst filtered: Record<string, string> = {};\n\t\t\tfor (const [key, value] of Object.entries(finalCredentials)) {\n\t\t\t\tif (needed.has(key)) {\n\t\t\t\t\tfiltered[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinalCredentials = filtered;\n\t\t\tconsole.log(\n\t\t\t\t` 🔍 Sniffed ${sniffed.requiredEnvVars.length} required env var(s)` +\n\t\t\t\t\t(result.declaredKeys.length > 0\n\t\t\t\t\t\t? `, kept ${result.declaredKeys.length} declared`\n\t\t\t\t\t\t: ''),\n\t\t\t);\n\t\t}\n\t}\n\n\tconsole.log('');\n\n\t// 4. Write final credentials and create preload script\n\tawait writeFile(\n\t\tresult.secretsJsonPath,\n\t\tJSON.stringify(finalCredentials, null, 2),\n\t);\n\n\tconst gkmDir = join(cwd, '.gkm');\n\tconst preloadPath = join(gkmDir, 'test-credentials-preload.ts');\n\tawait createCredentialsPreload(preloadPath, result.secretsJsonPath);\n\n\t// 5. The test manifest: what was discovered and resolved above, kept for the\n\t// suite, so a feature test is built from it rather than declaring it all\n\t// again — and the harness generated from it, `it` and a `Browser` with a\n\t// typed client per surface.\n\tconst workspace = await loadWorkspaceConfig(cwd)\n\t\t.then((loaded) => loaded.workspace)\n\t\t.catch(() => undefined);\n\tconst manifestPath = workspace\n\t\t? await writeTestHarness({\n\t\t\t\troot: workspace.root,\n\t\t\t\ttargets: [\n\t\t\t\t\tworkspace.root,\n\t\t\t\t\t...Object.values(workspace.apps).map((app) =>\n\t\t\t\t\t\tisAbsolute(app.path) ? app.path : join(workspace.root, app.path),\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t\tpatterns: constructGlobs(workspace),\n\t\t\t\tcacheBackend: backendsOf(workspace).cache,\n\t\t\t\teventsBackend: backendsOf(workspace).events,\n\t\t\t\tstage: TEST_STAGE,\n\t\t\t\tenv: finalCredentials,\n\t\t\t\tfactories: join(\n\t\t\t\t\tworkspace.root,\n\t\t\t\t\tworkspace.test.factories ?? DEFAULT_FACTORIES_DIR,\n\t\t\t\t),\n\t\t\t})\n\t\t: undefined;\n\n\tif (options.prepare) {\n\t\tconsole.log(\n\t\t\tmanifestPath\n\t\t\t\t? ` 🧪 Test harness written beside ${manifestPath}`\n\t\t\t\t: ' 🧪 Nothing to prepare: this project declares no constructs',\n\t\t);\n\t\treturn;\n\t}\n\n\t// 6. The databases, migrated and seeded — once, here, for every construct,\n\t// before any project's tests start. Not a Vitest `globalSetup` per\n\t// project: one of those runs only when its project has a matching test,\n\t// and two of them run twice.\n\tif (workspace) {\n\t\tawait migrateTestStage(workspace, result.credentials);\n\t}\n\n\t// What the Vitest global setup loads, and how it knows this run already did\n\t// its work.\n\tconst readyPath = join(cwd, TEST_READY_FILE);\n\tawait writeFile(\n\t\treadyPath,\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tenv: result.secretsJsonPath,\n\t\t\t\t...(manifestPath ? { manifest: manifestPath } : {}),\n\t\t\t\t...testDatabases(result.reconciled),\n\t\t\t} satisfies TestReady,\n\t\t\tnull,\n\t\t\t2,\n\t\t),\n\t);\n\n\tif (options.setup) {\n\t\tconsole.log(` 🧪 Test stage ready: ${TEST_READY_FILE}`);\n\t\treturn;\n\t}\n\n\t// Merge NODE_OPTIONS with existing value (if any)\n\tconst existingNodeOptions = process.env.NODE_OPTIONS ?? '';\n\tconst tsxImport = '--import=tsx';\n\tconst preloadImport = `--import=${preloadPath}`;\n\tconst nodeOptions = [existingNodeOptions, tsxImport, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Build vitest args\n\tconst args: string[] = [];\n\n\tif (options.run) {\n\t\targs.push('run');\n\t} else if (options.watch) {\n\t\targs.push('--watch');\n\t}\n\n\tif (options.coverage) {\n\t\targs.push('--coverage');\n\t}\n\n\tif (options.ui) {\n\t\targs.push('--ui');\n\t}\n\n\tif (options.pattern) {\n\t\targs.push(options.pattern);\n\t}\n\n\t// Run vitest with combined environment and credentials preload\n\tconst vitestProcess = spawn('npx', ['vitest', ...args], {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...finalCredentials,\n\t\t\t...(manifestPath ? { [TEST_MANIFEST_ENV]: manifestPath } : {}),\n\t\t\t[TEST_READY_ENV]: readyPath,\n\t\t\tNODE_ENV: 'test',\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for vitest to complete\n\treturn new Promise((resolve, reject) => {\n\t\tvitestProcess.on('close', (code) => {\n\t\t\tif (code === 0) {\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(new Error(`Tests failed with exit code ${code}`));\n\t\t\t}\n\t\t});\n\n\t\tvitestProcess.on('error', (error) => {\n\t\t\treject(error);\n\t\t});\n\t});\n}\n\n/** Drop what the last setup created — see `dropTestDatabases`. */\nasync function teardown(cwd: string): Promise<void> {\n\tconst root = await loadWorkspaceConfig(cwd)\n\t\t.then((loaded) => loaded.workspace.root)\n\t\t.catch(() => cwd);\n\tconst dropped = await dropTestDatabases(cwd, root);\n\tif (dropped.length > 0) {\n\t\tconsole.log(` 🧹 Dropped ${dropped.join(', ')}`);\n\t}\n}\n\n/**\n * The test stage's Postgres databases, to drop when the suite ends — those\n * the plan provisions, on the port the shared container answers.\n */\nfunction testDatabases(\n\treconciled: ReconcileResult | undefined,\n): Pick<TestReady, 'databases'> {\n\tconst port = reconciled?.ports[primaryPortKey('postgres')];\n\tconst names = reconciled ? postgresDatabaseNames(reconciled.plan) : [];\n\treturn port !== undefined && names.length > 0\n\t\t? { databases: { port, names } }\n\t\t: {};\n}\n\n/**\n * Migrate the test stage just reconciled, then seed it: a test run never\n * starts without the reference data the app needs.\n */\nasync function migrateTestStage(\n\tworkspace: NonNullable<\n\t\tAwaited<ReturnType<typeof loadWorkspaceConfig>>['workspace']\n\t>,\n\tenv: Readonly<Record<string, string>>,\n): Promise<void> {\n\tconst { migrateAndSeed } = await import('../migrate/index.js');\n\tconst { discover } = await import('../reconcile/discover.js');\n\n\tconst sources = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: workspace.root,\n\t\tsources,\n\t});\n\n\tconst { migrations, seeds } = await migrateAndSeed({\n\t\troot: workspace.root,\n\t\tmanifest,\n\t\tsources,\n\t\tenv,\n\t\tstage: TEST_STAGE,\n\t});\n\n\tfor (const { target, applied } of migrations) {\n\t\tif (applied.length > 0) {\n\t\t\tconsole.log(` 🗄️ ${target.migrations}: applied ${applied.join(', ')}`);\n\t\t}\n\t}\n\tfor (const { target, seeded } of seeds) {\n\t\tif (seeded.length > 0) {\n\t\t\tconsole.log(` 🌱 ${target.seeds}: ran ${seeded.join(', ')}`);\n\t\t}\n\t}\n}\n\n/** `gkm test` outside a project that declares stages, with none named. */\nexport class NoStageToTest extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'No stage to test with: add `stages` to gkm.config.ts, or pass --stage.',\n\t\t);\n\t\tthis.name = 'NoStageToTest';\n\t}\n}\n","/**\n * Just enough semver for `gkm upgrade`: ordering versions, and reading the\n * floor out of a simple range. The same ordering the release pipeline uses to\n * decide what is published (`scripts/release-state.mjs`).\n */\n\nconst VERSION = /(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\ninterface Parsed {\n\tcore: [number, number, number];\n\tids: (string | number)[];\n}\n\nfunction parse(version: string): Parsed | undefined {\n\tconst match = version.match(VERSION);\n\tif (!match) return undefined;\n\tconst [, major, minor, patch, pre] = match;\n\treturn {\n\t\tcore: [Number(major), Number(minor), Number(patch)],\n\t\tids: pre\n\t\t\t? pre.split('.').map((id) => (/^\\d+$/.test(id) ? Number(id) : id))\n\t\t\t: [],\n\t};\n}\n\n/** Negative, zero or positive, as `a` is below, equal to or above `b`. */\nexport function compareVersions(a: string, b: string): number {\n\tconst x = parse(a);\n\tconst y = parse(b);\n\tif (!x || !y) return 0;\n\n\tfor (let i = 0; i < 3; i++) {\n\t\tif (x.core[i] !== y.core[i]) return x.core[i]! - y.core[i]!;\n\t}\n\t// A release outranks any prerelease of the same version.\n\tif (!x.ids.length || !y.ids.length) return y.ids.length - x.ids.length;\n\tfor (let i = 0; i < Math.max(x.ids.length, y.ids.length); i++) {\n\t\tconst p = x.ids[i];\n\t\tconst q = y.ids[i];\n\t\tif (p === undefined) return -1;\n\t\tif (q === undefined) return 1;\n\t\tif (p === q) continue;\n\t\tif (typeof p === 'number' && typeof q === 'number') return p - q;\n\t\tif (typeof p === 'number') return -1;\n\t\tif (typeof q === 'number') return 1;\n\t\treturn p < q ? -1 : 1;\n\t}\n\treturn 0;\n}\n\n/** `alpha` for `10.0.0-alpha.6`; undefined for a release. */\nexport function prereleaseTag(version: string): string | undefined {\n\tconst id = parse(version)?.ids[0];\n\treturn typeof id === 'string' ? id : undefined;\n}\n\n/**\n * A range that is one operator and one version — `~1.2.3`, `^1.2.3`, `>=1.2.3`,\n * `1.2.3` — split into the two. Anything else (`>=8 <10`, `a || b`) is not\n * something to rewrite mechanically.\n */\nexport function simpleRange(\n\trange: string,\n): { operator: string; version: string } | undefined {\n\tconst match = range\n\t\t.trim()\n\t\t.match(/^(\\^|~|>=|)v?(\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?)$/);\n\treturn match ? { operator: match[1]!, version: match[2]! } : undefined;\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { parseDocument } from 'yaml';\nimport {\n\tdetectPackageManager,\n\tfindWorkspacePackages,\n\tfindWorkspaceRoot,\n\tgetInstallCommand,\n\ttype PackageManager,\n} from '../init/utils.js';\nimport { compareVersions, prereleaseTag, simpleRange } from './version.js';\n\nconst logger = console;\n\nconst SCOPE = '@geekmidas/';\nconst DEP_FIELDS = [\n\t'dependencies',\n\t'devDependencies',\n\t'peerDependencies',\n\t'optionalDependencies',\n] as const;\ntype DepField = (typeof DEP_FIELDS)[number];\n\nexport interface UpgradeOptions {\n\tdryRun?: boolean;\n\t/**\n\t * Every `@geekmidas` package, and the third-party packages their peer ranges\n\t * require. Without it only `@geekmidas/cli` moves — upgrade the CLI first,\n\t * then let the new one run `upgrade --all`, since it is the one that knows\n\t * what the new versions need.\n\t */\n\tall?: boolean;\n\t/** The npm dist-tag to follow. Default: the line the project is on. */\n\ttag?: string;\n}\n\n/** One dependency range, and where it is written. */\ninterface Occurrence {\n\tname: string;\n\trange: string;\n\t/** A package.json path, or `catalog` for pnpm-workspace.yaml. */\n\tfile: string;\n\tfield: DepField | 'catalog';\n\t/** For a named pnpm catalog. */\n\tcatalog?: string;\n}\n\ninterface Change extends Occurrence {\n\tnext: string;\n}\n\n/** The abbreviated npm document: dist-tags, and each version's peers. */\ninterface Packument {\n\t'dist-tags': Record<string, string>;\n\tversions: Record<\n\t\tstring,\n\t\t{ peerDependencies?: Record<string, string> } | undefined\n\t>;\n}\n\nasync function packument(name: string): Promise<Packument> {\n\tconst res = await fetch(\n\t\t`https://registry.npmjs.org/${name.replace('/', '%2F')}`,\n\t\t{ headers: { accept: 'application/vnd.npm.install-v1+json' } },\n\t);\n\tif (!res.ok) throw new RegistryUnavailable(name, res.status);\n\treturn (await res.json()) as Packument;\n}\n\n/** Every registry range in the workspace's package.json files. */\nfunction packageOccurrences(paths: string[]): Occurrence[] {\n\tconst found: Occurrence[] = [];\n\tfor (const file of paths) {\n\t\tconst pkg = JSON.parse(readFileSync(file, 'utf-8'));\n\t\tfor (const field of DEP_FIELDS) {\n\t\t\tfor (const [name, range] of Object.entries(pkg[field] ?? {})) {\n\t\t\t\tfound.push({ name, range: range as string, file, field });\n\t\t\t}\n\t\t}\n\t}\n\treturn found;\n}\n\n/** pnpm catalog entries, which is where `catalog:` references resolve. */\nfunction catalogOccurrences(root: string): Occurrence[] {\n\tconst file = join(root, 'pnpm-workspace.yaml');\n\tif (!existsSync(file)) return [];\n\n\tconst doc = parseDocument(readFileSync(file, 'utf-8')).toJS() ?? {};\n\tconst found: Occurrence[] = [];\n\tfor (const [name, range] of Object.entries(doc.catalog ?? {})) {\n\t\tfound.push({ name, range: String(range), file, field: 'catalog' });\n\t}\n\tfor (const [catalog, entries] of Object.entries(doc.catalogs ?? {})) {\n\t\tfor (const [name, range] of Object.entries(entries ?? {})) {\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\trange: String(range),\n\t\t\t\tfile,\n\t\t\t\tfield: 'catalog',\n\t\t\t\tcatalog,\n\t\t\t});\n\t\t}\n\t}\n\treturn found;\n}\n\n/** Not a registry range: resolved elsewhere, so not ours to move. */\nconst isIndirect = (range: string) =>\n\t/^(workspace|catalog|link|file|npm|git|github|https?):/.test(range);\n\n/**\n * The version every `@geekmidas` package moves to.\n *\n * All of them share one version, so the CLI's line answers for the rest. The\n * tag is the one the project is already on — a project on `10.0.0-alpha.6`\n * follows `alpha` — because `latest` names a different major while a new one\n * is in prerelease, and following it would move the project backwards.\n */\nexport function resolveTarget(\n\tdistTags: Record<string, string>,\n\tinstalled: string[],\n\ttag?: string,\n): { tag: string; version: string } {\n\tconst highest = [...installed].sort(compareVersions).at(-1);\n\tconst chosen = tag ?? (highest && prereleaseTag(highest)) ?? 'latest';\n\tconst version = distTags[chosen];\n\tif (!version) {\n\t\tthrow new NoReleaseOnTag(chosen, Object.keys(distTags));\n\t}\n\treturn { tag: chosen, version };\n}\n\n/** The same operator on the new version — `^`, `~`, `>=` or none, as written. */\nfunction withVersion(range: string, version: string): string {\n\treturn `${simpleRange(range)?.operator ?? ''}${version}`;\n}\n\nexport async function upgradeCommand(\n\toptions: UpgradeOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst pm = detectPackageManager(cwd);\n\tconst root = findWorkspaceRoot(cwd, pm);\n\n\tlogger.log('\\n📦 Scanning workspace for @geekmidas packages...\\n');\n\tlogger.log(` Package manager: ${pm}`);\n\n\tconst packageJsons = findWorkspacePackages(cwd, pm);\n\tconst occurrences = [\n\t\t...packageOccurrences(packageJsons),\n\t\t...catalogOccurrences(root),\n\t];\n\tlogger.log(` Found ${packageJsons.length} package(s) in workspace\\n`);\n\n\tconst ours = occurrences.filter(\n\t\t(o) => o.name.startsWith(SCOPE) && !isIndirect(o.range),\n\t);\n\tif (ours.length === 0) {\n\t\tlogger.log(' No @geekmidas packages found.\\n');\n\t\treturn;\n\t}\n\n\tconst installed = ours\n\t\t.map((o) => simpleRange(o.range)?.version)\n\t\t.filter((v): v is string => Boolean(v));\n\n\tconst cli = await packument(`${SCOPE}cli`);\n\tconst target = resolveTarget(cli['dist-tags'], installed, options.tag);\n\tlogger.log(` Target: ${target.version} (npm \"${target.tag}\")\\n`);\n\n\t// Never backwards: a project ahead of the tag it follows keeps its version.\n\tconst highest = installed.sort(compareVersions).at(-1)!;\n\tif (compareVersions(target.version, highest) < 0) {\n\t\tthrow new WouldDowngrade(highest, target.tag, target.version);\n\t}\n\n\tconst moving = options.all\n\t\t? ours\n\t\t: ours.filter((o) => o.name === `${SCOPE}cli`);\n\n\tconst changes: Change[] = [];\n\tfor (const o of moving) {\n\t\t// A range like `>=8 <10` says something on purpose; it is reported for a\n\t\t// person to widen rather than flattened to one version.\n\t\tif (!simpleRange(o.range)) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ ${o.name} ${o.range} is not a simple range; left as is (target ${target.version}).`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst next = withVersion(o.range, target.version);\n\t\tif (next !== o.range) changes.push({ ...o, next });\n\t}\n\n\tif (options.all) {\n\t\tchanges.push(...(await peerChanges(occurrences, ours, target.version)));\n\t}\n\n\tif (changes.length === 0) {\n\t\tlogger.log(' Everything is already on the target version.\\n');\n\t\treturn;\n\t}\n\n\tprintChanges(changes, root);\n\n\tif (!options.all && ours.some((o) => o.name !== `${SCOPE}cli`)) {\n\t\tlogger.log(\n\t\t\t'\\n Only @geekmidas/cli moves without --all. Afterwards, run `gkm upgrade --all` with the new CLI.',\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: no changes made.\\n');\n\t\treturn;\n\t}\n\n\tapplyChanges(changes);\n\tinstall(pm, root);\n\tlogger.log('\\n ✅ Upgrade complete. Run your tests to verify.\\n');\n}\n\n/**\n * Third-party packages the project already lists, raised to the floor of the\n * peer range the target `@geekmidas` versions declare.\n *\n * Only raised, never lowered, and only where both the peer range and the\n * project's range are one operator and one version; anything else is reported\n * for a person to decide.\n */\nasync function peerChanges(\n\toccurrences: Occurrence[],\n\tours: Occurrence[],\n\tversion: string,\n): Promise<Change[]> {\n\tconst floors = new Map<string, string>();\n\tconst names = [...new Set(ours.map((o) => o.name))];\n\tconst docs = await Promise.all(names.map(packument));\n\n\tfor (const doc of docs) {\n\t\tconst peers = doc.versions[version]?.peerDependencies ?? {};\n\t\tfor (const [peer, range] of Object.entries(peers)) {\n\t\t\tif (peer.startsWith(SCOPE)) continue;\n\t\t\tconst floor = simpleRange(range)?.version;\n\t\t\tif (!floor) continue;\n\t\t\tconst known = floors.get(peer);\n\t\t\tif (!known || compareVersions(floor, known) > 0) floors.set(peer, floor);\n\t\t}\n\t}\n\n\tconst changes: Change[] = [];\n\tfor (const o of occurrences) {\n\t\tconst floor = floors.get(o.name);\n\t\tif (!floor || isIndirect(o.range) || o.field === 'peerDependencies') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = simpleRange(o.range);\n\t\tif (!current) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ ${o.name} ${o.range} is not a simple range; @geekmidas needs at least ${floor}.`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tif (compareVersions(current.version, floor) < 0) {\n\t\t\tchanges.push({ ...o, next: withVersion(o.range, floor) });\n\t\t}\n\t}\n\treturn changes;\n}\n\nfunction printChanges(changes: Change[], root: string): void {\n\tlogger.log(' Changes:\\n');\n\tfor (const c of changes) {\n\t\tconst where =\n\t\t\tc.field === 'catalog'\n\t\t\t\t? `pnpm-workspace.yaml (${c.catalog ? `catalogs.${c.catalog}` : 'catalog'})`\n\t\t\t\t: `${relative(root, c.file) || 'package.json'} (${c.field})`;\n\t\tlogger.log(` ${c.name.padEnd(34)} ${c.range} → ${c.next} ${where}`);\n\t}\n}\n\nfunction applyChanges(changes: Change[]): void {\n\tconst byFile = new Map<string, Change[]>();\n\tfor (const c of changes) {\n\t\tbyFile.set(c.file, [...(byFile.get(c.file) ?? []), c]);\n\t}\n\n\tfor (const [file, fileChanges] of byFile) {\n\t\tconst text = readFileSync(file, 'utf-8');\n\t\tif (file.endsWith('.yaml')) {\n\t\t\t// Through the document, so comments and layout survive.\n\t\t\tconst doc = parseDocument(text);\n\t\t\tfor (const c of fileChanges) {\n\t\t\t\tconst path = c.catalog\n\t\t\t\t\t? ['catalogs', c.catalog, c.name]\n\t\t\t\t\t: ['catalog', c.name];\n\t\t\t\tdoc.setIn(path, c.next);\n\t\t\t}\n\t\t\twriteFileSync(file, doc.toString());\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst pkg = JSON.parse(text);\n\t\tfor (const c of fileChanges) pkg[c.field][c.name] = c.next;\n\t\tconst indent = text.match(/^[ \\t]+(?=\")/m)?.[0] ?? ' ';\n\t\twriteFileSync(file, `${JSON.stringify(pkg, null, indent)}\\n`);\n\t}\n}\n\nfunction install(pm: PackageManager, cwd: string): void {\n\tconst command = getInstallCommand(pm);\n\tlogger.log(`\\n Running: ${command}\\n`);\n\ttry {\n\t\texecSync(command, { cwd, stdio: 'inherit', timeout: 300_000 });\n\t} catch {\n\t\tthrow new InstallFailed(command);\n\t}\n}\n\n/** npm did not answer for a package, so there is no version to compare. */\nexport class RegistryUnavailable extends Error {\n\tconstructor(\n\t\t// Not `name`: that is Error's own, and holds the class name.\n\t\treadonly packageName: string,\n\t\treadonly status: number,\n\t) {\n\t\tsuper(\n\t\t\t`npm answered ${status} for ${packageName}. Check the name and your network.`,\n\t\t);\n\t\tthis.name = 'RegistryUnavailable';\n\t}\n}\n\n/** A dist-tag npm does not have, e.g. `--tag beta` before any beta. */\nexport class NoReleaseOnTag extends Error {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly tags: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`npm has no \"${tag}\" release of @geekmidas/cli. Tags: ${tags.join(', ')}.`,\n\t\t);\n\t\tthis.name = 'NoReleaseOnTag';\n\t}\n}\n\n/** The line asked for is behind what is installed; upgrade never goes back. */\nexport class WouldDowngrade extends Error {\n\tconstructor(\n\t\treadonly installed: string,\n\t\treadonly tag: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`The project is already on ${installed}, ahead of npm's \"${tag}\" (${target}). Pass --tag to follow another line.`,\n\t\t);\n\t\tthis.name = 'WouldDowngrade';\n\t}\n}\n\n/** The install after rewriting versions failed; its own output says why. */\nexport class InstallFailed extends Error {\n\tconstructor(readonly command: string) {\n\t\tsuper(`\\`${command}\\` failed. Check the output above for details.`);\n\t\tthis.name = 'InstallFailed';\n\t}\n}\n","#!/usr/bin/env -S npx tsx\n\nimport { resolve } from 'node:path';\nimport { Command, Option } from 'commander';\nimport pkg from '../package.json';\nimport { loginCommand, logoutCommand, whoamiCommand } from './auth';\nimport {\n\tbuildCommand,\n\tisMainProvider,\n\tUnknownBuildProvider,\n\tUnknownCacheBackend,\n} from './build/index';\nimport { type ComposeOptions, composeCommand } from './compose/index';\nimport { enableDebug, formatError } from './debug';\nimport { deployInitCommand, deployListCommand } from './deploy/init';\nimport {\n\tstateDiffCommand,\n\tstatePullCommand,\n\tstatePushCommand,\n\tstateShowCommand,\n\tstateUnlockCommand,\n} from './deploy/state-commands';\nimport { devCommand, execCommand } from './dev/index';\nimport { type DockerOptions, dockerCommand } from './docker/index';\nimport { type InitOptions, initCommand } from './init/index';\nimport { openapiCommand } from './openapi';\nimport {\n\tsecretsImportCommand,\n\tsecretsInitCommand,\n\tsecretsRotateCommand,\n\tsecretsSetCommand,\n\tsecretsShowCommand,\n} from './secrets';\nimport type { SecretServiceName } from './secrets/types';\nimport { type SetupOptions, setupCommand } from './setup/index';\nimport { type TestOptions, testCommand } from './test/index';\nimport { trustCommand } from './trust/index';\nimport { isCacheBackend } from './types';\nimport { type UpgradeOptions, upgradeCommand } from './upgrade/index';\n\nconst program = new Command();\n\nprogram\n\t.name('gkm')\n\t.description('GeekMidas backend framework CLI')\n\t.version(pkg.version)\n\t.option('--cwd <path>', 'Change working directory')\n\t.option('--debug', 'Enable debug mode (verbose errors with stack traces)')\n\t.hook('preAction', () => {\n\t\tconst opts = program.opts();\n\t\tif (opts.debug) enableDebug();\n\t});\n\nprogram\n\t.command('init')\n\t.description('Scaffold a new project')\n\t.argument('[name]', 'Project name')\n\t.option(\n\t\t'--template <template>',\n\t\t'Project template (minimal, api, serverless, worker)',\n\t)\n\t.option('--skip-install', 'Skip dependency installation', false)\n\t.option('-y, --yes', 'Skip prompts, use defaults', false)\n\t.option('--monorepo', 'Setup as monorepo with packages/models', false)\n\t.option('--api-path <path>', 'API app path in monorepo (default: apps/api)')\n\t.option('--pm <manager>', 'Package manager (pnpm, npm, yarn, bun)')\n\t.option('--deploy <target>', 'Where it deploys (dokploy, sst, none)')\n\t.option('--region <region>', 'AWS region for an SST deploy (e.g. eu-west-1)')\n\t.option(\n\t\t'--stages <names>',\n\t\t'Deployed stages, comma-separated (e.g. staging,prod)',\n\t)\n\t.option('--protected-stage <name>', 'Which deployed stage is production')\n\t.option('--local-stage <name>', 'What gkm dev runs as (e.g. dev)')\n\t.action(async (name: string | undefined, options: InitOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait initCommand(name, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('trust')\n\t.description(\n\t\t\"Trust the local edge's certificate authority, so a browser accepts https\",\n\t)\n\t.option('--dry-run', 'Print the commands instead of running them')\n\t.action(async (options: { dryRun?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait trustCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('setup')\n\t.description(\n\t\t'Reconcile declared constructs — containers, databases, buckets, secrets',\n\t)\n\t.option('--stage <stage>', 'Stage name (default: stages.local)')\n\t.option('--force', 'Regenerate secrets even if they exist')\n\t.option('--skip-docker', 'Skip starting Docker services')\n\t.option('-y, --yes', 'Skip prompts')\n\t.action(async (options: SetupOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait setupCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('build')\n\t.description('Build handlers and the manifest from declared constructs')\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Build for aws or server (default: where gkm.config.ts deploys)',\n\t)\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation generation for server builds',\n\t)\n\t.option('--production', 'Build for production (no dev tools, bundled output)')\n\t.option('--skip-bundle', 'Skip bundling step in production build')\n\t.option('--stage <stage>', 'Inject encrypted secrets for deployment stage')\n\t.option(\n\t\t'--mark-optional',\n\t\t'Suffix optional env vars with ? in manifest envVars field (e.g. PORT?)',\n\t)\n\t// Written by the Dockerfiles `gkm compose` generates, whose stack runs its\n\t// own Redis: not a choice a project makes, so not in the help.\n\t.addOption(\n\t\tnew Option(\n\t\t\t'--cache <backend>',\n\t\t\t'Register the drivers for this cache backend rather than the target default',\n\t\t).hideHelp(),\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider?: string;\n\t\t\tcache?: string;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tproduction?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tstage?: string;\n\t\t\tmarkOptional?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\toptions.provider !== undefined &&\n\t\t\t\t\t!isMainProvider(options.provider)\n\t\t\t\t) {\n\t\t\t\t\tthrow new UnknownBuildProvider(options.provider);\n\t\t\t\t}\n\t\t\t\tif (options.cache !== undefined && !isCacheBackend(options.cache)) {\n\t\t\t\t\tthrow new UnknownCacheBackend(options.cache);\n\t\t\t\t}\n\n\t\t\t\tawait buildCommand({\n\t\t\t\t\t...(options.provider ? { provider: options.provider } : {}),\n\t\t\t\t\t...(options.cache ? { cache: options.cache } : {}),\n\t\t\t\t\tenableOpenApi: options.enableOpenapi || false,\n\t\t\t\t\tproduction: options.production || false,\n\t\t\t\t\tskipBundle: options.skipBundle || false,\n\t\t\t\t\tstage: options.stage,\n\t\t\t\t\tmarkOptional: options.markOptional || false,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('dev')\n\t.description(\n\t\t'Reconcile constructs and start the dev server with automatic reload',\n\t)\n\t.option('-p, --port <port>', 'Port to run the development server on')\n\t.option('--entry <file>', 'Entry file to run (bypasses gkm config)')\n\t.option('--watch', 'Watch for file changes (default: true with --entry)')\n\t.option('--no-watch', 'Disable file watching')\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation for development server',\n\t\ttrue,\n\t)\n\t.option('--migrate', 'Apply pending migrations before the apps start')\n\t.option('--seed', 'Migrate, then run the seeds, before the apps start')\n\t.option(\n\t\t'--fake',\n\t\t'Call each external API’s fake (test/fakes/<id>.ts) instead of the provider',\n\t)\n\t.option(\n\t\t'--no-subscribers',\n\t\t'Run no topic subscribers: nothing is subscribed, polled or pushed to',\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tport?: string;\n\t\t\tentry?: string;\n\t\t\twatch?: boolean;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tmigrate?: boolean;\n\t\t\tseed?: boolean;\n\t\t\tfake?: boolean;\n\t\t\tsubscribers?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait devCommand({\n\t\t\t\t\t// Unset without `--port`, so an app in a workspace gets the port the\n\t\t\t\t\t// workspace gave it. Defaulting to 3000 here meant every app asked\n\t\t\t\t\t// for 3000, and the first to start took it from the others.\n\t\t\t\t\tport: options.port ? Number.parseInt(options.port, 10) : undefined,\n\t\t\t\t\tportExplicit: !!options.port,\n\t\t\t\t\tenableOpenApi: options.enableOpenapi ?? true,\n\t\t\t\t\tentry: options.entry,\n\t\t\t\t\twatch: options.watch,\n\t\t\t\t\tmigrate: options.migrate,\n\t\t\t\t\tseed: options.seed,\n\t\t\t\t\tfake: options.fake,\n\t\t\t\t\tsubscribers: options.subscribers,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('exec')\n\t.description('Run a command with secrets injected into Credentials')\n\t.argument('<command...>', 'Command to run (use -- before command)')\n\t.action(async (commandArgs: string[]) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait execCommand(commandArgs);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('test')\n\t.description('Run tests with secrets loaded from environment')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'Stage to load secrets from (default: stages.local)',\n\t)\n\t.option('--run', 'Run tests once without watch mode')\n\t.option('--watch', 'Enable watch mode')\n\t.option('--coverage', 'Generate coverage report')\n\t.option('--ui', 'Open Vitest UI')\n\t.option(\n\t\t'--auto-setup',\n\t\t'Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)',\n\t)\n\t.option(\n\t\t'--prepare',\n\t\t'Write the test manifest and #test harness, then stop — for a typecheck that runs before the suite',\n\t)\n\t.option(\n\t\t'--setup',\n\t\t'Reconcile, migrate and seed the test stage and write the harness, then stop — what @geekmidas/cli/vitest runs',\n\t)\n\t.option(\n\t\t'--teardown',\n\t\t\"Drop the test stage's databases the last setup created, then stop — what @geekmidas/cli/vitest runs when the suite ends\",\n\t)\n\t.argument('[pattern]', 'Pattern to filter tests')\n\t.action(async (pattern: string | undefined, options: TestOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait testCommand({ ...options, pattern });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('migrate')\n\t.description(\n\t\t\"Apply each database construct's migrations from db/<construct>/migrations/, as its owner\",\n\t)\n\t.argument('[construct]', 'Only this construct, by name')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'The local stage (default) or test — a deploy migrates its own stage',\n\t)\n\t.action(\n\t\tasync (construct: string | undefined, options: { stage?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { migrateCommand } = await import('./migrate/index.js');\n\t\t\t\tawait migrateCommand({\n\t\t\t\t\t...options,\n\t\t\t\t\t...(construct ? { construct } : {}),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('seed')\n\t.description(\n\t\t\"Migrate, then run each database construct's seeds from db/<construct>/seeds/, as its owner\",\n\t)\n\t.argument('[construct]', 'Only this construct, by name')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'The local stage (default) or test — a deploy seeds its own stage',\n\t)\n\t.action(\n\t\tasync (construct: string | undefined, options: { stage?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { seedCommand } = await import('./migrate/index.js');\n\t\t\t\tawait seedCommand({\n\t\t\t\t\t...options,\n\t\t\t\t\t...(construct ? { construct } : {}),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('migration')\n\t.description(\n\t\t\"Write a construct's next migration: an empty one for a database, the schema change for an auth server\",\n\t)\n\t.argument('<construct>', 'The construct, by name')\n\t.argument('[name]', 'What the migration is called')\n\t.action(async (construct: string, name: string | undefined) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { migrationCommand } = await import('./migrate/index.js');\n\t\t\tawait migrationCommand({ construct, ...(name ? { name } : {}) });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('cron')\n\t.description('Manage cron jobs')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Cron management - coming soon\\n');\n\t});\n\nprogram\n\t.command('function')\n\t.description('Manage serverless functions')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Serverless function management - coming soon\\n');\n\t});\n\nprogram\n\t.command('api')\n\t.description('Manage REST API endpoints')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('REST API management - coming soon\\n');\n\t});\n\nprogram\n\t.command('openapi')\n\t.description('Generate OpenAPI specification from endpoints')\n\t.option(\n\t\t'--app <name>',\n\t\t'Workspace mode: generate for a single named backend app',\n\t)\n\t.action(async (options: { app?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait openapiCommand({ app: options.app });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('docker')\n\t.description('Generate Docker deployment files')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.action(async (options: DockerOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait dockerCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('compose')\n\t.description(\n\t\t\"Run the workspace's APIs and sites for a stage as one Docker Compose stack behind Caddy\",\n\t)\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Stage to run — always named, so a stack is never a deployed stage by accident',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'Run the images CI pushed at this tag (sites: <tag>-<stage>); nothing is built',\n\t)\n\t.option('--build', 'Build images from this checkout, tagged with the commit')\n\t.option('--pull', 'Pull images (at --tag, or latest) rather than build them')\n\t.option(\n\t\t'--push',\n\t\t'With --build: push every image to deploy.registry and start nothing (for CI)',\n\t)\n\t.option(\n\t\t'--digests-file <path>',\n\t\t'With --push: write each image as <ref>@sha256:… (JSON). With --tag: run the images at those digests',\n\t)\n\t.option('--dry-run', 'Write the files and print the plan; start nothing')\n\t.option('--down', \"Stop the stage's stack (its volumes are kept)\")\n\t.option(\n\t\t'--allow-dev-services <list>',\n\t\t\"Deployed stage: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade\",\n\t)\n\t.action(async (options: ComposeOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait composeCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('prepack')\n\t.description('Generate Docker files for production deployment')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.action(\n\t\tasync (options: {\n\t\t\tbuild?: boolean;\n\t\t\tpush?: boolean;\n\t\t\ttag?: string;\n\t\t\tregistry?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait dockerCommand({\n\t\t\t\t\tbuild: options.build,\n\t\t\t\t\tpush: options.push,\n\t\t\t\t\ttag: options.tag,\n\t\t\t\t\tregistry: options.registry,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Secrets management commands\nprogram\n\t.command('secrets:init')\n\t.description('Initialize secrets for a deployment stage')\n\t.requiredOption('--stage <stage>', 'Stage name (e.g., production, staging)')\n\t.option('--force', 'Overwrite existing secrets')\n\t.action(async (options: { stage: string; force?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsInitCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:set')\n\t.description('Set a custom secret for a stage')\n\t.argument('<key>', 'Secret key (e.g., API_KEY)')\n\t.argument('[value]', 'Secret value (reads from stdin if omitted)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(\n\t\tasync (\n\t\t\tkey: string,\n\t\t\tvalue: string | undefined,\n\t\t\toptions: { stage: string },\n\t\t) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tawait secretsSetCommand(key, value, options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('secrets:add')\n\t.description(\n\t\t\"Build the keys a stage must be given — buckets, mail, file servers, third parties' credentials — across every app\",\n\t)\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--missing', 'Only the keys the stage has not set')\n\t.option('--json', 'Print the keys as JSON and ask nothing')\n\t.action(\n\t\tasync (options: { stage: string; missing?: boolean; json?: boolean }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { secretsAddCommand } = await import('./secrets/add');\n\t\t\t\tawait secretsAddCommand(options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('encryption:rotate')\n\t.description(\n\t\t\"Add a new current key to an Encryption construct's keyring on a server stage\",\n\t)\n\t.argument('<construct>', 'The Encryption construct (e.g. Pii)')\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.action(async (construct: string, options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { encryptionRotateCommand } = await import('./encryption/index.js');\n\t\t\tawait encryptionRotateCommand(construct, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('encryption:retire')\n\t.description(\n\t\t\"Remove an old key from an Encryption construct's keyring, once nothing is under it\",\n\t)\n\t.argument('<construct>', 'The Encryption construct (e.g. Pii)')\n\t.argument('<key>', 'The key to retire (e.g. k1)')\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.action(\n\t\tasync (construct: string, key: string, options: { stage: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { encryptionRetireCommand } = await import(\n\t\t\t\t\t'./encryption/index.js'\n\t\t\t\t);\n\t\t\t\tawait encryptionRetireCommand(construct, key, options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('secrets:show')\n\t.description('Show secrets for a stage')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--reveal', 'Show actual secret values (not masked)')\n\t.action(async (options: { stage: string; reveal?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:rotate')\n\t.description('Rotate service passwords')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option(\n\t\t'--service <service>',\n\t\t'Specific service to rotate (postgres, redis, minio, …)',\n\t)\n\t.action(async (options: { stage: string; service?: SecretServiceName }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsRotateCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:import')\n\t.description('Import secrets from a JSON file')\n\t.argument('<file>', 'JSON file path (e.g., secrets.json)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--no-merge', 'Replace all custom secrets instead of merging')\n\t.action(async (file: string, options: { stage: string; merge?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsImportCommand(file, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:reconcile')\n\t.description('Backfill missing custom secrets from workspace config')\n\t.option('--stage <stage>', 'Stage name (default: stages.local)')\n\t.action(async (options: { stage?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tconst { loadWorkspaceConfig } = await import('./config');\n\t\t\tconst { reconcileMissingSecrets } = await import('./secrets/reconcile');\n\t\t\tconst { secretsStoreFor } = await import('./secrets/store');\n\n\t\t\tconst { workspace } = await loadWorkspaceConfig();\n\t\t\tconst stage = options.stage ?? workspace.stages.local;\n\t\t\tconst store = await secretsStoreFor(workspace, stage);\n\t\t\tconst secrets = await store.read(stage);\n\n\t\t\tif (!secrets) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t\t);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tconst { derivedContainers } = await import('./reconcile/workspace');\n\t\t\tconst result = reconcileMissingSecrets(\n\t\t\t\tsecrets,\n\t\t\t\tworkspace,\n\t\t\t\tawait derivedContainers(workspace, stage),\n\t\t\t);\n\n\t\t\tif (!result) {\n\t\t\t\tconsole.log(`\\n✓ Secrets for stage \"${stage}\" are up-to-date`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait store.write(stage, result.secrets);\n\t\t\tconsole.log(\n\t\t\t\t`\\n✓ Reconciled ${result.addedKeys.length} missing secret(s) for stage \"${stage}\":`,\n\t\t\t);\n\t\t\tfor (const key of result.addedKeys) {\n\t\t\t\tconsole.log(` + ${key}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:migrate')\n\t.description(\n\t\t\"Copy a deployed stage's secrets from the configured store to another (file, ssm, secrets-manager)\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.requiredOption('--to <provider>', 'file, ssm or secrets-manager')\n\t.option(\n\t\t'--region <region>',\n\t\t\"The target's AWS region (default: the configured store's)\",\n\t)\n\t.option('--profile <profile>', \"AWS profile for the stage's account\")\n\t.option('--force', 'Replace a stage the target already holds')\n\t.action(\n\t\tasync (options: {\n\t\t\tstage: string;\n\t\t\tto: string;\n\t\t\tregion?: string;\n\t\t\tprofile?: string;\n\t\t\tforce?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { secretsMigrateCommand } = await import('./secrets/migrate');\n\t\t\t\tawait secretsMigrateCommand(options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy command — the terminal around `deploy()`: it prompts, prints and\n// sets the exit code; the deploy itself does none of the three.\nprogram\n\t.command('deploy')\n\t.description('Deploy a stage through its target')\n\t.option(\n\t\t'--target <name>',\n\t\t'Deploy target: dokploy, compose, sst, or one named in deploy.targets (default: deploy.default)',\n\t)\n\t.option('--provider <provider>', '[DEPRECATED] Use --target instead')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'Image tag (default: stage-timestamp; compose: the commit). Compose pulls a given tag',\n\t)\n\t.option('--skip-push', 'Skip pushing image to registry')\n\t.option('--skip-build', 'Skip build step (use existing build)')\n\t.option(\n\t\t'--json',\n\t\t'Write events as JSON lines instead of progress; never prompts',\n\t)\n\t.option(\n\t\t'--dry-run',\n\t\t'Show what would be created or reused; change, build and push nothing',\n\t)\n\t.option(\n\t\t'--atomic',\n\t\t'If the release fails, roll back every app it released, not only the failed ones',\n\t)\n\t.option(\n\t\t'--allow-dev-services <list>',\n\t\t\"Server targets: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade\",\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\ttarget?: string;\n\t\t\tprovider?: string;\n\t\t\tstage: string;\n\t\t\ttag?: string;\n\t\t\tjson?: boolean;\n\t\t\tdryRun?: boolean;\n\t\t\tatomic?: boolean;\n\t\t\tallowDevServices?: string;\n\t\t}) => {\n\t\t\tconst { deployCli } = await import('./deploy/cli');\n\t\t\tconst globalOptions = program.opts();\n\t\t\t// Passed down, not `process.chdir`ed into: the deploy is told which\n\t\t\t// project it is deploying.\n\t\t\tconst code = await deployCli({\n\t\t\t\tcwd: resolve(globalOptions.cwd ?? process.cwd()),\n\t\t\t\t...(options.target ? { target: options.target } : {}),\n\t\t\t\t...(options.provider ? { provider: options.provider } : {}),\n\t\t\t\tstage: options.stage,\n\t\t\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t\t\t...(options.json ? { json: true } : {}),\n\t\t\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t\t\t...(options.allowDevServices\n\t\t\t\t\t? { allowDevServices: options.allowDevServices }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t\tif (code !== 0) process.exit(code);\n\t\t},\n\t);\n\n// Rollback — a stage's apps back on the release before the one they run.\nprogram\n\t.command('deploy:rollback')\n\t.description(\n\t\t\"Put a stage's app back on its previous release (Dokploy): one app with --app, every app with --atomic\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.option('--app <app>', 'The app to roll back')\n\t.option('--atomic', 'Roll back every app that has an earlier release')\n\t.action(\n\t\tasync (options: { stage: string; app?: string; atomic?: boolean }) => {\n\t\t\ttry {\n\t\t\t\tconst { rollbackStage } = await import('./target/dokploy/rollback');\n\t\t\t\tconst { terminalCredentials } = await import('./deploy/terminal');\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tawait rollbackStage({\n\t\t\t\t\tcwd: resolve(globalOptions.cwd ?? process.cwd()),\n\t\t\t\t\tstage: options.stage,\n\t\t\t\t\t...(options.app ? { app: options.app } : {}),\n\t\t\t\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t\t\t\tcredentials: terminalCredentials(),\n\t\t\t\t\tlog: (line) => console.log(line),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy init command - Initialize Dokploy project and application\nprogram\n\t.command('deploy:init')\n\t.description('Initialize Dokploy deployment (create project and application)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.requiredOption('--project <name>', 'Project name (creates if not exists)')\n\t.requiredOption('--app <name>', 'Application name')\n\t.option('--project-id <id>', 'Use existing project ID instead of creating')\n\t.option('--registry-id <id>', 'Configure registry for the application')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tproject: string;\n\t\t\tapp: string;\n\t\t\tprojectId?: string;\n\t\t\tregistryId?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait deployInitCommand({\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\tprojectName: options.project,\n\t\t\t\t\tappName: options.app,\n\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\tregistryId: options.registryId,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy list command - List Dokploy resources\nprogram\n\t.command('deploy:github')\n\t.description(\n\t\t\"Let GitHub Actions deploy a stage: OIDC role in the stage's AWS account, and the GitHub environment the deploy workflow uses\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage from gkm.config.ts')\n\t.option('--profile <profile>', \"AWS profile for the stage's account\")\n\t.option('--repo <owner/name>', 'GitHub repository (default: this one)')\n\t.option(\n\t\t'--policy-arn <arn>',\n\t\t'Policy for the deploy role (default: AdministratorAccess)',\n\t)\n\t.option('--dry-run', 'Show the plan without changing AWS or GitHub')\n\t.action(async (options) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { deployGithubCommand } = await import('./deploy/github.js');\n\t\t\tawait deployGithubCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('deploy:list')\n\t.description('List Dokploy resources (projects, registries)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.option('--projects', 'List projects')\n\t.option('--registries', 'List registries')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tprojects?: boolean;\n\t\t\tregistries?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (options.projects) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (options.registries) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (!options.projects && !options.registries) {\n\t\t\t\t\t// Default to listing both\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Login command\nprogram\n\t.command('login')\n\t.description('Authenticate with a deployment or DNS provider')\n\t// `--provider`, the same word `gkm deploy` and the DNS config already use for\n\t// these same names. It was `--service`, which made `dokploy` a provider in\n\t// one command and a service in the next — and `service` is the most\n\t// overloaded word in this codebase already: the DI interface, the\n\t// `services:` backend block, and a Dokploy resource name.\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Provider to log in to (dokploy, hostinger)',\n\t\t'dokploy',\n\t)\n\t// Kept working rather than removed: it is what shipped, and a flag rename is\n\t// not worth breaking somebody's CI over.\n\t.option('--service <provider>', '[DEPRECATED] Use --provider instead')\n\t.option('--token <token>', 'API token (will prompt if not provided)')\n\t.option('--endpoint <url>', 'Service endpoint URL')\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider: string;\n\t\t\tservice?: string;\n\t\t\ttoken?: string;\n\t\t\tendpoint?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\t// The alias wins when given, because a default is not a choice.\n\t\t\t\tconst provider = options.service ?? options.provider;\n\n\t\t\t\tif (!['dokploy', 'hostinger'].includes(provider)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Unknown provider: ${provider}. Supported: dokploy, hostinger`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\n\t\t\t\tawait loginCommand({\n\t\t\t\t\tprovider: provider as 'dokploy' | 'hostinger',\n\t\t\t\t\ttoken: options.token,\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Logout command\nprogram\n\t.command('logout')\n\t.description('Remove stored credentials')\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Whose credentials to remove (dokploy, all)',\n\t\t'dokploy',\n\t)\n\t.option('--service <provider>', '[DEPRECATED] Use --provider instead')\n\t.action(async (options: { provider: string; service?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait logoutCommand({\n\t\t\t\tprovider: (options.service ?? options.provider) as 'dokploy' | 'all',\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// Whoami command\nprogram\n\t.command('whoami')\n\t.description('Show current authentication status')\n\t.action(async () => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait whoamiCommand();\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// State management commands\nprogram\n\t.command('state:pull')\n\t.description('Pull deployment state from remote to local')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePullCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:push')\n\t.description('Push deployment state from local to remote')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePushCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:show')\n\t.description('Show deployment state for a stage')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option('--json', 'Output as JSON')\n\t.action(async (options: { stage: string; json?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:unlock')\n\t.description('Release a stage deploy lock left behind by a run that crashed')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateUnlockCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:diff')\n\t.description('Compare local and remote deployment state')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateDiffCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('upgrade')\n\t.description(\n\t\t'Upgrade @geekmidas/cli (with --all, every @geekmidas package) along the release line the project is on',\n\t)\n\t.option('--dry-run', 'Show what would be upgraded without making changes')\n\t.option(\n\t\t'--all',\n\t\t'Every @geekmidas package, and the third-party packages their peers require',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'npm dist-tag to follow (default: the line you are on)',\n\t)\n\t.action(async (options: UpgradeOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait upgradeCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram.parse();\n"],"x_google_ignoreList":[5],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["logger","ask","logger","createServer","Readable","Http2ServerRequest2","createServerHTTP","logger","logger","logger","deploy","logger","require","detectPackageManager","logger","logger","backendsOf","parse","detectPackageManager","pkg.version"],"sources":["../package.json","../src/prompt.ts","../src/auth/index.ts","../src/trust/index.ts","../src/dev/discovery.ts","../../../node_modules/.pnpm/@hono+node-server@1.19.5_hono@4.13.8/node_modules/@hono/node-server/dist/index.mjs","../src/dev/fakes.ts","../src/exec/index.ts","../src/dev/index.ts","../src/generators/FunctionGenerator.ts","../src/generators/TopicGenerator.ts","../src/build/types.ts","../src/build/owners.ts","../src/build/surfaceEntry.ts","../src/build/index.ts","../src/compose/index.ts","../src/debug.ts","../src/deploy/init.ts","../src/deploy/state-commands.ts","../src/secrets/generator.ts","../src/migrate/names.ts","../src/init/constructs.ts","../src/init/generators/agents.ts","../src/init/dependencies.ts","../src/init/versions.ts","../src/init/generators/auth.ts","../src/init/generators/stages.ts","../src/init/generators/config.ts","../src/init/generators/env.ts","../src/init/generators/github.ts","../src/init/generators/mobile-expo.ts","../src/init/generators/models.ts","../src/init/generators/deploy.ts","../src/init/generators/monorepo.ts","../src/init/generators/package.ts","../src/init/generators/source.ts","../src/init/generators/test.ts","../src/init/generators/shadcn.ts","../src/init/generators/web.ts","../src/init/generators/web-tanstack.ts","../src/init/templates/api.ts","../src/init/templates/minimal.ts","../src/init/templates/serverless.ts","../src/init/templates/worker.ts","../src/init/templates/index.ts","../src/init/index.ts","../src/setup/fullstack-secrets.ts","../src/secrets/index.ts","../src/setup/index.ts","../src/test/teardown.ts","../src/test/index.ts","../src/upgrade/version.ts","../src/upgrade/index.ts","../src/index.ts"],"sourcesContent":["","/**\n * Asking the person at the terminal.\n *\n * CLI layer only: a command's action may prompt, nothing it calls may. A\n * library call (`deploy()`) that needs something it was not given raises a\n * named error instead, and the command decides whether to ask.\n */\n\nimport { stdin as input, stdout as output } from 'node:process';\nimport * as readline from 'node:readline/promises';\n\n/** A prompt was needed with no terminal to ask at. */\nexport class PromptNeedsTerminal extends Error {\n\tconstructor(\n\t\treadonly question: string,\n\t\t/** What to do instead — the flag or variable that answers it. */\n\t\treadonly instead: string,\n\t) {\n\t\tsuper(`Interactive input required. ${instead}`);\n\t\tthis.name = 'PromptNeedsTerminal';\n\t}\n}\n\n/** Whether there is a person at a terminal to ask. */\nexport function canPrompt(): boolean {\n\treturn process.stdin.isTTY === true;\n}\n\n/**\n * Ask `message` and resolve with the line typed — without echoing it when\n * `hidden`. Ctrl+C at a hidden prompt exits, as it would anywhere else in a\n * terminal program: raw mode has taken the signal away from the shell.\n */\nexport async function prompt(\n\tmessage: string,\n\toptions: { hidden?: boolean; instead: string },\n): Promise<string> {\n\tif (!canPrompt()) {\n\t\tthrow new PromptNeedsTerminal(message, options.instead);\n\t}\n\n\tif (options.hidden) {\n\t\t// For hidden input, use raw mode directly without readline\n\t\tprocess.stdout.write(message);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet value = '';\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\tprocess.stdin.pause();\n\t\t\t\tprocess.stdin.removeListener('data', onData);\n\t\t\t\tprocess.stdin.removeListener('error', onError);\n\t\t\t};\n\n\t\t\tconst onError = (err: Error) => {\n\t\t\t\tcleanup();\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tconst onData = (char: Buffer) => {\n\t\t\t\tconst c = char.toString();\n\n\t\t\t\tif (c === '\\n' || c === '\\r') {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tresolve(value);\n\t\t\t\t} else if (c === '\\u0003') {\n\t\t\t\t\t// Ctrl+C\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t} else if (c === '\\u007F' || c === '\\b') {\n\t\t\t\t\t// Backspace\n\t\t\t\t\tif (value.length > 0) {\n\t\t\t\t\t\tvalue = value.slice(0, -1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue += c;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t\tprocess.stdin.resume();\n\t\t\tprocess.stdin.on('data', onData);\n\t\t\tprocess.stdin.on('error', onError);\n\t\t});\n\t}\n\n\t// For visible input, use readline\n\tconst rl = readline.createInterface({ input, output });\n\ttry {\n\t\treturn await rl.question(message);\n\t} finally {\n\t\trl.close();\n\t}\n}\n","import { prompt as ask } from '../prompt';\nimport {\n\tgetCredentialsPath,\n\tgetDokployCredentials,\n\tremoveDokployCredentials,\n\tstoreDokployCredentials,\n\tstoreHostingerToken,\n} from './credentials';\n\nconst logger = console;\n\nexport interface LoginOptions {\n\t/** Which provider's credentials to store — the same word `gkm deploy` uses. */\n\tprovider: 'dokploy' | 'hostinger';\n\t/** API token (if not provided, will prompt) */\n\ttoken?: string;\n\t/** Endpoint URL */\n\tendpoint?: string;\n}\n\nexport interface LogoutOptions {\n\t/** Whose credentials to remove — `all` clears every stored provider. */\n\tprovider?: 'dokploy' | 'all';\n}\n\n/**\n * Validate Dokploy token by making a test API call\n */\nexport async function validateDokployToken(\n\tendpoint: string,\n\ttoken: string,\n): Promise<boolean> {\n\tconst { DokployApi } = await import('../target/dokploy/dokploy-api');\n\tconst api = new DokployApi({ baseUrl: endpoint, token });\n\treturn api.validateToken();\n}\n\n/** What answers a login prompt without a terminal. */\nconst LOGIN_INSTEAD = 'Please provide --token option.';\n\n/**\n * Login to a service\n */\nexport async function loginCommand(options: LoginOptions): Promise<void> {\n\tconst {\n\t\tprovider,\n\t\ttoken: providedToken,\n\t\tendpoint: providedEndpoint,\n\t} = options;\n\n\tif (provider === 'dokploy') {\n\t\tlogger.log('\\n🔐 Logging in to Dokploy...\\n');\n\n\t\t// Get endpoint\n\t\tlet endpoint = providedEndpoint;\n\t\tif (!endpoint) {\n\t\t\tendpoint = await ask(\n\t\t\t\t'Dokploy URL (e.g., https://dokploy.example.com): ',\n\t\t\t\t{\n\t\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Normalize endpoint (remove trailing slash)\n\t\tendpoint = endpoint.replace(/\\/$/, '');\n\n\t\t// Validate endpoint format\n\t\ttry {\n\t\t\tnew URL(endpoint);\n\t\t} catch {\n\t\t\tlogger.error('Invalid URL format');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Get token\n\t\tlet token = providedToken;\n\t\tif (!token) {\n\t\t\tlogger.log(`\\nGenerate a token at: ${endpoint}/settings/profile\\n`);\n\t\t\ttoken = await ask('API Token: ', {\n\t\t\t\thidden: true,\n\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t});\n\t\t}\n\n\t\tif (!token) {\n\t\t\tlogger.error('Token is required');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Validate token\n\t\tlogger.log('\\nValidating credentials...');\n\t\tconst isValid = await validateDokployToken(endpoint, token);\n\n\t\tif (!isValid) {\n\t\t\tlogger.error(\n\t\t\t\t'\\n✗ Invalid credentials. Please check your token and try again.',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Store credentials\n\t\tawait storeDokployCredentials(token, endpoint);\n\n\t\tlogger.log('\\n✓ Successfully logged in to Dokploy!');\n\t\tlogger.log(` Endpoint: ${endpoint}`);\n\t\tlogger.log(` Credentials stored in: ${getCredentialsPath()}`);\n\t\tlogger.log(\n\t\t\t'\\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\n\tif (provider === 'hostinger') {\n\t\t// The DNS provider has told people to run this since it was written, and\n\t\t// this branch did not exist — so the only way to supply the token was the\n\t\t// environment variable, which the message does not mention.\n\t\tlogger.log('\\n🔐 Logging in to Hostinger...\\n');\n\n\t\tlet token = providedToken;\n\t\tif (!token) {\n\t\t\tlogger.log(\n\t\t\t\t'\\nGenerate a token at: https://hpanel.hostinger.com/profile/api\\n',\n\t\t\t);\n\t\t\ttoken = await ask('API Token: ', {\n\t\t\t\thidden: true,\n\t\t\t\tinstead: LOGIN_INSTEAD,\n\t\t\t});\n\t\t}\n\n\t\tif (!token) {\n\t\t\tlogger.error('Token is required');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Stored without validating, and that is worth saying rather than hiding.\n\t\t// Hostinger's DNS API is zone-scoped — every endpoint takes a domain — so\n\t\t// there is nothing to call that means \"is this token good\" without\n\t\t// already knowing a domain this account owns. A check against a guessed\n\t\t// one would fail for two different reasons and report one.\n\t\tawait storeHostingerToken(token);\n\n\t\tlogger.log('\\n✓ Hostinger token stored.');\n\t\tlogger.log(` Credentials stored in: ${getCredentialsPath()}`);\n\t\tlogger.log(\n\t\t\t' Not validated here: every DNS endpoint is scoped to a domain, so the\\n' +\n\t\t\t\t' first deploy that touches DNS is where a bad token reports itself.',\n\t\t);\n\t\tlogger.log(\n\t\t\t'\\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.',\n\t\t);\n\t}\n}\n\n/**\n * Logout from a service\n */\nexport async function logoutCommand(options: LogoutOptions): Promise<void> {\n\tconst { provider = 'dokploy' } = options;\n\n\tif (provider === 'all') {\n\t\tconst dokployRemoved = await removeDokployCredentials();\n\n\t\tif (dokployRemoved) {\n\t\t\tlogger.log('\\n✓ Logged out from all services');\n\t\t} else {\n\t\t\tlogger.log('\\nNo stored credentials found');\n\t\t}\n\t\treturn;\n\t}\n\n\tif (provider === 'dokploy') {\n\t\tconst removed = await removeDokployCredentials();\n\n\t\tif (removed) {\n\t\t\tlogger.log('\\n✓ Logged out from Dokploy');\n\t\t} else {\n\t\t\tlogger.log('\\nNo Dokploy credentials found');\n\t\t}\n\t}\n}\n\n/**\n * Show current login status\n */\nexport async function whoamiCommand(): Promise<void> {\n\tlogger.log('\\n📋 Current credentials:\\n');\n\n\tconst dokploy = await getDokployCredentials();\n\n\tif (dokploy) {\n\t\tlogger.log(' Dokploy:');\n\t\tlogger.log(` Endpoint: ${dokploy.endpoint}`);\n\t\tlogger.log(` Token: ${maskToken(dokploy.token)}`);\n\t} else {\n\t\tlogger.log(' Dokploy: Not logged in');\n\t}\n\n\tlogger.log(`\\n Credentials file: ${getCredentialsPath()}`);\n}\n\n/**\n * Mask a token for display\n */\nexport function maskToken(token: string): string {\n\tif (token.length <= 8) {\n\t\treturn '****';\n\t}\n\treturn `${token.slice(0, 4)}...${token.slice(-4)}`;\n}\n\n// Re-export credentials utilities for use in other modules\nexport {\n\tgetDokployCredentials,\n\tgetDokployEndpoint,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployCredentials,\n\tstoreDokployRegistryId,\n} from './credentials';\n","/**\n * Installing the local edge's certificate authority into the OS trust store.\n *\n * `NODE_EXTRA_CA_CERTS` covers everything gkm starts — the dev server, the test\n * suite, anything under `gkm exec` — because reconcile injects it. A browser\n * reads none of that: it asks the operating system, so until the root is in the\n * system store a local `https://` address is \"not secure\", which is true and\n * unhelpful.\n *\n * A separate command rather than part of `gkm setup`, for one reason: this\n * asks for a password, and a setup that silently escalates on every run is a\n * worse trade than one that tells you what to type. Caddy's own `caddy trust`\n * draws the line in the same place.\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport prompts from 'prompts';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { LOCAL_CA_PATH } from '../reconcile/index.js';\n\nconst logger = console;\n\nconst run = promisify(execFile);\n\nexport interface TrustOptions {\n\t/** Print the commands rather than running them. */\n\tdryRun?: boolean;\n}\n\n/**\n * How each platform is told about a new authority.\n *\n * Separate rather than shelled through one script because the failure modes\n * differ and the message should name the real one: macOS refuses without an\n * admin password, Debian needs the file in a specific directory before its\n * updater will look at it.\n */\nfunction installation(\n\tplatform: NodeJS.Platform,\n\tcertificate: string,\n): { describe: string; asks: string; steps: [string, string[]][] } {\n\tif (platform === 'darwin') {\n\t\t// The login keychain, trusted for this user, and no sudo. The System\n\t\t// keychain needs both: sudo to write the file, then macOS's own\n\t\t// authorization to change trust settings, which sudo does not cover — so\n\t\t// it asked for the password twice. A local CA is one developer's\n\t\t// business anyway, and browsers and Node's system store honour a\n\t\t// user's trust settings.\n\t\treturn {\n\t\t\tdescribe: 'your login keychain',\n\t\t\tasks: 'macOS asks once — your password or Touch ID — to change trust settings.',\n\t\t\tsteps: [\n\t\t\t\t[\n\t\t\t\t\t'security',\n\t\t\t\t\t[\n\t\t\t\t\t\t'add-trusted-cert',\n\t\t\t\t\t\t'-r',\n\t\t\t\t\t\t'trustRoot',\n\t\t\t\t\t\t'-k',\n\t\t\t\t\t\tjoin(homedir(), 'Library/Keychains/login.keychain-db'),\n\t\t\t\t\t\tcertificate,\n\t\t\t\t\t],\n\t\t\t\t],\n\t\t\t],\n\t\t};\n\t}\n\n\tif (platform === 'linux') {\n\t\t// Debian and Fedora keep anchors in different places and run different\n\t\t// updaters. Whichever directory exists is the one this system uses.\n\t\tconst debian = existsSync('/usr/local/share/ca-certificates');\n\n\t\treturn {\n\t\t\tdescribe: debian ? 'the system CA bundle' : 'the system trust anchors',\n\t\t\tasks: 'This needs sudo: the system trust store is the only one.',\n\t\t\tsteps: debian\n\t\t\t\t? [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t'sudo',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'cp',\n\t\t\t\t\t\t\t\tcertificate,\n\t\t\t\t\t\t\t\t'/usr/local/share/ca-certificates/gkm-local-ca.crt',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t],\n\t\t\t\t\t\t['sudo', ['update-ca-certificates']],\n\t\t\t\t\t]\n\t\t\t\t: [\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t'sudo',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'cp',\n\t\t\t\t\t\t\t\tcertificate,\n\t\t\t\t\t\t\t\t'/etc/pki/ca-trust/source/anchors/gkm-local-ca.crt',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t],\n\t\t\t\t\t\t['sudo', ['update-ca-trust']],\n\t\t\t\t\t],\n\t\t};\n\t}\n\n\tthrow new UnsupportedPlatform(platform, certificate);\n}\n\n/**\n * Trust the certificate authority this project's edge issues from.\n *\n * Idempotent in effect: installing a root that is already trusted replaces the\n * same entry, so running it twice is not an error.\n */\nexport async function trustCommand(options: TrustOptions = {}): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst certificate = join(workspace.root, LOCAL_CA_PATH);\n\n\tif (!existsSync(certificate)) {\n\t\tthrow new NoLocalAuthority(certificate);\n\t}\n\n\tconst { describe, asks, steps } = installation(process.platform, certificate);\n\n\tlogger.log(`\\n🔐 Trusting the local authority in ${describe}`);\n\tlogger.log(` ${certificate}\\n`);\n\n\tif (options.dryRun) {\n\t\tfor (const [command, args] of steps) {\n\t\t\tlogger.log(` ${command} ${args.join(' ')}`);\n\t\t}\n\t\treturn;\n\t}\n\n\tlogger.log(` ${asks}\\n`);\n\n\tfor (const [command, args] of steps) {\n\t\t// Inherited stdio, because sudo prompts on the terminal and a captured\n\t\t// prompt is a command that appears to hang.\n\t\tawait run(command, args, { stdio: 'inherit' } as never);\n\t}\n\n\tlogger.log('\\n✅ Local https addresses are trusted. Restart your browser.\\n');\n}\n\n/**\n * Trust the authority if this machine lacks it and its owner agrees.\n *\n * A machine's answer, not the project's: whether a laptop installs a root\n * certificate is its owner's call, so the decision is `--yes`, then what this\n * machine previously answered, then a prompt. Never a silent escalation — that is\n * the one thing a setup command should not do on somebody's behalf.\n *\n * Silent and free when the machine already trusts it, which is what makes it\n * acceptable to call on every `gkm setup`.\n */\nexport async function ensureTrusted(\n\troot: string,\n\turl: string,\n\toptions: { assumeYes?: boolean } = {},\n): Promise<void> {\n\tif (await isTrusted(url)) return;\n\n\tif (!options.assumeYes) {\n\t\t// Nothing to answer a prompt in CI, a hook, or a piped shell — and a\n\t\t// setup that stops there waiting is worse than one that leaves the\n\t\t// authority untrusted. Not recorded as declined, because nobody\n\t\t// declined: the next interactive run should still ask.\n\t\tif (!process.stdin.isTTY) {\n\t\t\tlogger.log(\n\t\t\t\t' Local https addresses are not trusted here. Run \"gkm trust\", ' +\n\t\t\t\t\t'or \"gkm setup --yes\".',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// A recorded \"no\" is why this asks once rather than every start. There is\n\t\t// no recorded \"yes\": trusting is checked directly above, so a yes that\n\t\t// worked answers itself and a yes that did not should ask again.\n\t\tif (await declined(root)) return;\n\n\t\tconst { install } = await prompts({\n\t\t\ttype: 'confirm',\n\t\t\tname: 'install',\n\t\t\tmessage:\n\t\t\t\t\"Trust this project's local certificate authority, so a browser \" +\n\t\t\t\t'accepts its https addresses? (asks for your password)',\n\t\t\tinitial: false,\n\t\t});\n\n\t\tif (!install) {\n\t\t\tawait recordDeclined(root);\n\t\t\tlogger.log(' Skipped. Run \"gkm trust\" later.');\n\t\t\treturn;\n\t\t}\n\t}\n\n\tawait trustCommand();\n}\n\n/** Where a declined answer is remembered, so setup asks once and not again. */\nconst TRUST_STATE = '.gkm/trust.json';\n\nasync function declined(root: string): Promise<boolean> {\n\ttry {\n\t\tconst raw = await readFile(join(root, TRUST_STATE), 'utf-8');\n\n\t\treturn (JSON.parse(raw) as { declined?: boolean }).declined === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function recordDeclined(root: string): Promise<void> {\n\tconst path = join(root, TRUST_STATE);\n\n\tawait mkdir(dirname(path), { recursive: true });\n\tawait writeFile(path, `${JSON.stringify({ declined: true }, null, 2)}\\n`);\n}\n\n/**\n * Whether this machine already trusts the local authority.\n *\n * Asked by connecting rather than by reading a keychain: what matters is\n * whether a client with no special configuration verifies the edge, and that is\n * one platform-neutral question instead of three platform-specific ones. It is\n * also the exact thing a browser is about to do.\n *\n * A child process, because `NODE_EXTRA_CA_CERTS` is read once at startup and\n * this process almost certainly has it set — asking in-process would answer\n * \"yes\" for everyone.\n */\nexport async function isTrusted(url: string): Promise<boolean> {\n\tconst { NODE_EXTRA_CA_CERTS: _ignored, ...env } = process.env;\n\n\ttry {\n\t\tawait run(\n\t\t\tprocess.execPath,\n\t\t\t[\n\t\t\t\t// The operating system's store — where `gkm trust` installs the root,\n\t\t\t\t// and what a browser reads. Without it Node checks only its own\n\t\t\t\t// bundled authorities, so an installed root still read as untrusted\n\t\t\t\t// and every run asked again.\n\t\t\t\t'--use-system-ca',\n\t\t\t\t'-e',\n\t\t\t\t`fetch(${JSON.stringify(url)}).then(()=>0,()=>process.exit(1))`,\n\t\t\t],\n\t\t\t{ env, timeout: 15_000 },\n\t\t);\n\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Copy the root somewhere a tool that wants a file can read it.\n *\n * For anything that takes a CA bundle rather than reading the system store —\n * another language's HTTP client, a container, a CI job.\n */\nexport async function exportLocalAuthority(to: string): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst certificate = join(workspace.root, LOCAL_CA_PATH);\n\n\tif (!existsSync(certificate)) throw new NoLocalAuthority(certificate);\n\n\tawait copyFile(certificate, to);\n}\n\n/** The edge has not run, so there is no authority to trust yet. */\nexport class NoLocalAuthority extends Error {\n\tconstructor(readonly path: string) {\n\t\tsuper(\n\t\t\t`No local certificate authority at ${path}. It is generated the first ` +\n\t\t\t\t`time the edge starts, so run \"gkm setup\" (or \"gkm dev\") once — and ` +\n\t\t\t\t`if this project declares no file server, nothing needs one.`,\n\t\t);\n\t\tthis.name = 'NoLocalAuthority';\n\t}\n}\n\n/** A platform with no trust store this knows how to write to. */\nexport class UnsupportedPlatform extends Error {\n\tconstructor(\n\t\treadonly platform: string,\n\t\treadonly certificate: string,\n\t) {\n\t\tsuper(\n\t\t\t`gkm does not know how to install a certificate authority on ` +\n\t\t\t\t`${platform}. The root is at ${certificate} — add it to the trust ` +\n\t\t\t\t`store by hand, or point a client at it with NODE_EXTRA_CA_CERTS.`,\n\t\t);\n\t\tthis.name = 'UnsupportedPlatform';\n\t}\n}\n","/**\n * How a tool finds what `gkm dev` is running on this machine.\n *\n * Every app already serves its data as JSON — Telescope's requests, logs and\n * exceptions, the declared database at `/__gkm/db`, the OpenAPI document — but\n * each on its own port, and nothing said which ports those were. A console had\n * to be told. So `gkm dev` serves one more thing, on one well-known loopback\n * port: `GET /__gkm` lists the running workspaces, their apps and the data APIs\n * each app exposes, `GET /__gkm/events` streams the changes, and\n * `/__gkm/workspaces/<id>/apps/<app>/…` forwards to an app's data APIs, so a\n * client talks to one origin.\n *\n * **Many sessions, one endpoint.** A developer runs several `gkm dev`s at once\n * — a workspace's own, the one per app turbo starts under it, another\n * project's. Each writes what it runs to a registry directory shared by the\n * machine (`~/.gkm/dev/sessions/<id>.json`) and removes it when it stops. The\n * endpoint is served by whichever of them bound the port first, and it reads\n * the registry rather than being told — so nothing has to be handed over when\n * that process exits. Every other session keeps trying to bind the port, and\n * the first to manage it after the host is gone is the new host. A session that\n * died without cleaning up is recognised by its pid and pruned.\n *\n * **Security.** Any web page the developer visits can send requests to a\n * loopback port, so nothing here trusts being on loopback:\n * - it binds `127.0.0.1` only;\n * - the `Host` header must be `127.0.0.1` or `localhost` with this port, which\n * defeats DNS rebinding (an attacker's hostname resolving to 127.0.0.1);\n * - a browser's `Origin` must be in a workspace's `dev.allowedOrigins`, empty\n * by default; CORS replies only to those, and a workspace is only visible to\n * the origins it listed;\n * - every request carries the session token (`Authorization: Bearer …` or\n * `?token=…`, since `EventSource` cannot set headers), which `gkm dev` prints\n * in a connect URL the way Jupyter does;\n * - it is read-only: `GET` and `HEAD`, and the forwarder reaches an app's data\n * APIs and nothing else of it.\n */\n\nimport { createHash, randomBytes, timingSafeEqual } from 'node:crypto';\nimport {\n\tlinkSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from 'node:fs';\nimport {\n\tcreateServer,\n\ttype IncomingMessage,\n\ttype Server,\n\ttype ServerResponse,\n} from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { connect } from 'node:net';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport type { DevConfig } from '../workspace/types.js';\n\n/** Where the endpoint listens unless configured otherwise. */\nexport const DEFAULT_DISCOVERY_PORT = 4983;\n\n/** Overrides `dev.discoveryPort` — `0` serves on a port of its own. */\nexport const DISCOVERY_PORT_ENV = 'GKM_DISCOVERY_PORT';\n\n/** Overrides where the sessions register — `~/.gkm/dev` by default. */\nexport const DISCOVERY_REGISTRY_ENV = 'GKM_DEV_REGISTRY';\n\n/**\n * Set by a workspace's `gkm dev` for the app sessions turbo starts under it:\n * the workspace has printed the connect URL, so they do not repeat it.\n */\nexport const DISCOVERY_QUIET_ENV = 'GKM_DISCOVERY_QUIET';\n\n/** The route everything is served under. */\nconst BASE = '/__gkm';\n\n// ---------------------------------------------------------------------------\n// What a session registers\n// ---------------------------------------------------------------------------\n\n/** Where an app is in its life. `stopped` is a server that exited on its own. */\nexport type AppStatus = 'starting' | 'ready' | 'reloading' | 'stopped';\n\n/** A JSON API an app serves about itself. */\nexport type DataApiKind = 'telescope' | 'database' | 'openapi';\n\nexport interface SessionDataApi {\n\tkind: DataApiKind;\n\t/** Where the app serves it, e.g. `/__gkm/db`. */\n\tpath: string;\n}\n\nexport interface SessionApp {\n\tname: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tport: number;\n\t/** Its address behind the edge, when it has one. */\n\tpublicUrl?: string;\n\tstatus: AppStatus;\n\t/** How many times it has been rebuilt and restarted since it started. */\n\treloads: number;\n\tdataApis: SessionDataApi[];\n}\n\n/**\n * One `gkm dev` process, as it registers itself.\n *\n * A `workspace` session is the workspace's own `gkm dev`: it lists every app\n * turbo starts, but runs none of them itself. An `app` session runs one app's\n * server, and knows its status and data APIs — so where both describe an app,\n * the `app` session's word is taken.\n */\nexport interface DevSessionRecord {\n\tid: string;\n\tpid: number;\n\trole: 'workspace' | 'app';\n\tstartedAt: string;\n\tupdatedAt: string;\n\tworkspace: { name: string; root: string; stage: string };\n\t/** `dev.allowedOrigins`: the browser origins this workspace is shown to. */\n\tallowedOrigins: string[];\n\tmanifest?: ConstructManifest;\n\tapps: SessionApp[];\n}\n\n// ---------------------------------------------------------------------------\n// What `GET /__gkm` answers\n// ---------------------------------------------------------------------------\n\nexport interface DiscoveredDataApi {\n\tkind: DataApiKind;\n\t/** Where the app serves it. */\n\tpath: string;\n\t/** The app's own address for it — `http://localhost:<port><path>`. */\n\turl: string;\n\t/** The same API through this endpoint, relative to its origin. */\n\tproxy: string;\n}\n\nexport interface DiscoveredApp {\n\tname: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tport: number;\n\t/** `http://localhost:<port>`. */\n\turl: string;\n\tpublicUrl: string | null;\n\tstatus: AppStatus;\n\treloads: number;\n\t/** The `gkm dev` running it, when it runs in one of its own. */\n\tpid: number | null;\n\tdataApis: DiscoveredDataApi[];\n}\n\nexport interface DiscoveredWorkspace {\n\t/** Stable for a workspace's root: its name, and a hash of where it is. */\n\tid: string;\n\tname: string;\n\troot: string;\n\tstage: string;\n\tmanifest: ConstructManifest | null;\n\tapps: DiscoveredApp[];\n}\n\n/** The body of `GET /__gkm`. */\nexport interface DiscoveryResponse {\n\tversion: 1;\n\t/** The `gkm dev` serving this endpoint, which may change while you watch. */\n\thost: { pid: number; port: number };\n\t/** Where the changes stream, as server-sent events. */\n\tevents: string;\n\tworkspaces: DiscoveredWorkspace[];\n}\n\n/** One message on `GET /__gkm/events`; its SSE `event:` is its `type`. */\nexport type DiscoveryEvent =\n\t| { type: 'snapshot'; snapshot: DiscoveryResponse }\n\t| { type: 'workspace.started' | 'workspace.stopped'; workspace: string }\n\t| {\n\t\t\ttype: 'app.started' | 'app.stopped' | 'app.reloaded' | 'app.status';\n\t\t\tworkspace: string;\n\t\t\tapp: DiscoveredApp;\n\t };\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/** `GKM_DISCOVERY_PORT` is set to something that is not a port. */\nexport class InvalidDiscoveryPort extends Error {\n\tconstructor(readonly value: string) {\n\t\tsuper(\n\t\t\t`${DISCOVERY_PORT_ENV}=${value} is not a port. Set it to a number from 0 ` +\n\t\t\t\t'to 65535 (0 serves discovery on a free port of its own), or unset ' +\n\t\t\t\t'it to use dev.discoveryPort.',\n\t\t);\n\t\tthis.name = 'InvalidDiscoveryPort';\n\t}\n}\n\n/** The port the endpoint uses: the env, then `dev.discoveryPort`, then 4983. */\nexport function discoveryPort(\n\tconfig: DevConfig | undefined,\n\tenv: NodeJS.ProcessEnv = process.env,\n): number {\n\tconst raw = env[DISCOVERY_PORT_ENV];\n\tif (raw !== undefined && raw !== '') {\n\t\tconst port = Number(raw);\n\t\tif (!Number.isInteger(port) || port < 0 || port > 65535) {\n\t\t\tthrow new InvalidDiscoveryPort(raw);\n\t\t}\n\t\treturn port;\n\t}\n\treturn config?.discoveryPort ?? DEFAULT_DISCOVERY_PORT;\n}\n\n/** The machine's registry, shared by every `gkm dev`. */\nexport function discoveryRegistry(env: NodeJS.ProcessEnv = process.env) {\n\treturn env[DISCOVERY_REGISTRY_ENV] || join(homedir(), '.gkm', 'dev');\n}\n\n// ---------------------------------------------------------------------------\n// The registry\n// ---------------------------------------------------------------------------\n\nfunction sessionsDir(registry: string): string {\n\treturn join(registry, 'sessions');\n}\n\n/** Whether a process is alive. `EPERM` is someone else's — alive. */\nfunction alive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === 'EPERM';\n\t}\n}\n\n/**\n * Every live session, pruning the ones whose process is gone — a `gkm dev`\n * killed outright never got to remove its own.\n */\nexport function liveSessions(registry: string): DevSessionRecord[] {\n\tconst dir = sessionsDir(registry);\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(dir).filter((file) => file.endsWith('.json'));\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst records: DevSessionRecord[] = [];\n\tfor (const file of files) {\n\t\tconst path = join(dir, file);\n\t\tlet record: DevSessionRecord;\n\t\ttry {\n\t\t\trecord = JSON.parse(readFileSync(path, 'utf8'));\n\t\t} catch {\n\t\t\t// Removed between the listing and the read.\n\t\t\tcontinue;\n\t\t}\n\t\tif (alive(record.pid)) {\n\t\t\trecords.push(record);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tunlinkSync(path);\n\t\t} catch {\n\t\t\t// Another session pruned it first.\n\t\t}\n\t}\n\treturn records;\n}\n\n/** Written whole, then renamed into place, so a reader never sees half. */\nfunction writeRecord(registry: string, record: DevSessionRecord): void {\n\tconst path = join(sessionsDir(registry), `${record.id}.json`);\n\tconst partial = `${path}.${process.pid}.tmp`;\n\twriteFileSync(partial, JSON.stringify(record), { mode: 0o600 });\n\trenameSync(partial, path);\n}\n\nfunction removeRecord(registry: string, id: string): void {\n\ttry {\n\t\tunlinkSync(join(sessionsDir(registry), `${id}.json`));\n\t} catch {\n\t\t// Already gone.\n\t}\n}\n\n/**\n * The token every session prints and every host checks.\n *\n * Shared through the registry, so a URL printed by one session still works\n * after another has taken over hosting. It lives as long as some session does:\n * a session that finds none but itself starts a new one, so a token printed\n * yesterday stops working once everything it was printed by has stopped.\n */\nfunction sessionToken(registry: string, self: string): string {\n\tconst path = join(registry, 'token');\n\tconst others = liveSessions(registry).filter((r) => r.id !== self);\n\n\tif (others.length === 0) {\n\t\t// Left by a session that died without removing it. Renamed away rather\n\t\t// than deleted, so only one of two sessions starting at once does it.\n\t\tconst stale = `${path}.${self}.stale`;\n\t\ttry {\n\t\t\trenameSync(path, stale);\n\t\t\tunlinkSync(stale);\n\t\t} catch {\n\t\t\t// None there, or another session got to it first.\n\t\t}\n\t}\n\n\t// Linked into place, which fails if one is already there — so two sessions\n\t// starting together agree on whichever landed first, and neither reads a\n\t// half-written file.\n\tconst fresh = `${path}.${self}.new`;\n\twriteFileSync(fresh, randomBytes(32).toString('base64url'), {\n\t\tmode: 0o600,\n\t});\n\ttry {\n\t\tlinkSync(fresh, path);\n\t} catch {\n\t\t// Someone else's is already there; theirs is the token.\n\t}\n\tunlinkSync(fresh);\n\treturn readFileSync(path, 'utf8').trim();\n}\n\n// ---------------------------------------------------------------------------\n// The view: sessions merged into workspaces\n// ---------------------------------------------------------------------------\n\n/** A workspace as served, with who may see it. */\ninterface WorkspaceView extends DiscoveredWorkspace {\n\tallowedOrigins: readonly string[];\n}\n\n/** `<name>-<8 hex>`: readable, and two checkouts of a project stay apart. */\nexport function workspaceId(name: string, root: string): string {\n\tconst slug =\n\t\tname\n\t\t\t.toLowerCase()\n\t\t\t.replace(/^@/, '')\n\t\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t\t.replace(/^-|-$/g, '') || 'workspace';\n\tconst hash = createHash('sha256').update(root).digest('hex').slice(0, 8);\n\treturn `${slug}-${hash}`;\n}\n\n/** Whether anything accepts connections on a local port. */\nfunction listening(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\t// `localhost`, not 127.0.0.1: a Vite server listens on `::1` alone.\n\t\tconst socket = connect({ port, host: 'localhost' });\n\t\tconst done = (open: boolean) => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(open);\n\t\t};\n\t\tsocket.setTimeout(300, () => done(false));\n\t\tsocket.once('connect', () => done(true));\n\t\tsocket.once('error', () => done(false));\n\t});\n}\n\n/** Which data APIs the forwarder matches by prefix, rather than exactly. */\nconst PREFIXED: ReadonlySet<DataApiKind> = new Set(['telescope', 'database']);\n\n/** Whether `path` on an app is one of its data APIs. */\nfunction servesData(app: DiscoveredApp, path: string): boolean {\n\treturn app.dataApis.some((api) =>\n\t\tPREFIXED.has(api.kind)\n\t\t\t? path === api.path || path.startsWith(`${api.path}/`)\n\t\t\t: // The OpenAPI document is exactly `/__docs`; `/__docs/ui` is a page.\n\t\t\t\tpath === api.path,\n\t);\n}\n\n/**\n * Every workspace the sessions describe, one entry per root.\n *\n * An app listed only by its workspace's session — a web app turbo started, an\n * API whose own `gkm dev` has not registered yet — is `ready` when its port\n * answers and `starting` until then.\n */\nasync function collect(records: DevSessionRecord[]): Promise<WorkspaceView[]> {\n\tconst byRoot = new Map<string, DevSessionRecord[]>();\n\tfor (const record of records) {\n\t\tconst group = byRoot.get(record.workspace.root) ?? [];\n\t\tgroup.push(record);\n\t\tbyRoot.set(record.workspace.root, group);\n\t}\n\n\tconst views: WorkspaceView[] = [];\n\tfor (const [root, group] of byRoot) {\n\t\t// The workspace's own session first, then the oldest: what names the\n\t\t// workspace and carries its manifest.\n\t\tgroup.sort(\n\t\t\t(a, b) =>\n\t\t\t\tNumber(b.role === 'workspace') - Number(a.role === 'workspace') ||\n\t\t\t\ta.startedAt.localeCompare(b.startedAt),\n\t\t);\n\t\tconst lead = group[0]!;\n\t\tconst id = workspaceId(lead.workspace.name, root);\n\n\t\tconst apps = new Map<string, { app: SessionApp; pid: number | null }>();\n\t\tfor (const record of group) {\n\t\t\tfor (const app of record.apps) {\n\t\t\t\tconst own = record.role === 'app';\n\t\t\t\tif (!own && apps.has(app.name)) continue;\n\t\t\t\tapps.set(app.name, { app, pid: own ? record.pid : null });\n\t\t\t}\n\t\t}\n\n\t\tconst discovered = await Promise.all(\n\t\t\t[...apps.values()].map(async ({ app, pid }): Promise<DiscoveredApp> => {\n\t\t\t\tconst url = `http://localhost:${app.port}`;\n\t\t\t\tconst status =\n\t\t\t\t\tpid === null\n\t\t\t\t\t\t? (await listening(app.port))\n\t\t\t\t\t\t\t? 'ready'\n\t\t\t\t\t\t\t: 'starting'\n\t\t\t\t\t\t: app.status;\n\t\t\t\treturn {\n\t\t\t\t\tname: app.name,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tport: app.port,\n\t\t\t\t\turl,\n\t\t\t\t\tpublicUrl: app.publicUrl ?? null,\n\t\t\t\t\tstatus,\n\t\t\t\t\treloads: app.reloads,\n\t\t\t\t\tpid,\n\t\t\t\t\tdataApis: app.dataApis.map((api) => ({\n\t\t\t\t\t\tkind: api.kind,\n\t\t\t\t\t\tpath: api.path,\n\t\t\t\t\t\turl: `${url}${api.path}`,\n\t\t\t\t\t\tproxy: `${BASE}/workspaces/${id}/apps/${encodeURIComponent(app.name)}${api.path}`,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\t\tdiscovered.sort((a, b) => a.name.localeCompare(b.name));\n\n\t\tviews.push({\n\t\t\tid,\n\t\t\tname: lead.workspace.name,\n\t\t\troot,\n\t\t\tstage: lead.workspace.stage,\n\t\t\tmanifest: group.find((r) => r.manifest)?.manifest ?? null,\n\t\t\tapps: discovered,\n\t\t\tallowedOrigins: [...new Set(group.flatMap((r) => r.allowedOrigins))],\n\t\t});\n\t}\n\n\treturn views.sort(\n\t\t(a, b) => a.name.localeCompare(b.name) || a.root.localeCompare(b.root),\n\t);\n}\n\n/** What changed between two views, as events. */\nfunction changes(\n\tbefore: readonly WorkspaceView[],\n\tafter: readonly WorkspaceView[],\n): { workspace: WorkspaceView; event: DiscoveryEvent }[] {\n\tconst out: { workspace: WorkspaceView; event: DiscoveryEvent }[] = [];\n\tconst previous = new Map(before.map((w) => [w.id, w]));\n\tconst next = new Map(after.map((w) => [w.id, w]));\n\n\tfor (const workspace of after) {\n\t\tconst was = previous.get(workspace.id);\n\t\tif (!was) {\n\t\t\tout.push({\n\t\t\t\tworkspace,\n\t\t\t\tevent: { type: 'workspace.started', workspace: workspace.id },\n\t\t\t});\n\t\t}\n\t\tconst wasApps = new Map((was?.apps ?? []).map((a) => [a.name, a]));\n\t\tfor (const app of workspace.apps) {\n\t\t\tconst old = wasApps.get(app.name);\n\t\t\tconst type = !old\n\t\t\t\t? 'app.started'\n\t\t\t\t: app.reloads > old.reloads\n\t\t\t\t\t? 'app.reloaded'\n\t\t\t\t\t: app.status !== old.status ||\n\t\t\t\t\t\t\tapp.port !== old.port ||\n\t\t\t\t\t\t\tapp.dataApis.length !== old.dataApis.length\n\t\t\t\t\t\t? 'app.status'\n\t\t\t\t\t\t: undefined;\n\t\t\tif (type) {\n\t\t\t\tout.push({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tevent: { type, workspace: workspace.id, app },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tfor (const old of was?.apps ?? []) {\n\t\t\tif (!workspace.apps.some((a) => a.name === old.name)) {\n\t\t\t\tout.push({\n\t\t\t\t\tworkspace,\n\t\t\t\t\tevent: { type: 'app.stopped', workspace: workspace.id, app: old },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const workspace of before) {\n\t\tif (next.has(workspace.id)) continue;\n\t\tfor (const app of workspace.apps) {\n\t\t\tout.push({\n\t\t\t\tworkspace,\n\t\t\t\tevent: { type: 'app.stopped', workspace: workspace.id, app },\n\t\t\t});\n\t\t}\n\t\tout.push({\n\t\t\tworkspace,\n\t\t\tevent: { type: 'workspace.stopped', workspace: workspace.id },\n\t\t});\n\t}\n\n\treturn out;\n}\n\n// ---------------------------------------------------------------------------\n// The endpoint\n// ---------------------------------------------------------------------------\n\n/** A browser with no `Origin` — curl, a local process — sees everything. */\nfunction visibleTo(workspace: WorkspaceView, origin: string | undefined) {\n\treturn origin === undefined || workspace.allowedOrigins.includes(origin);\n}\n\nfunction publicView({\n\tallowedOrigins: _,\n\t...workspace\n}: WorkspaceView): DiscoveredWorkspace {\n\treturn workspace;\n}\n\n/** Headers an app's response is passed on with; nothing that sets state. */\nconst FORWARDED_RESPONSE_HEADERS = [\n\t'content-type',\n\t'cache-control',\n\t'etag',\n\t'last-modified',\n];\n\ninterface EventStream {\n\torigin: string | undefined;\n\tresponse: ServerResponse;\n}\n\n/**\n * The HTTP side: serves the registry it reads, checking every request.\n * @internal Exported for testing\n */\nexport class DiscoveryHost {\n\tprivate server: Server | undefined;\n\tprivate view: WorkspaceView[] = [];\n\tprivate streams = new Set<EventStream>();\n\tprivate scanning: Promise<WorkspaceView[]> | undefined;\n\tprivate timers: NodeJS.Timeout[] = [];\n\tprivate sequence = 0;\n\n\tconstructor(\n\t\tprivate readonly registry: string,\n\t\tprivate readonly token: string,\n\t\tprivate readonly pollMs: number,\n\t) {}\n\n\t/** The port it is bound to, once it is. */\n\tget port(): number | undefined {\n\t\tconst address = this.server?.address() as AddressInfo | null | undefined;\n\t\treturn address?.port;\n\t}\n\n\t/** Binds the port; `false` when another process already has it. */\n\tasync listen(port: number): Promise<boolean> {\n\t\tconst server = createServer((request, response) => {\n\t\t\tthis.handle(request, response).catch(() => {\n\t\t\t\tif (!response.headersSent) {\n\t\t\t\t\treply(response, 500, { error: 'DiscoveryFailed' });\n\t\t\t\t} else {\n\t\t\t\t\tresponse.destroy();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tconst bound = await new Promise<boolean>((resolve) => {\n\t\t\tserver.once('error', () => resolve(false));\n\t\t\tserver.listen(port, '127.0.0.1', () => resolve(true));\n\t\t});\n\t\tif (!bound) return false;\n\n\t\t// Neither the server nor its timers hold `gkm dev` open; the dev server\n\t\t// and the watcher are what it runs for.\n\t\tserver.unref();\n\t\tthis.server = server;\n\t\tthis.view = await this.scan();\n\t\tthis.timers.push(\n\t\t\tsetInterval(() => void this.scan(), this.pollMs).unref(),\n\t\t\t// A comment line every 15s, so proxies and idle timeouts leave the\n\t\t\t// stream open.\n\t\t\tsetInterval(() => {\n\t\t\t\tfor (const { response } of this.streams) response.write(': ping\\n\\n');\n\t\t\t}, 15_000).unref(),\n\t\t);\n\t\treturn true;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tfor (const timer of this.timers) clearInterval(timer);\n\t\tthis.timers = [];\n\t\tfor (const { response } of this.streams) response.end();\n\t\tthis.streams.clear();\n\t\tconst server = this.server;\n\t\tthis.server = undefined;\n\t\tif (!server) return;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tserver.close(() => resolve());\n\t\t\tserver.closeAllConnections();\n\t\t});\n\t}\n\n\t/** Reads the registry, and tells every stream what changed. One at a time. */\n\tscan(): Promise<WorkspaceView[]> {\n\t\tconst run = (this.scanning ?? Promise.resolve()).then(async () => {\n\t\t\tconst next = await collect(liveSessions(this.registry));\n\t\t\tfor (const { workspace, event } of changes(this.view, next)) {\n\t\t\t\tthis.broadcast(workspace, event);\n\t\t\t}\n\t\t\tthis.view = next;\n\t\t\treturn next;\n\t\t});\n\t\tthis.scanning = run.catch(() => this.view);\n\t\treturn run;\n\t}\n\n\tprivate broadcast(workspace: WorkspaceView, event: DiscoveryEvent): void {\n\t\tthis.sequence += 1;\n\t\tfor (const stream of this.streams) {\n\t\t\tif (!visibleTo(workspace, stream.origin)) continue;\n\t\t\tsend(stream.response, event, this.sequence);\n\t\t}\n\t}\n\n\tprivate snapshot(origin: string | undefined): DiscoveryResponse {\n\t\treturn {\n\t\t\tversion: 1,\n\t\t\thost: { pid: process.pid, port: this.port ?? 0 },\n\t\t\tevents: `${BASE}/events`,\n\t\t\tworkspaces: this.view.filter((w) => visibleTo(w, origin)).map(publicView),\n\t\t};\n\t}\n\n\tprivate async handle(\n\t\trequest: IncomingMessage,\n\t\tresponse: ServerResponse,\n\t): Promise<void> {\n\t\t// Rebinding: a page on `evil.example` that resolves to 127.0.0.1 sends\n\t\t// `Host: evil.example`. Only our own names, with our own port.\n\t\tconst port = this.port;\n\t\tconst host = request.headers.host;\n\t\tif (host !== `127.0.0.1:${port}` && host !== `localhost:${port}`) {\n\t\t\treply(response, 403, {\n\t\t\t\terror: 'HostNotAllowed',\n\t\t\t\tmessage: `Reach discovery at http://127.0.0.1:${port}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst origin = request.headers.origin;\n\t\tconst allowed = this.view.flatMap((w) => w.allowedOrigins);\n\t\tif (origin !== undefined && !allowed.includes(origin)) {\n\t\t\t// No CORS headers: the browser hides even this answer from the page.\n\t\t\treply(response, 403, {\n\t\t\t\terror: 'OriginNotAllowed',\n\t\t\t\tmessage: `Add ${origin} to dev.allowedOrigins in gkm.config.ts to let it read gkm dev.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (origin !== undefined) {\n\t\t\tresponse.setHeader('access-control-allow-origin', origin);\n\t\t\tresponse.setHeader('vary', 'Origin');\n\t\t}\n\n\t\tif (request.method === 'OPTIONS') {\n\t\t\t// A preflight carries no credentials, so it is answered before the\n\t\t\t// token is asked for — only for an origin that was listed.\n\t\t\tresponse.setHeader('access-control-allow-methods', 'GET, HEAD');\n\t\t\tresponse.setHeader('access-control-allow-headers', 'Authorization');\n\t\t\tresponse.setHeader('access-control-max-age', '600');\n\t\t\tif (request.headers['access-control-request-private-network']) {\n\t\t\t\tresponse.setHeader('access-control-allow-private-network', 'true');\n\t\t\t}\n\t\t\tresponse.writeHead(204).end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(request.url ?? '/', `http://${host}`);\n\t\tif (!this.authorized(request, url)) {\n\t\t\treply(response, 401, {\n\t\t\t\terror: 'TokenRequired',\n\t\t\t\tmessage:\n\t\t\t\t\t'Use the connect URL gkm dev printed, or send its token as `Authorization: Bearer <token>`.',\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (request.method !== 'GET' && request.method !== 'HEAD') {\n\t\t\tresponse.setHeader('allow', 'GET, HEAD, OPTIONS');\n\t\t\treply(response, 405, {\n\t\t\t\terror: 'ReadOnly',\n\t\t\t\tmessage: 'Discovery is read-only: GET and HEAD.',\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst path = url.pathname.replace(/\\/+$/, '') || '/';\n\t\tif (path === BASE) {\n\t\t\tawait this.scan();\n\t\t\treply(response, 200, this.snapshot(origin));\n\t\t\treturn;\n\t\t}\n\t\tif (path === `${BASE}/events`) {\n\t\t\tawait this.scan();\n\t\t\tthis.stream(response, origin);\n\t\t\tresponse.once('close', () => {\n\t\t\t\tfor (const stream of this.streams) {\n\t\t\t\t\tif (stream.response === response) this.streams.delete(stream);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst forwarded = path.match(\n\t\t\t/^\\/__gkm\\/workspaces\\/([^/]+)\\/apps\\/([^/]+)(\\/.*)$/,\n\t\t);\n\t\tif (forwarded) {\n\t\t\tconst [, id, name, rest] = forwarded;\n\t\t\tawait this.forward(\n\t\t\t\trequest,\n\t\t\t\tresponse,\n\t\t\t\torigin,\n\t\t\t\tid!,\n\t\t\t\tdecodeURIComponent(name!),\n\t\t\t\trest!,\n\t\t\t\turl,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\treply(response, 404, { error: 'NotFound' });\n\t}\n\n\tprivate authorized(request: IncomingMessage, url: URL): boolean {\n\t\tconst header = request.headers.authorization;\n\t\tconst given = header?.startsWith('Bearer ')\n\t\t\t? header.slice('Bearer '.length).trim()\n\t\t\t: url.searchParams.get('token');\n\t\tif (!given) return false;\n\t\tconst a = Buffer.from(given);\n\t\tconst b = Buffer.from(this.token);\n\t\treturn a.length === b.length && timingSafeEqual(a, b);\n\t}\n\n\tprivate stream(response: ServerResponse, origin: string | undefined): void {\n\t\tresponse.writeHead(200, {\n\t\t\t'content-type': 'text/event-stream',\n\t\t\t'cache-control': 'no-cache',\n\t\t\tconnection: 'keep-alive',\n\t\t});\n\t\t// When the host changes, `EventSource` reconnects — to the new one.\n\t\tresponse.write('retry: 1000\\n\\n');\n\t\tsend(response, { type: 'snapshot', snapshot: this.snapshot(origin) });\n\t\tthis.streams.add({ origin, response });\n\t}\n\n\t/** Passes a read of one data API on to the app that serves it. */\n\tprivate async forward(\n\t\trequest: IncomingMessage,\n\t\tresponse: ServerResponse,\n\t\torigin: string | undefined,\n\t\tid: string,\n\t\tname: string,\n\t\tpath: string,\n\t\turl: URL,\n\t): Promise<void> {\n\t\tconst workspace = this.view.find(\n\t\t\t(w) => w.id === id && visibleTo(w, origin),\n\t\t);\n\t\tconst app = workspace?.apps.find((a) => a.name === name);\n\t\tif (!app) {\n\t\t\treply(response, 404, { error: 'AppNotFound' });\n\t\t\treturn;\n\t\t}\n\t\tif (!servesData(app, path)) {\n\t\t\treply(response, 404, {\n\t\t\t\terror: 'NotADataApi',\n\t\t\t\tmessage: `Only ${name}'s data APIs are forwarded: ${app.dataApis.map((a) => a.path).join(', ') || 'it has none'}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// The token is ours, not the app's.\n\t\tconst search = new URLSearchParams(url.searchParams);\n\t\tsearch.delete('token');\n\t\tconst query = search.size > 0 ? `?${search}` : '';\n\n\t\t// The response, not the request: a request's `close` fires once its\n\t\t// (empty) body is read, which would abort the read straight away.\n\t\tconst abort = new AbortController();\n\t\tresponse.once('close', () => abort.abort());\n\t\tlet upstream: Response;\n\t\ttry {\n\t\t\tupstream = await fetch(`http://localhost:${app.port}${path}${query}`, {\n\t\t\t\tmethod: request.method,\n\t\t\t\t// Only what describes the read: no cookies, no credentials.\n\t\t\t\theaders: { accept: request.headers.accept ?? '*/*' },\n\t\t\t\tsignal: abort.signal,\n\t\t\t});\n\t\t} catch {\n\t\t\treply(response, 502, {\n\t\t\t\terror: 'AppUnavailable',\n\t\t\t\tmessage: `${name} is not answering on port ${app.port}.`,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst headers: Record<string, string> = {};\n\t\tfor (const key of FORWARDED_RESPONSE_HEADERS) {\n\t\t\tconst value = upstream.headers.get(key);\n\t\t\tif (value) headers[key] = value;\n\t\t}\n\t\tresponse.writeHead(upstream.status, headers);\n\t\tif (!upstream.body || request.method === 'HEAD') {\n\t\t\tresponse.end();\n\t\t\treturn;\n\t\t}\n\t\tReadable.fromWeb(upstream.body as never)\n\t\t\t.on('error', () => response.destroy())\n\t\t\t.pipe(response);\n\t}\n}\n\nfunction reply(response: ServerResponse, status: number, body: unknown) {\n\tresponse.writeHead(status, { 'content-type': 'application/json' });\n\tresponse.end(JSON.stringify(body));\n}\n\nfunction send(response: ServerResponse, event: DiscoveryEvent, id?: number) {\n\tresponse.write(\n\t\t`${id === undefined ? '' : `id: ${id}\\n`}event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// A session\n// ---------------------------------------------------------------------------\n\nexport interface JoinDiscoveryOptions {\n\trole: DevSessionRecord['role'];\n\tworkspace: DevSessionRecord['workspace'];\n\tallowedOrigins?: readonly string[];\n\tmanifest?: ConstructManifest;\n\tapps: SessionApp[];\n\t/** `0` hosts on a free port of its own, and never hands over. */\n\tport?: number;\n\tregistry?: string;\n\t/** How often the host rereads the registry. */\n\tpollMs?: number;\n\t/** How often a session that is not hosting tries to take over. */\n\telectionMs?: number;\n}\n\n/**\n * One `gkm dev`'s membership: its record in the registry, and — while it holds\n * the port — the endpoint itself.\n */\nexport class DiscoverySession {\n\tprivate host: DiscoveryHost | undefined;\n\tprivate election: NodeJS.Timeout | undefined;\n\tprivate left = false;\n\tprivate readonly cleanup = () => removeRecord(this.registry, this.record.id);\n\n\tprivate constructor(\n\t\tprivate readonly registry: string,\n\t\tprivate readonly port: number,\n\t\tprivate readonly record: DevSessionRecord,\n\t\treadonly token: string,\n\t\tprivate readonly pollMs: number,\n\t) {}\n\n\tstatic async join(options: JoinDiscoveryOptions): Promise<DiscoverySession> {\n\t\tconst registry = options.registry ?? discoveryRegistry();\n\t\tmkdirSync(sessionsDir(registry), { recursive: true, mode: 0o700 });\n\n\t\tconst now = new Date().toISOString();\n\t\tconst record: DevSessionRecord = {\n\t\t\tid: `${process.pid}-${randomBytes(4).toString('hex')}`,\n\t\t\tpid: process.pid,\n\t\t\trole: options.role,\n\t\t\tstartedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tworkspace: options.workspace,\n\t\t\tallowedOrigins: [...(options.allowedOrigins ?? [])],\n\t\t\t...(options.manifest ? { manifest: options.manifest } : {}),\n\t\t\tapps: options.apps,\n\t\t};\n\t\t// Registered before the token is settled, so a session starting at the\n\t\t// same moment sees this one and does not replace the token under it.\n\t\twriteRecord(registry, record);\n\t\tconst token = sessionToken(registry, record.id);\n\n\t\tconst session = new DiscoverySession(\n\t\t\tregistry,\n\t\t\toptions.port ?? DEFAULT_DISCOVERY_PORT,\n\t\t\trecord,\n\t\t\ttoken,\n\t\t\toptions.pollMs ?? 500,\n\t\t);\n\t\tprocess.once('exit', session.cleanup);\n\n\t\tawait session.elect();\n\t\t// On port 0 every session hosts its own, so there is nothing to take\n\t\t// over.\n\t\tif (!session.host && session.port !== 0) {\n\t\t\tsession.election = setInterval(\n\t\t\t\t() => void session.elect(),\n\t\t\t\toptions.electionMs ?? 1000,\n\t\t\t).unref();\n\t\t}\n\t\treturn session;\n\t}\n\n\t/** Whether this session is the one serving the endpoint. */\n\tget hosting(): boolean {\n\t\treturn this.host !== undefined;\n\t}\n\n\t/** The port clients reach — this host's own, when it chose one. */\n\tget endpointPort(): number {\n\t\treturn this.host?.port ?? this.port;\n\t}\n\n\t/** Jupyter-style: the endpoint, with the token that opens it. */\n\tget connectUrl(): string {\n\t\treturn `http://127.0.0.1:${this.endpointPort}${BASE}?token=${this.token}`;\n\t}\n\n\t/** Changes one of this session's apps, and tells the endpoint. */\n\tupdateApp(name: string, change: (app: SessionApp) => SessionApp): void {\n\t\tif (this.left) return;\n\t\tthis.record.apps = this.record.apps.map((app) =>\n\t\t\tapp.name === name ? change(app) : app,\n\t\t);\n\t\tthis.record.updatedAt = new Date().toISOString();\n\t\twriteRecord(this.registry, this.record);\n\t\t// The host hears of its own changes now, not on its next poll.\n\t\tvoid this.host?.scan();\n\t}\n\n\t/** Leaves the registry, and the port to whichever session takes it next. */\n\tasync leave(): Promise<void> {\n\t\tif (this.left) return;\n\t\tthis.left = true;\n\t\tif (this.election) clearInterval(this.election);\n\t\tprocess.removeListener('exit', this.cleanup);\n\t\tthis.cleanup();\n\t\tawait this.host?.close();\n\t\tthis.host = undefined;\n\t\t// The last one out takes the token with it.\n\t\tif (liveSessions(this.registry).length === 0) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(join(this.registry, 'token'));\n\t\t\t} catch {\n\t\t\t\t// Already gone.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async elect(): Promise<void> {\n\t\tif (this.host || this.left) return;\n\t\tconst host = new DiscoveryHost(this.registry, this.token, this.pollMs);\n\t\tif (!(await host.listen(this.port))) return;\n\t\tif (this.left) {\n\t\t\tawait host.close();\n\t\t\treturn;\n\t\t}\n\t\tthis.host = host;\n\t\tif (this.election) clearInterval(this.election);\n\t\tthis.election = undefined;\n\t}\n}\n\n/** Joins the machine's discovery; see {@link DiscoverySession}. */\nexport function joinDiscovery(\n\toptions: JoinDiscoveryOptions,\n): Promise<DiscoverySession> {\n\treturn DiscoverySession.join(options);\n}\n\n/** The data APIs a generated dev app mounts, from what `gkm dev` built. */\nexport function dataApisOf(options: {\n\tselfServing: boolean;\n\ttelescopePath?: string;\n\tdatabaseApi?: string;\n\topenApi: boolean;\n}): SessionDataApi[] {\n\t// An app that serves itself — an auth server — mounts none of them.\n\tif (options.selfServing) return [];\n\treturn [\n\t\t...(options.telescopePath\n\t\t\t? [{ kind: 'telescope' as const, path: `${options.telescopePath}/api` }]\n\t\t\t: []),\n\t\t...(options.databaseApi\n\t\t\t? [{ kind: 'database' as const, path: options.databaseApi }]\n\t\t\t: []),\n\t\t...(options.openApi ? [{ kind: 'openapi' as const, path: '/__docs' }] : []),\n\t];\n}\n","// src/server.ts\nimport { createServer as createServerHTTP } from \"http\";\n\n// src/listener.ts\nimport { Http2ServerRequest as Http2ServerRequest2 } from \"http2\";\n\n// src/request.ts\nimport { Http2ServerRequest } from \"http2\";\nimport { Readable } from \"stream\";\nvar RequestError = class extends Error {\n constructor(message, options) {\n super(message, options);\n this.name = \"RequestError\";\n }\n};\nvar toRequestError = (e) => {\n if (e instanceof RequestError) {\n return e;\n }\n return new RequestError(e.message, { cause: e });\n};\nvar GlobalRequest = global.Request;\nvar Request = class extends GlobalRequest {\n constructor(input, options) {\n if (typeof input === \"object\" && getRequestCache in input) {\n input = input[getRequestCache]();\n }\n if (typeof options?.body?.getReader !== \"undefined\") {\n ;\n options.duplex ??= \"half\";\n }\n super(input, options);\n }\n};\nvar newHeadersFromIncoming = (incoming) => {\n const headerRecord = [];\n const rawHeaders = incoming.rawHeaders;\n for (let i = 0; i < rawHeaders.length; i += 2) {\n const { [i]: key, [i + 1]: value } = rawHeaders;\n if (key.charCodeAt(0) !== /*:*/\n 58) {\n headerRecord.push([key, value]);\n }\n }\n return new Headers(headerRecord);\n};\nvar wrapBodyStream = Symbol(\"wrapBodyStream\");\nvar newRequestFromIncoming = (method, url, headers, incoming, abortController) => {\n const init = {\n method,\n headers,\n signal: abortController.signal\n };\n if (method === \"TRACE\") {\n init.method = \"GET\";\n const req = new Request(url, init);\n Object.defineProperty(req, \"method\", {\n get() {\n return \"TRACE\";\n }\n });\n return req;\n }\n if (!(method === \"GET\" || method === \"HEAD\")) {\n if (\"rawBody\" in incoming && incoming.rawBody instanceof Buffer) {\n init.body = new ReadableStream({\n start(controller) {\n controller.enqueue(incoming.rawBody);\n controller.close();\n }\n });\n } else if (incoming[wrapBodyStream]) {\n let reader;\n init.body = new ReadableStream({\n async pull(controller) {\n try {\n reader ||= Readable.toWeb(incoming).getReader();\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n });\n } else {\n init.body = Readable.toWeb(incoming);\n }\n }\n return new Request(url, init);\n};\nvar getRequestCache = Symbol(\"getRequestCache\");\nvar requestCache = Symbol(\"requestCache\");\nvar incomingKey = Symbol(\"incomingKey\");\nvar urlKey = Symbol(\"urlKey\");\nvar headersKey = Symbol(\"headersKey\");\nvar abortControllerKey = Symbol(\"abortControllerKey\");\nvar getAbortController = Symbol(\"getAbortController\");\nvar requestPrototype = {\n get method() {\n return this[incomingKey].method || \"GET\";\n },\n get url() {\n return this[urlKey];\n },\n get headers() {\n return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);\n },\n [getAbortController]() {\n this[getRequestCache]();\n return this[abortControllerKey];\n },\n [getRequestCache]() {\n this[abortControllerKey] ||= new AbortController();\n return this[requestCache] ||= newRequestFromIncoming(\n this.method,\n this[urlKey],\n this.headers,\n this[incomingKey],\n this[abortControllerKey]\n );\n }\n};\n[\n \"body\",\n \"bodyUsed\",\n \"cache\",\n \"credentials\",\n \"destination\",\n \"integrity\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"keepalive\"\n].forEach((k) => {\n Object.defineProperty(requestPrototype, k, {\n get() {\n return this[getRequestCache]()[k];\n }\n });\n});\n[\"arrayBuffer\", \"blob\", \"clone\", \"formData\", \"json\", \"text\"].forEach((k) => {\n Object.defineProperty(requestPrototype, k, {\n value: function() {\n return this[getRequestCache]()[k]();\n }\n });\n});\nObject.setPrototypeOf(requestPrototype, Request.prototype);\nvar newRequest = (incoming, defaultHostname) => {\n const req = Object.create(requestPrototype);\n req[incomingKey] = incoming;\n const incomingUrl = incoming.url || \"\";\n if (incomingUrl[0] !== \"/\" && // short-circuit for performance. most requests are relative URL.\n (incomingUrl.startsWith(\"http://\") || incomingUrl.startsWith(\"https://\"))) {\n if (incoming instanceof Http2ServerRequest) {\n throw new RequestError(\"Absolute URL for :path is not allowed in HTTP/2\");\n }\n try {\n const url2 = new URL(incomingUrl);\n req[urlKey] = url2.href;\n } catch (e) {\n throw new RequestError(\"Invalid absolute URL\", { cause: e });\n }\n return req;\n }\n const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;\n if (!host) {\n throw new RequestError(\"Missing host header\");\n }\n let scheme;\n if (incoming instanceof Http2ServerRequest) {\n scheme = incoming.scheme;\n if (!(scheme === \"http\" || scheme === \"https\")) {\n throw new RequestError(\"Unsupported scheme\");\n }\n } else {\n scheme = incoming.socket && incoming.socket.encrypted ? \"https\" : \"http\";\n }\n const url = new URL(`${scheme}://${host}${incomingUrl}`);\n if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\\d+$/, \"\")) {\n throw new RequestError(\"Invalid host header\");\n }\n req[urlKey] = url.href;\n return req;\n};\n\n// src/response.ts\nvar responseCache = Symbol(\"responseCache\");\nvar getResponseCache = Symbol(\"getResponseCache\");\nvar cacheKey = Symbol(\"cache\");\nvar GlobalResponse = global.Response;\nvar Response2 = class _Response {\n #body;\n #init;\n [getResponseCache]() {\n delete this[cacheKey];\n return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);\n }\n constructor(body, init) {\n let headers;\n this.#body = body;\n if (init instanceof _Response) {\n const cachedGlobalResponse = init[responseCache];\n if (cachedGlobalResponse) {\n this.#init = cachedGlobalResponse;\n this[getResponseCache]();\n return;\n } else {\n this.#init = init.#init;\n headers = new Headers(init.#init.headers);\n }\n } else {\n this.#init = init;\n }\n if (typeof body === \"string\" || typeof body?.getReader !== \"undefined\" || body instanceof Blob || body instanceof Uint8Array) {\n headers ||= init?.headers || { \"content-type\": \"text/plain; charset=UTF-8\" };\n this[cacheKey] = [init?.status || 200, body, headers];\n }\n }\n get headers() {\n const cache = this[cacheKey];\n if (cache) {\n if (!(cache[2] instanceof Headers)) {\n cache[2] = new Headers(cache[2]);\n }\n return cache[2];\n }\n return this[getResponseCache]().headers;\n }\n get status() {\n return this[cacheKey]?.[0] ?? this[getResponseCache]().status;\n }\n get ok() {\n const status = this.status;\n return status >= 200 && status < 300;\n }\n};\n[\"body\", \"bodyUsed\", \"redirected\", \"statusText\", \"trailers\", \"type\", \"url\"].forEach((k) => {\n Object.defineProperty(Response2.prototype, k, {\n get() {\n return this[getResponseCache]()[k];\n }\n });\n});\n[\"arrayBuffer\", \"blob\", \"clone\", \"formData\", \"json\", \"text\"].forEach((k) => {\n Object.defineProperty(Response2.prototype, k, {\n value: function() {\n return this[getResponseCache]()[k]();\n }\n });\n});\nObject.setPrototypeOf(Response2, GlobalResponse);\nObject.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);\n\n// src/utils.ts\nasync function readWithoutBlocking(readPromise) {\n return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);\n}\nfunction writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {\n const cancel = (error) => {\n reader.cancel(error).catch(() => {\n });\n };\n writable.on(\"close\", cancel);\n writable.on(\"error\", cancel);\n (currentReadPromise ?? reader.read()).then(flow, handleStreamError);\n return reader.closed.finally(() => {\n writable.off(\"close\", cancel);\n writable.off(\"error\", cancel);\n });\n function handleStreamError(error) {\n if (error) {\n writable.destroy(error);\n }\n }\n function onDrain() {\n reader.read().then(flow, handleStreamError);\n }\n function flow({ done, value }) {\n try {\n if (done) {\n writable.end();\n } else if (!writable.write(value)) {\n writable.once(\"drain\", onDrain);\n } else {\n return reader.read().then(flow, handleStreamError);\n }\n } catch (e) {\n handleStreamError(e);\n }\n }\n}\nfunction writeFromReadableStream(stream, writable) {\n if (stream.locked) {\n throw new TypeError(\"ReadableStream is locked.\");\n } else if (writable.destroyed) {\n return;\n }\n return writeFromReadableStreamDefaultReader(stream.getReader(), writable);\n}\nvar buildOutgoingHttpHeaders = (headers) => {\n const res = {};\n if (!(headers instanceof Headers)) {\n headers = new Headers(headers ?? void 0);\n }\n const cookies = [];\n for (const [k, v] of headers) {\n if (k === \"set-cookie\") {\n cookies.push(v);\n } else {\n res[k] = v;\n }\n }\n if (cookies.length > 0) {\n res[\"set-cookie\"] = cookies;\n }\n res[\"content-type\"] ??= \"text/plain; charset=UTF-8\";\n return res;\n};\n\n// src/utils/response/constants.ts\nvar X_ALREADY_SENT = \"x-hono-already-sent\";\n\n// src/globals.ts\nimport crypto from \"crypto\";\nvar webFetch = global.fetch;\nif (typeof global.crypto === \"undefined\") {\n global.crypto = crypto;\n}\nglobal.fetch = (info, init) => {\n init = {\n // Disable compression handling so people can return the result of a fetch\n // directly in the loader without messing with the Content-Encoding header.\n compress: false,\n ...init\n };\n return webFetch(info, init);\n};\n\n// src/listener.ts\nvar outgoingEnded = Symbol(\"outgoingEnded\");\nvar handleRequestError = () => new Response(null, {\n status: 400\n});\nvar handleFetchError = (e) => new Response(null, {\n status: e instanceof Error && (e.name === \"TimeoutError\" || e.constructor.name === \"TimeoutError\") ? 504 : 500\n});\nvar handleResponseError = (e, outgoing) => {\n const err = e instanceof Error ? e : new Error(\"unknown error\", { cause: e });\n if (err.code === \"ERR_STREAM_PREMATURE_CLOSE\") {\n console.info(\"The user aborted a request.\");\n } else {\n console.error(e);\n if (!outgoing.headersSent) {\n outgoing.writeHead(500, { \"Content-Type\": \"text/plain\" });\n }\n outgoing.end(`Error: ${err.message}`);\n outgoing.destroy(err);\n }\n};\nvar flushHeaders = (outgoing) => {\n if (\"flushHeaders\" in outgoing && outgoing.writable) {\n outgoing.flushHeaders();\n }\n};\nvar responseViaCache = async (res, outgoing) => {\n let [status, body, header] = res[cacheKey];\n if (header instanceof Headers) {\n header = buildOutgoingHttpHeaders(header);\n }\n if (typeof body === \"string\") {\n header[\"Content-Length\"] = Buffer.byteLength(body);\n } else if (body instanceof Uint8Array) {\n header[\"Content-Length\"] = body.byteLength;\n } else if (body instanceof Blob) {\n header[\"Content-Length\"] = body.size;\n }\n outgoing.writeHead(status, header);\n if (typeof body === \"string\" || body instanceof Uint8Array) {\n outgoing.end(body);\n } else if (body instanceof Blob) {\n outgoing.end(new Uint8Array(await body.arrayBuffer()));\n } else {\n flushHeaders(outgoing);\n await writeFromReadableStream(body, outgoing)?.catch(\n (e) => handleResponseError(e, outgoing)\n );\n }\n ;\n outgoing[outgoingEnded]?.();\n};\nvar isPromise = (res) => typeof res.then === \"function\";\nvar responseViaResponseObject = async (res, outgoing, options = {}) => {\n if (isPromise(res)) {\n if (options.errorHandler) {\n try {\n res = await res;\n } catch (err) {\n const errRes = await options.errorHandler(err);\n if (!errRes) {\n return;\n }\n res = errRes;\n }\n } else {\n res = await res.catch(handleFetchError);\n }\n }\n if (cacheKey in res) {\n return responseViaCache(res, outgoing);\n }\n const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);\n if (res.body) {\n const reader = res.body.getReader();\n const values = [];\n let done = false;\n let currentReadPromise = void 0;\n if (resHeaderRecord[\"transfer-encoding\"] !== \"chunked\") {\n let maxReadCount = 2;\n for (let i = 0; i < maxReadCount; i++) {\n currentReadPromise ||= reader.read();\n const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {\n console.error(e);\n done = true;\n });\n if (!chunk) {\n if (i === 1) {\n await new Promise((resolve) => setTimeout(resolve));\n maxReadCount = 3;\n continue;\n }\n break;\n }\n currentReadPromise = void 0;\n if (chunk.value) {\n values.push(chunk.value);\n }\n if (chunk.done) {\n done = true;\n break;\n }\n }\n if (done && !(\"content-length\" in resHeaderRecord)) {\n resHeaderRecord[\"content-length\"] = values.reduce((acc, value) => acc + value.length, 0);\n }\n }\n outgoing.writeHead(res.status, resHeaderRecord);\n values.forEach((value) => {\n ;\n outgoing.write(value);\n });\n if (done) {\n outgoing.end();\n } else {\n if (values.length === 0) {\n flushHeaders(outgoing);\n }\n await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);\n }\n } else if (resHeaderRecord[X_ALREADY_SENT]) {\n } else {\n outgoing.writeHead(res.status, resHeaderRecord);\n outgoing.end();\n }\n ;\n outgoing[outgoingEnded]?.();\n};\nvar getRequestListener = (fetchCallback, options = {}) => {\n const autoCleanupIncoming = options.autoCleanupIncoming ?? true;\n if (options.overrideGlobalObjects !== false && global.Request !== Request) {\n Object.defineProperty(global, \"Request\", {\n value: Request\n });\n Object.defineProperty(global, \"Response\", {\n value: Response2\n });\n }\n return async (incoming, outgoing) => {\n let res, req;\n try {\n req = newRequest(incoming, options.hostname);\n let incomingEnded = !autoCleanupIncoming || incoming.method === \"GET\" || incoming.method === \"HEAD\";\n if (!incomingEnded) {\n ;\n incoming[wrapBodyStream] = true;\n incoming.on(\"end\", () => {\n incomingEnded = true;\n });\n if (incoming instanceof Http2ServerRequest2) {\n ;\n outgoing[outgoingEnded] = () => {\n if (!incomingEnded) {\n setTimeout(() => {\n if (!incomingEnded) {\n setTimeout(() => {\n incoming.destroy();\n outgoing.destroy();\n });\n }\n });\n }\n };\n }\n }\n outgoing.on(\"close\", () => {\n const abortController = req[abortControllerKey];\n if (abortController) {\n if (incoming.errored) {\n req[abortControllerKey].abort(incoming.errored.toString());\n } else if (!outgoing.writableFinished) {\n req[abortControllerKey].abort(\"Client connection prematurely closed.\");\n }\n }\n if (!incomingEnded) {\n setTimeout(() => {\n if (!incomingEnded) {\n setTimeout(() => {\n incoming.destroy();\n });\n }\n });\n }\n });\n res = fetchCallback(req, { incoming, outgoing });\n if (cacheKey in res) {\n return responseViaCache(res, outgoing);\n }\n } catch (e) {\n if (!res) {\n if (options.errorHandler) {\n res = await options.errorHandler(req ? e : toRequestError(e));\n if (!res) {\n return;\n }\n } else if (!req) {\n res = handleRequestError();\n } else {\n res = handleFetchError(e);\n }\n } else {\n return handleResponseError(e, outgoing);\n }\n }\n try {\n return await responseViaResponseObject(res, outgoing, options);\n } catch (e) {\n return handleResponseError(e, outgoing);\n }\n };\n};\n\n// src/server.ts\nvar createAdaptorServer = (options) => {\n const fetchCallback = options.fetch;\n const requestListener = getRequestListener(fetchCallback, {\n hostname: options.hostname,\n overrideGlobalObjects: options.overrideGlobalObjects,\n autoCleanupIncoming: options.autoCleanupIncoming\n });\n const createServer = options.createServer || createServerHTTP;\n const server = createServer(options.serverOptions || {}, requestListener);\n return server;\n};\nvar serve = (options, listeningListener) => {\n const server = createAdaptorServer(options);\n server.listen(options?.port ?? 3e3, options.hostname, () => {\n const serverInfo = server.address();\n listeningListener && listeningListener(serverInfo);\n });\n return server;\n};\nexport {\n RequestError,\n createAdaptorServer,\n getRequestListener,\n serve\n};\n","/**\n * External APIs' app fakes, served for `gkm dev`.\n *\n * An image fake runs with the other containers. An app fake is a fetch handler\n * in `test/fakes/<id>.ts`, and nothing runs it unless this does: each one\n * listens on the port its key was allocated, which is the port the stage's\n * `<ID>_URL` already names.\n */\n\nimport { pathToFileURL } from 'node:url';\nimport type { Fake } from '@geekmidas/constructs/external-api';\nimport { type ServerType, serve } from '@hono/node-server';\nimport { fakeKey } from '../reconcile/containers.js';\nimport type { LocalFake } from '../reconcile/fakes.js';\nimport type { PortAssignments } from '../reconcile/ports.js';\n\n/** One app fake, listening. */\nexport interface ServedFake {\n\tid: string;\n\tport: number;\n\tserver: ServerType;\n}\n\n/**\n * Serve every app fake on its allocated port. Image fakes are skipped — their\n * containers are already up.\n */\nexport async function serveFakes(\n\tfakes: Readonly<Record<string, LocalFake>>,\n\tports: PortAssignments,\n): Promise<ServedFake[]> {\n\tconst served: ServedFake[] = [];\n\n\tfor (const [id, local] of Object.entries(fakes)) {\n\t\tif (local.image) continue;\n\n\t\tconst port = ports[fakeKey(id)];\n\t\tif (port === undefined) continue;\n\n\t\t// Read by `readFakes` already, so the module is known to be a fake.\n\t\tconst module = (await import(pathToFileURL(local.file).href)) as {\n\t\t\tdefault: Extract<Fake, { kind: 'app' }>;\n\t\t};\n\t\tconst { handler } = module.default;\n\t\tconst server = serve({ fetch: (request) => handler.fetch(request), port });\n\t\tserved.push({ id, port, server });\n\t}\n\n\treturn served;\n}\n\n/** Stop every served fake. */\nexport function closeFakes(served: readonly ServedFake[]): void {\n\tfor (const { server } of served) server.close();\n}\n","import { spawn } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { imageBuildCredentials, isImageBuild } from './imageBuild';\n\nconst logger = console;\n\n/** `gkm exec` was given nothing to run. */\nexport class NoCommandSpecified extends Error {\n\tconstructor() {\n\t\tsuper('No command specified. Usage: gkm exec -- <command>');\n\t\tthis.name = 'NoCommandSpecified';\n\t}\n}\n\n/**\n * Options for the exec command.\n */\nexport interface ExecOptions {\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Run a command with secrets injected into Credentials.\n * Uses Node's --import flag to preload a script that populates Credentials\n * before the command loads any modules that depend on them.\n *\n * @example\n * ```bash\n * gkm exec -- npx @better-auth/cli migrate\n * gkm exec -- npx prisma migrate dev\n * ```\n */\nexport async function execCommand(\n\tcommandArgs: string[],\n\toptions: ExecOptions = {},\n): Promise<void> {\n\tconst cwd = options.cwd ?? process.cwd();\n\n\tif (!commandArgs[0]) {\n\t\tthrow new NoCommandSpecified();\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials: loads secrets, resolves Docker ports, rewrites URLs,\n\t// injects dependency URLs. Uses readonly port mode (no probing for new ports).\n\t//\n\t// Inside an image build there is none of that to do: the build args are the\n\t// stage's public values, and nothing on a developer's machine is reachable.\n\tconst { credentials, secretsJsonPath, appName } = isImageBuild()\n\t\t? await imageBuildEntry(cwd)\n\t\t: await prepareEntryCredentials({ cwd });\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName}`);\n\t}\n\n\tconst secretCount = Object.keys(credentials).filter(\n\t\t(k) => k !== 'PORT',\n\t).length;\n\tif (secretCount > 0 && !isImageBuild()) {\n\t\tlogger.log(`🔐 Loaded ${secretCount} secret(s)`);\n\t}\n\n\t// Create preload script that injects Credentials\n\t// Written as .mjs (plain ESM) so it doesn't need tsx — this avoids\n\t// breaking frameworks like Next.js whose workers inherit NODE_OPTIONS.\n\tconst preloadDir = join(cwd, '.gkm');\n\tawait mkdir(preloadDir, { recursive: true });\n\tconst preloadPath = join(preloadDir, 'credentials-preload.mjs');\n\tawait createCredentialsPreload(preloadPath, secretsJsonPath);\n\n\t// Build command\n\tconst [cmd, ...args] = commandArgs as [string, ...string[]];\n\n\tlogger.log(`🚀 Running: ${[cmd, ...args].join(' ')}`);\n\n\t// Build NODE_OPTIONS for the child process.\n\t// Strip any --import flags from the inherited NODE_OPTIONS — the gkm binary\n\t// adds --import=tsx for itself, but the spawned command (e.g. next, prisma)\n\t// doesn't need it and it breaks frameworks that spawn their own workers.\n\tconst existingNodeOptions = (process.env.NODE_OPTIONS ?? '')\n\t\t.replace(/--import[= ]\\S+/g, '')\n\t\t.trim();\n\tconst preloadImport = `--import=${preloadPath}`;\n\n\tconst nodeOptions = [existingNodeOptions, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Spawn the command with secrets in both:\n\t// 1. Environment variables (for tools that read process.env directly)\n\t// 2. Preload script (for tools that use Credentials object)\n\tconst child = spawn(cmd, args, {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...credentials, // Inject secrets as env vars\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for the command to complete\n\tconst exitCode = await new Promise<number>((resolve) => {\n\t\tchild.on('close', (code: number | null) => resolve(code ?? 0));\n\t\tchild.on('error', (error: Error) => {\n\t\t\tlogger.error(`Failed to run command: ${error.message}`);\n\t\t\tresolve(1);\n\t\t});\n\t});\n\n\tif (exitCode !== 0) {\n\t\tprocess.exit(exitCode);\n\t}\n}\n\n/**\n * `gkm exec` inside an image build: the public values the Dockerfile's build\n * args set, written where the preload reads them. No workspace is loaded, no\n * secret read and no address resolved.\n */\nasync function imageBuildEntry(cwd: string): Promise<{\n\tcredentials: Record<string, string>;\n\tsecretsJsonPath: string;\n\tappName?: string;\n}> {\n\tconst credentials = imageBuildCredentials();\n\tlogger.log(\n\t\t`🐳 Image build: ${Object.keys(credentials).length} public value(s) from the build args`,\n\t);\n\tconst dir = join(cwd, '.gkm');\n\tawait mkdir(dir, { recursive: true });\n\tconst secretsJsonPath = join(dir, 'image-build-env.json');\n\tawait writeFile(secretsJsonPath, JSON.stringify(credentials, null, 2));\n\treturn { credentials, secretsJsonPath };\n}\n","import { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport chokidar from 'chokidar';\nimport fg from 'fast-glob';\nimport { appPackageName, buildApp, turboFilters } from '../build/index';\nimport type {\n\tNormalizedHooksConfig,\n\tNormalizedProductionConfig,\n\tNormalizedTelescopeConfig,\n} from '../build/types';\nimport {\n\tloadAppConfig,\n\tloadWorkspaceConfig,\n\tNotABackendApp,\n\tNotInAnApp,\n\tparseModuleConfig,\n} from '../config';\nimport {\n\tcreateEntryWrapper,\n\tfindAvailablePort,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadSecretsForApp,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { resolveOpenApiConfig } from '../openapi';\nimport { withOwningTsconfigJsx } from '../owningTsconfigJsx.js';\nimport { describeServices } from '../reconcile/containers.js';\nimport { FAKE_ENV, reconcileWorkspace } from '../reconcile/workspace.js';\nimport { toEmbeddableSecrets } from '../secrets/storage.js';\nimport { FileSecretsStore, secretsStoreFor } from '../secrets/store.js';\nimport { ensureTrusted } from '../trust/index.js';\nimport type { GkmConfig, Runtime, TelescopeConfig } from '../types';\nimport {\n\tcacheBackendFor,\n\teventsBackendFor,\n\tproviderOf,\n} from '../workspace/backends.js';\nimport { appKey } from '../workspace/derive.js';\nimport {\n\ttype FrontendFramework,\n\tgetAppBuildOrder,\n\ttype MobileFramework,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport {\n\tAPP_TAG_ENV,\n\ttype AppRunning,\n\tappTag,\n\tassignAppPorts,\n\tdescribeHolder,\n\tholderOf,\n\twithAppPorts,\n} from './appPorts.js';\nimport {\n\ttype AppStatus,\n\tDISCOVERY_QUIET_ENV,\n\ttype DiscoverySession,\n\tdataApisOf,\n\tdiscoveryPort,\n\tjoinDiscovery,\n} from './discovery.js';\nimport { closeFakes, serveFakes } from './fakes.js';\n\n// Re-export shared utilities from credentials module so existing imports\n// from '../dev' or '../dev/index' continue to work.\nexport {\n\tcreateCredentialsPreload,\n\tcreateEntryWrapper,\n\ttype EntryCredentialsResult,\n\tfindAvailablePort,\n\tfindSecretsRoot,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadPortState,\n\tloadSecretsForApp,\n\ttype PortState,\n\tprepareEntryCredentials,\n\tsavePortState,\n} from '../credentials';\n\n// Re-export execCommand from its own module\nexport { type ExecOptions, execCommand } from '../exec';\n\nconst logger = console;\n\n/**\n * Normalize telescope configuration\n * @internal Exported for testing\n */\nexport function normalizeTelescopeConfig(\n\tconfig: GkmConfig['telescope'],\n): NormalizedTelescopeConfig | undefined {\n\tif (config === false) {\n\t\treturn undefined;\n\t}\n\n\t// Handle string path (e.g., './src/config/telescope')\n\tif (typeof config === 'string') {\n\t\tconst { path: telescopePath, importPattern: telescopeImportPattern } =\n\t\t\tparseModuleConfig(config, 'telescope');\n\n\t\treturn {\n\t\t\tenabled: true,\n\t\t\ttelescopePath,\n\t\t\ttelescopeImportPattern,\n\t\t\tpath: '/__telescope',\n\t\t\tignore: [],\n\t\t\trecordBody: true,\n\t\t\tmaxEntries: 1000,\n\t\t\twebsocket: true,\n\t\t};\n\t}\n\n\t// Default to enabled in development mode\n\tconst isEnabled =\n\t\tconfig === true || config === undefined || config.enabled !== false;\n\n\tif (!isEnabled) {\n\t\treturn undefined;\n\t}\n\n\tconst telescopeConfig: TelescopeConfig =\n\t\ttypeof config === 'object' ? config : {};\n\n\treturn {\n\t\tenabled: true,\n\t\tpath: telescopeConfig.path ?? '/__telescope',\n\t\tignore: telescopeConfig.ignore ?? [],\n\t\trecordBody: telescopeConfig.recordBody ?? true,\n\t\tmaxEntries: telescopeConfig.maxEntries ?? 1000,\n\t\twebsocket: telescopeConfig.websocket ?? true,\n\t};\n}\n\n/**\n * Normalize hooks configuration\n * @internal Exported for testing\n */\nexport function normalizeHooksConfig(\n\tconfig: GkmConfig['hooks'],\n\tcwd: string = process.cwd(),\n): NormalizedHooksConfig | undefined {\n\tif (!config?.server) {\n\t\treturn undefined;\n\t}\n\n\t// Resolve the path (handle .ts extension)\n\tconst serverPath = config.server.endsWith('.ts')\n\t\t? config.server\n\t\t: `${config.server}.ts`;\n\n\tconst resolvedPath = resolve(cwd, serverPath);\n\n\treturn {\n\t\tserverHooksPath: resolvedPath,\n\t};\n}\n\n/**\n * What a `--production` build is.\n *\n * Background work — queues polled, crons scheduled, subscribers drained — is\n * included here, and `buildApp` takes it back out when the app serves a\n * RestApi: an API's image answers HTTP and nothing else, and that work belongs\n * to a Worker. The build still writes their files on every server build.\n *\n * @internal Exported for testing\n */\nexport function normalizeProductionConfig(\n\tcliProduction: boolean,\n): NormalizedProductionConfig | undefined {\n\tif (!cliProduction) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tenabled: true,\n\t\tbundle: true,\n\t\tminify: true,\n\t\thealthCheck: '/health',\n\t\tgracefulShutdown: true,\n\t\texternal: [],\n\t\tsubscribers: 'include',\n\t\topenapi: false,\n\t};\n}\n\nexport interface DevOptions {\n\tport?: number;\n\tportExplicit?: boolean;\n\tenableOpenApi?: boolean;\n\t/** Specific app to run in workspace mode (default: all apps) */\n\tapp?: string;\n\t/** Filter apps by pattern (passed to turbo --filter) */\n\tfilter?: string;\n\t/** Entry file to run (bypasses gkm config) */\n\tentry?: string;\n\t/** Watch for file changes (default: true with --entry) */\n\twatch?: boolean;\n\t/** Apply pending migrations before the apps start. */\n\tmigrate?: boolean;\n\t/** Migrate, then run the seeds, before the apps start. */\n\tseed?: boolean;\n\t/**\n\t * Call each external API's fake (`test/fakes/<id>.ts`) instead of the\n\t * provider. Without it an external API is the real one, at its URL for the\n\t * local stage, with the local stage's own credentials.\n\t */\n\tfake?: boolean;\n\t/**\n\t * `false` (`--no-subscribers`) runs no topic subscribers. Every declared\n\t * subscriber runs otherwise — fan-out is the default, opting out is this.\n\t */\n\tsubscribers?: boolean;\n}\n\n/** Read by the generated server: no subscriber is subscribed or polled. */\nexport const SUBSCRIBERS_ENV = 'GKM_SUBSCRIBERS';\n\nexport async function devCommand(options: DevOptions): Promise<void> {\n\t// Set on this process, so the server it starts — directly or through turbo\n\t// — inherits it.\n\tif (options.subscribers === false) process.env[SUBSCRIBERS_ENV] = 'off';\n\n\t// Handle --entry mode: run any file with secret injection\n\tif (options.entry) {\n\t\treturn entryDevCommand(options);\n\t}\n\n\t// Load default .env file BEFORE loading config\n\t// This ensures env vars are available when config and its dependencies are loaded\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// The app whose configured path holds this directory. Anywhere else, the\n\t// workspace runs: turbo starts each app's own `gkm dev`, in its folder.\n\tconst appConfig = await loadAppConfig().catch((error: unknown) => {\n\t\tif (error instanceof NotInAnApp || error instanceof NotABackendApp) {\n\t\t\treturn undefined;\n\t\t}\n\t\tthrow error;\n\t});\n\n\tif (!appConfig) {\n\t\t// Discovery imports every construct and route module — the longest\n\t\t// silence of a start, before anything else can be said.\n\t\tlogger.log('🔎 Reading gkm.config.ts and the constructs');\n\t\tconst { workspace: everything } = await loadWorkspaceConfig();\n\t\treturn workspaceDevCommand(everything, options);\n\t}\n\n\tconst config: GkmConfig = appConfig.gkmConfig;\n\tconst appRoot = appConfig.appRoot;\n\tconst secretsRoot = appConfig.workspaceRoot; // Where .gkm/secrets/ lives\n\tconst workspaceAppName = appConfig.appName;\n\t// The same rule the workspace start applies, for this app alone — run on\n\t// its own, it moves off another project's port too. Under the workspace\n\t// start its port was just checked free, so it stays put.\n\tconst assigned = await assignAppPorts(\n\t\tappConfig.workspace,\n\t\t[workspaceAppName],\n\t\t{\n\t\t\tfree: isPortAvailable,\n\t\t\tholder: holderOf,\n\t\t},\n\t);\n\tif (assigned.running.length > 0) {\n\t\tthrow new WorkspacePortsInUse(assigned.running);\n\t}\n\tfor (const { app, from, to, holder } of assigned.moved) {\n\t\tlogger.log(\n\t\t\t`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`,\n\t\t);\n\t}\n\tconst workspace: NormalizedWorkspace = withAppPorts(\n\t\tappConfig.workspace,\n\t\tassigned.ports,\n\t);\n\tconst workspaceAppPort =\n\t\tassigned.ports[workspaceAppName] ?? appConfig.app.port;\n\t// Tagged, so a later start can tell this app's server from another\n\t// project's on the same port. The server is spawned from this process and\n\t// inherits it, and so does anything it forks.\n\tprocess.env[APP_TAG_ENV] = appTag(appConfig.workspaceRoot, workspaceAppName);\n\n\t// An app with an entry point (a non-gkm app like better-auth) runs it.\n\tif (appConfig.app.entry) {\n\t\tlogger.log(`📄 Using entry point: ${appConfig.app.entry}`);\n\t\treturn entryDevCommand({\n\t\t\t...options,\n\t\t\tentry: appConfig.app.entry,\n\t\t\tport: workspaceAppPort,\n\t\t\tportExplicit: true,\n\t\t});\n\t}\n\n\t// Load any additional env files specified in config\n\tif (config.env) {\n\t\tconst { loaded, missing } = loadEnvFiles(config.env, appRoot);\n\t\tif (loaded.length > 0) {\n\t\t\tlogger.log(`📦 Loaded env: ${loaded.join(', ')}`);\n\t\t}\n\t\tif (missing.length > 0) {\n\t\t\tlogger.warn(`⚠️ Missing env files: ${missing.join(', ')}`);\n\t\t}\n\t}\n\n\t// Normalize telescope configuration\n\tconst telescope = normalizeTelescopeConfig(config.telescope);\n\n\t// Normalize hooks configuration\n\tconst hooks = normalizeHooksConfig(config.hooks, appRoot);\n\n\t// Resolve OpenAPI configuration\n\tconst openApiConfig = resolveOpenApiConfig(config);\n\tconst enableOpenApi = openApiConfig.enabled;\n\n\t// The build's own pipeline, for the server target: what dev runs is what\n\t// `gkm build` would have generated, never a second reading of the same\n\t// constructs.\n\t// Quietly: the build's progress — every count, every generated file — is\n\t// `gkm build`'s output, and repeated on every start and rebuild it buried\n\t// the one line dev has to say. Warnings and errors still print.\n\tconst build = (bustCache = false) =>\n\t\tquietly(() =>\n\t\t\tbuildApp({\n\t\t\t\tconfig,\n\t\t\t\t// Where a surface's `path` is measured from, so the build can tell\n\t\t\t\t// which surface this app serves.\n\t\t\t\tworkspaceRoot: workspace?.root ?? secretsRoot,\n\t\t\t\tappRoot,\n\t\t\t\ttarget: 'server',\n\t\t\t\tenableOpenApi,\n\t\t\t\tcacheBackend: cacheBackendFor(providerOf(workspace ?? config)),\n\t\t\t\t// The local stage's broker: the target's, which the dev stack runs.\n\t\t\t\teventsBackend: eventsBackendFor(providerOf(workspace ?? config)),\n\t\t\t\ttelescope,\n\t\t\t\tdatabaseApi: true,\n\t\t\t\thooks,\n\t\t\t\tskipBundle: true,\n\t\t\t\tbustCache,\n\t\t\t\tserveEmpty: true,\n\t\t\t}),\n\t\t);\n\n\t// Build initial version\n\tlogger.log(`🔨 Building ${workspaceAppName ?? 'the app'}`);\n\tconst initial = await build();\n\n\t// Determine runtime (default to node)\n\tconst runtime: Runtime = config.runtime ?? 'node';\n\n\t// Load secrets for dev mode, resolve every declared address, and write to\n\t// JSON file\n\tlet secretsJsonPath: string | undefined;\n\tlet publicUrl: string | undefined;\n\tlet manifest: ConstructManifest | undefined;\n\t// The local stage's store, which is always the file.\n\tconst appSecrets = await loadSecretsForApp(\n\t\tworkspace\n\t\t\t? await secretsStoreFor(workspace, config.stages.local)\n\t\t\t: new FileSecretsStore(secretsRoot),\n\t\tconfig.stages.local,\n\t);\n\n\tif (workspace) {\n\t\t// The same reconcile `gkm setup` and the workspace dev path run: derive\n\t\t// the containers from what the app declares, start them, create what the\n\t\t// URLs name, and inject those URLs.\n\t\tconst reconciled = await reconcileWorkspace(workspace, {\n\t\t\tstage: workspace.stages.local,\n\t\t\t...(options.fake ? { fake: true } : {}),\n\t\t\tprogress: (message) => logger.log(message),\n\t\t});\n\n\t\t// Every start, not only the one that changed something: where the inbox\n\t\t// is matters on the hundredth `gkm dev` as much as the first.\n\t\tif (reconciled.services.length > 0) {\n\t\t\tlogger.log('🐳 Services');\n\t\t\tfor (const line of describeServices(reconciled.services)) {\n\t\t\t\tlogger.log(line);\n\t\t\t}\n\t\t}\n\n\t\t// Declared URLs win over anything sniffed or stored — the manifest is the\n\t\t// statement of what exists.\n\t\tObject.assign(appSecrets, reconciled.env);\n\n\t\t// This app's own address behind the edge, for the ready line.\n\t\tconst own = reconciled.plan.resources.find(\n\t\t\t(r) =>\n\t\t\t\t(r.kind === 'rest-api' || r.kind === 'site') &&\n\t\t\t\tappKey(r.id) === workspaceAppName,\n\t\t);\n\t\tpublicUrl = own ? reconciled.env[own.envKey] : undefined;\n\t\tmanifest = reconciled.manifest;\n\t}\n\n\tif (Object.keys(appSecrets).length > 0) {\n\t\tconst secretsDir = join(secretsRoot, '.gkm');\n\t\tawait mkdir(secretsDir, { recursive: true });\n\t\tconst secretsFileName = workspaceAppName\n\t\t\t? `dev-secrets-${workspaceAppName}.json`\n\t\t\t: 'dev-secrets.json';\n\t\tsecretsJsonPath = join(secretsDir, secretsFileName);\n\t\tawait writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));\n\t}\n\n\t// Start the dev server\n\t// Priority: explicit --port option > workspace app port > default 3000\n\tconst devServer = new DevServer(\n\t\toptions.port ?? workspaceAppPort ?? 3000,\n\t\t// A workspace's port is as fixed as one passed with --port: every other\n\t\t// app's URL, CORS list and cookie domain names it. Drifting to the next\n\t\t// free port served the app where nothing points — and in a workspace the\n\t\t// next free port is usually another app's.\n\t\toptions.portExplicit ?? workspaceAppPort !== undefined,\n\t\tenableOpenApi,\n\t\ttelescope,\n\t\tinitial.databaseApi,\n\t\truntime,\n\t\tappRoot,\n\t\tsecretsJsonPath,\n\t\tinitial.selfServing !== undefined,\n\t);\n\n\tdevServer.label = workspaceAppName ?? 'server';\n\tdevServer.publicUrl = publicUrl;\n\tawait devServer.start();\n\n\t// Said to the machine's discovery endpoint, so a console can find this app\n\t// and read its data APIs without being told the port.\n\tconst discovery = await joinDiscovery({\n\t\trole: 'app',\n\t\tport: discoveryPort(workspace.dev),\n\t\tworkspace: {\n\t\t\tname: workspace.name,\n\t\t\troot: workspace.root,\n\t\t\tstage: workspace.stages.local,\n\t\t},\n\t\tallowedOrigins: workspace.dev?.allowedOrigins ?? [],\n\t\t...(manifest ? { manifest } : {}),\n\t\tapps: [\n\t\t\t{\n\t\t\t\tname: workspaceAppName,\n\t\t\t\ttype: 'backend',\n\t\t\t\tport: devServer.port,\n\t\t\t\t...(publicUrl ? { publicUrl } : {}),\n\t\t\t\tstatus: 'ready',\n\t\t\t\treloads: 0,\n\t\t\t\tdataApis: dataApisOf({\n\t\t\t\t\tselfServing: devServer.selfServing,\n\t\t\t\t\ttelescopePath: telescope?.path,\n\t\t\t\t\tdatabaseApi: initial.databaseApi,\n\t\t\t\t\topenApi: enableOpenApi,\n\t\t\t\t}),\n\t\t\t},\n\t\t],\n\t});\n\t// Under a workspace's `gkm dev`, which printed it once for every app.\n\tif (!process.env[DISCOVERY_QUIET_ENV]) announce(discovery);\n\tdevServer.onStatus = (status) =>\n\t\tdiscovery.updateApp(workspaceAppName, (app) => ({\n\t\t\t...app,\n\t\t\tstatus,\n\t\t\tport: devServer.port,\n\t\t\treloads:\n\t\t\t\tapp.status === 'reloading' && status === 'ready'\n\t\t\t\t\t? app.reloads + 1\n\t\t\t\t\t: app.reloads,\n\t\t}));\n\n\t// Watch for file changes\n\t// Get hooks file path for watching\n\tconst hooksFileParts = config.hooks?.server?.split('#');\n\tconst hooksFile = hooksFileParts?.[0];\n\n\t// One glob to watch, the same one the build loads from. The logger and the\n\t// environment parser are inside it — they are constructs now, not module\n\t// paths beside the code.\n\tconst watchPatterns = [\n\t\tconfig.constructs,\n\t\t// Add hooks file to watch list\n\t\t...(hooksFile\n\t\t\t? [hooksFile.endsWith('.ts') ? hooksFile : `${hooksFile}.ts`]\n\t\t\t: []),\n\t]\n\t\t.flat()\n\t\t.filter((p): p is string => typeof p === 'string');\n\n\t// Relative to the app, which the watcher runs from: the construct globs\n\t// arrive absolute from the config, and a relative path is what the change\n\t// line prints.\n\tconst normalizedPatterns = watchPatterns.map((p) =>\n\t\tisAbsolute(p) ? relative(appRoot, p) : p.replace(/^\\.\\//, ''),\n\t);\n\n\t// Resolve glob patterns to actual files (chokidar 4.x doesn't support globs)\n\tconst resolvedFiles = await fg(normalizedPatterns, {\n\t\tcwd: appRoot,\n\t\tabsolute: false,\n\t\tonlyFiles: true,\n\t});\n\n\t// Also watch the directories for new files\n\tconst dirsToWatch = [\n\t\t...new Set(\n\t\t\tresolvedFiles.map((f) => {\n\t\t\t\tconst parts = f.split('/');\n\t\t\t\treturn parts.slice(0, -1).join('/');\n\t\t\t}),\n\t\t),\n\t];\n\n\tconst watcher = chokidar.watch([...resolvedFiles, ...dirsToWatch], {\n\t\tignored: /(^|[/\\\\])\\../, // ignore dotfiles\n\t\tpersistent: true,\n\t\tignoreInitial: true,\n\t\tcwd: appRoot,\n\t});\n\n\twatcher.on('error', (error) => {\n\t\tlogger.error('❌ Watcher error:', error);\n\t});\n\n\tlet rebuildTimeout: NodeJS.Timeout | null = null;\n\n\twatcher.on('change', async (path) => {\n\t\tlogger.log(`🔄 ${path} changed — rebuilding`);\n\n\t\t// Debounce rebuilds\n\t\tif (rebuildTimeout) {\n\t\t\tclearTimeout(rebuildTimeout);\n\t\t}\n\n\t\trebuildTimeout = setTimeout(async () => {\n\t\t\ttry {\n\t\t\t\t// Bust the module cache: the edit is what the rebuild is for.\n\t\t\t\tconst rebuilt = await build(true);\n\n\t\t\t\tdevServer.selfServing = rebuilt.selfServing !== undefined;\n\t\t\t\tawait devServer.restart();\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`❌ Rebuild failed: ${err.message}`);\n\t\t\t\tif (err.stack) {\n\t\t\t\t\tlogger.error(err.stack);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 300);\n\t});\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\n\t\t// Use sync-style shutdown to ensure it completes before exit\n\t\tPromise.all([watcher.close(), devServer.stop(), discovery.leave()])\n\t\t\t.catch((err) => {\n\t\t\t\tlogger.error('Error during shutdown:', err);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tprocess.exit(0);\n\t\t\t});\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n}\n\n/**\n * Check for port conflicts across all apps.\n * Returns list of conflicts if any ports are duplicated.\n * @internal Exported for testing\n */\nexport function checkPortConflicts(\n\tworkspace: NormalizedWorkspace,\n): { app1: string; app2: string; port: number }[] {\n\tconst conflicts: { app1: string; app2: string; port: number }[] = [];\n\tconst portToApp = new Map<number, string>();\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tconst existingApp = portToApp.get(app.port);\n\t\tif (existingApp) {\n\t\t\tconflicts.push({ app1: existingApp, app2: appName, port: app.port });\n\t\t} else {\n\t\t\tportToApp.set(app.port, appName);\n\t\t}\n\t}\n\n\treturn conflicts;\n}\n\n/**\n * A framework the dev server starts an app with.\n *\n * Expo is a mobile framework, not a frontend one, but it is detected and\n * validated here the same way — so the union is what this table is keyed by.\n * It used to be keyed by `FrontendFramework` alone, with the Expo entry typed\n * as an excess property and the one call site casting around it.\n */\ntype ClientFramework = FrontendFramework | MobileFramework;\n\n/**\n * Per-framework validation spec for the frameworks the dev server supports.\n */\ninterface FrontendFrameworkSpec {\n\tdisplayName: string;\n\tconfigFiles: string[];\n\tdependency: string;\n\tinstallCommand: string;\n}\n\nconst FRONTEND_FRAMEWORKS: Record<ClientFramework, FrontendFrameworkSpec> = {\n\tnextjs: {\n\t\tdisplayName: 'Next.js',\n\t\tconfigFiles: [\n\t\t\t'next.config.js',\n\t\t\t'next.config.ts',\n\t\t\t'next.config.mjs',\n\t\t\t'next.config.cjs',\n\t\t],\n\t\tdependency: 'next',\n\t\tinstallCommand: 'pnpm add next react react-dom',\n\t},\n\tremix: {\n\t\tdisplayName: 'Remix',\n\t\tconfigFiles: [\n\t\t\t'remix.config.js',\n\t\t\t'remix.config.mjs',\n\t\t\t'remix.config.ts',\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@remix-run/dev',\n\t\tinstallCommand: 'pnpm add -D @remix-run/dev',\n\t},\n\tvite: {\n\t\tdisplayName: 'Vite',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: 'vite',\n\t\tinstallCommand: 'pnpm add -D vite',\n\t},\n\t'tanstack-start': {\n\t\tdisplayName: 'TanStack Start',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@tanstack/react-start',\n\t\tinstallCommand: 'pnpm add @tanstack/react-start @tanstack/react-router',\n\t},\n\texpo: {\n\t\tdisplayName: 'Expo',\n\t\tconfigFiles: ['app.config.ts', 'app.config.js', 'app.json'],\n\t\tdependency: 'expo',\n\t\tinstallCommand: 'pnpm add expo',\n\t},\n};\n\n/** Whether a configured framework is one this table knows how to start. */\nfunction isClientFramework(\n\tframework: string | undefined,\n): framework is ClientFramework {\n\treturn framework !== undefined && framework in FRONTEND_FRAMEWORKS;\n}\n\n/**\n * Auto-detect the frontend framework by scanning package.json deps and config\n * files. Dependency match wins over config file match because deps are more\n * distinctive (a Remix app has both vite.config.ts AND @remix-run/dev).\n */\nfunction detectFrontendFramework(\n\tfullPath: string,\n\tdeps: Record<string, string>,\n): ClientFramework | undefined {\n\t// tanstack-start before vite/remix so its more specific dep wins; vite last\n\t// because plain vite is the fallback when neither nextjs/remix/tanstack match.\n\t// Order matters: more specific deps win over general ones.\n\t// expo first (own dep), then tanstack-start (uses vite), remix (uses vite),\n\t// nextjs (own dep), and plain vite last as the fallback.\n\tconst order: ClientFramework[] = [\n\t\t'expo',\n\t\t'tanstack-start',\n\t\t'nextjs',\n\t\t'remix',\n\t\t'vite',\n\t];\n\tfor (const name of order) {\n\t\tif (deps[FRONTEND_FRAMEWORKS[name].dependency]) {\n\t\t\treturn name;\n\t\t}\n\t}\n\tfor (const name of order) {\n\t\tconst hasConfig = FRONTEND_FRAMEWORKS[name].configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (hasConfig) {\n\t\t\treturn name;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * Validation result for a frontend app.\n */\nexport interface FrontendValidationResult {\n\tappName: string;\n\tvalid: boolean;\n\terrors: string[];\n\twarnings: string[];\n}\n\n/**\n * Validate a frontend app configuration.\n *\n * If `framework` is provided, validates strictly against that framework's\n * expected config file and dependency. Otherwise auto-detects the framework\n * from package.json and config files. If no recognized framework is found, the\n * app is allowed through with a warning provided it has a `dev` script.\n *\n * @internal Exported for testing\n */\nexport async function validateFrontendApp(\n\tappName: string,\n\tappPath: string,\n\tworkspaceRoot: string,\n\tframework?: ClientFramework,\n): Promise<FrontendValidationResult> {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst fullPath = join(workspaceRoot, appPath);\n\n\tconst packageJsonPath = join(fullPath, 'package.json');\n\tif (!existsSync(packageJsonPath)) {\n\t\terrors.push(\n\t\t\t`package.json not found at ${appPath}. Run: pnpm init in the app directory.`,\n\t\t);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tlet pkg: {\n\t\tdependencies?: Record<string, string>;\n\t\tdevDependencies?: Record<string, string>;\n\t\tscripts?: Record<string, string>;\n\t};\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tpkg = require(packageJsonPath);\n\t} catch {\n\t\terrors.push(`Failed to read package.json at ${packageJsonPath}`);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tconst deps: Record<string, string> = {\n\t\t...pkg.dependencies,\n\t\t...pkg.devDependencies,\n\t};\n\n\tconst resolvedFramework =\n\t\tframework ?? detectFrontendFramework(fullPath, deps);\n\n\tif (resolvedFramework) {\n\t\tconst spec = FRONTEND_FRAMEWORKS[resolvedFramework];\n\t\tconst hasConfig = spec.configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (!hasConfig) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} config file not found. Expected one of: ${spec.configFiles.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!deps[spec.dependency]) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} not found in dependencies. Run: ${spec.installCommand}`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\twarnings.push(\n\t\t\t'No recognized frontend framework detected (Next.js, Vite, Remix). ' +\n\t\t\t\t'The app will run via its \"dev\" script. Set `framework` in your app config to enable strict validation.',\n\t\t);\n\t}\n\n\tif (!pkg.scripts?.dev) {\n\t\tif (resolvedFramework) {\n\t\t\twarnings.push(\n\t\t\t\t'No \"dev\" script found in package.json. Turbo expects a \"dev\" script to run.',\n\t\t\t);\n\t\t} else {\n\t\t\terrors.push(\n\t\t\t\t'No \"dev\" script found in package.json. Without a recognized framework or a dev script, there is nothing to run.',\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tappName,\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n/**\n * Validate all frontend apps in the workspace.\n * Returns validation results for each frontend app.\n * @internal Exported for testing\n */\nexport async function validateFrontendApps(\n\tworkspace: NormalizedWorkspace,\n): Promise<FrontendValidationResult[]> {\n\tconst results: FrontendValidationResult[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'web') {\n\t\t\tconst result = await validateFrontendApp(\n\t\t\t\tappName,\n\t\t\t\tapp.path,\n\t\t\t\tworkspace.root,\n\t\t\t\tisClientFramework(app.framework) ? app.framework : undefined,\n\t\t\t);\n\t\t\tresults.push(result);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Load secrets for development stage.\n * Returns env vars to inject, or empty object if secrets not configured/found.\n * @internal Exported for testing\n */\nexport async function loadDevSecrets(\n\tworkspace: NormalizedWorkspace,\n): Promise<Record<string, string>> {\n\t// Check if secrets are enabled in workspace config\n\tif (!workspace.secrets.enabled) {\n\t\treturn {};\n\t}\n\n\tconst stage = workspace.stages.local;\n\tconst secrets = await (await secretsStoreFor(workspace, stage)).read(stage);\n\tif (secrets) return toEmbeddableSecrets(secrets);\n\n\t// Nothing to warn about: the local stage's own secrets and every address are\n\t// derived by reconcile. A stored stage only adds what nothing can derive — a\n\t// third party's key — and a construct missing one says so when it is read.\n\treturn {};\n}\n\n/**\n * Workspace dev command - orchestrates multi-app development using Turbo.\n *\n * Flow:\n * 1. Check for port conflicts\n * 2. Start docker-compose services (db, cache, mail)\n * 3. Generate dependency URLs ({APP_NAME}_URL)\n * 4. Spawn turbo run dev with injected env vars\n */\nasync function workspaceDevCommand(\n\tconfigured: NormalizedWorkspace,\n\toptions: DevOptions,\n): Promise<void> {\n\t// Each app's local port, before anything reads one: the edge routes, every\n\t// address an app is handed, and the ready lines all follow it. An app whose\n\t// port another project holds moves; one this workspace already has running\n\t// is refused, since moving would start a second copy beside it.\n\tconst scoped = options.app\n\t\t? [options.app]\n\t\t: options.filter\n\t\t\t? []\n\t\t\t: Object.keys(configured.apps);\n\tconst assigned = await assignAppPorts(configured, scoped, {\n\t\tfree: isPortAvailable,\n\t\tholder: holderOf,\n\t});\n\tif (assigned.running.length > 0) {\n\t\tthrow new WorkspacePortsInUse(assigned.running);\n\t}\n\tfor (const { app, from, to, holder } of assigned.moved) {\n\t\tlogger.log(\n\t\t\t`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`,\n\t\t);\n\t}\n\tconst workspace = withAppPorts(configured, assigned.ports);\n\tconst appCount = Object.keys(workspace.apps).length;\n\tconst frontendApps = Object.entries(workspace.apps).filter(\n\t\t([_, app]) => app.type === 'web',\n\t);\n\n\t// Check for port conflicts\n\tconst conflicts = checkPortConflicts(workspace);\n\tif (conflicts.length > 0) {\n\t\tfor (const conflict of conflicts) {\n\t\t\tlogger.error(\n\t\t\t\t`❌ Port conflict: Apps \"${conflict.app1}\" and \"${conflict.app2}\" both use port ${conflict.port}`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(\n\t\t\t'Port conflicts detected. Please assign unique ports to each app.',\n\t\t);\n\t}\n\n\t// Validate frontend apps (Next.js setup)\n\tif (frontendApps.length > 0) {\n\t\tconst validationResults = await validateFrontendApps(workspace);\n\n\t\tlet hasErrors = false;\n\t\tfor (const result of validationResults) {\n\t\t\tif (!result.valid) {\n\t\t\t\thasErrors = true;\n\t\t\t\tlogger.error(\n\t\t\t\t\t`\\n❌ Frontend app \"${result.appName}\" validation failed:`,\n\t\t\t\t);\n\t\t\t\tfor (const error of result.errors) {\n\t\t\t\t\tlogger.error(` • ${error}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const warning of result.warnings) {\n\t\t\t\tlogger.warn(` ⚠️ ${result.appName}: ${warning}`);\n\t\t\t}\n\t\t}\n\n\t\tif (hasErrors) {\n\t\t\tthrow new Error(\n\t\t\t\t'Frontend app validation failed. Fix the issues above and try again.',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Frontend apps import each API's client from the workspace root's\n\t// `.gkm/client/` through their tsconfig alias\n\t// (`import { createApi } from '@myapp/client/api'`) — nothing is copied.\n\n\tconst rawSecrets = await loadDevSecrets(workspace);\n\n\t// Derive the containers from what the apps declare, start them, create what\n\t// the URLs name, and inject those URLs. Safe to do on every start because\n\t// the blast radius is this project's containers and `.gkm/`, and because the\n\t// converged case costs one hash and one health check.\n\tconst reconciled = await reconcileWorkspace(workspace, {\n\t\tstage: workspace.stages.local,\n\t\t...(options.fake ? { fake: true } : {}),\n\t\tprogress: (message) => logger.log(message),\n\t});\n\n\t// Every start, not only the one that changed something: where the inbox is\n\t// matters on the hundredth `gkm dev` as much as the first.\n\tif (reconciled.services.length > 0) {\n\t\tlogger.log('🐳 Services');\n\t\tfor (const line of describeServices(reconciled.services)) {\n\t\t\tlogger.log(line);\n\t\t}\n\t}\n\n\tconst secretsEnv: Record<string, string> = {\n\t\t...rawSecrets,\n\t\t...reconciled.env,\n\t};\n\n\t// Only with `--fake`, and here rather than in reconcile: every app's own\n\t// `gkm dev` reconciles too, and only this process — the one that outlives\n\t// them — may own the ports.\n\tconst fakes = options.fake\n\t\t? await serveFakes(reconciled.fakes, reconciled.ports)\n\t\t: [];\n\tfor (const { id, port } of fakes) {\n\t\tlogger.log(`🎭 ${id} fake: http://localhost:${port}`);\n\t}\n\n\t// Asked for, the databases are migrated (and seeded) before anything\n\t// starts, and a failure stops here. Otherwise pending migrations are only\n\t// reported, and a failure to check is only a warning: nothing about it\n\t// should keep the apps from starting.\n\tlogger.log(\n\t\toptions.migrate || options.seed\n\t\t\t? '🗄️ Migrating the databases'\n\t\t\t: '🗄️ Checking for pending migrations',\n\t);\n\tif (options.migrate || options.seed) {\n\t\tconst { prepareDevDatabases } = await import('../migrate/index.js');\n\t\tawait prepareDevDatabases(workspace, reconciled.env, {\n\t\t\tseed: !!options.seed,\n\t\t});\n\t} else {\n\t\tawait import('../migrate/index.js')\n\t\t\t.then(({ reportPendingMigrations }) =>\n\t\t\t\treportPendingMigrations(workspace, reconciled.env),\n\t\t\t)\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t});\n\t}\n\n\t// Where each app answers, behind the edge — the addresses the apps were just\n\t// given, rather than their ports.\n\tconst appUrls: Record<string, string> = {};\n\tfor (const resource of reconciled.plan.resources) {\n\t\tif (resource.kind !== 'rest-api' && resource.kind !== 'site') continue;\n\t\tconst address = reconciled.env[resource.envKey];\n\t\tif (address) appUrls[resource.id] = address;\n\t}\n\n\t// A browser trusts the edge's HTTPS addresses only once its authority is in\n\t// the system store. Asked here, once, rather than left for the first page\n\t// load to say \"your connection is not private\".\n\tconst firstUrl = Object.values(appUrls).find((url) =>\n\t\turl.startsWith('https://'),\n\t);\n\tif (firstUrl) await ensureTrusted(workspace.root, firstUrl);\n\n\t// Build turbo filter\n\tlet turboFilter: string[] = [];\n\tif (options.app) {\n\t\t// Run specific app\n\t\tif (!workspace.apps[options.app]) {\n\t\t\tconst appNames = Object.keys(workspace.apps).join(', ');\n\t\t\tthrow new Error(\n\t\t\t\t`App \"${options.app}\" not found. Available apps: ${appNames}`,\n\t\t\t);\n\t\t}\n\t\tturboFilter = [\n\t\t\t'--filter',\n\t\t\tappPackageName(workspace, options.app) ?? options.app,\n\t\t];\n\t} else if (options.filter) {\n\t\t// Use custom filter\n\t\tturboFilter = ['--filter', options.filter];\n\t} else {\n\t\t// Every app, by name. Left to infer its own scope at the workspace root,\n\t\t// turbo includes the root package — whose `dev` script is `gkm dev`,\n\t\t// which arrives here and starts turbo again, and every app twice over.\n\t\t// `gkm build` names its apps for the same reason.\n\t\tconst { filters, unpackaged } = turboFilters(workspace);\n\t\tturboFilter = filters.flatMap((name) => ['--filter', name]);\n\t\tif (unpackaged.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t`⚠️ No package.json with a name for: ${unpackaged.join(', ')} — turbo cannot run ${unpackaged.length === 1 ? 'it' : 'them'}.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Each app once: the address it is reached at, and the local port the edge\n\t// forwards it to.\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tconst width = Math.max(...buildOrder.map((name) => name.length));\n\tlogger.log(`\\n${workspace.name}: ${appCount} app(s)`);\n\tfor (const appName of buildOrder) {\n\t\tconst app = workspace.apps[appName];\n\t\tif (!app) continue;\n\t\t// A mobile app answers on its scheme, and a phone reaches this machine\n\t\t// at its LAN address — which is what to check when sign-in fails there.\n\t\tif (app.type === 'mobile') {\n\t\t\tconst own = reconciled.plan.resources.find(\n\t\t\t\t(r) => r.kind === 'mobile-app' && appKey(r.id) === appName,\n\t\t\t);\n\t\t\tconst scheme = own ? reconciled.env[own.envKey] : undefined;\n\t\t\tconst device = Object.entries(reconciled.env).find(([key]) =>\n\t\t\t\tkey.endsWith('_DEVICE_URL'),\n\t\t\t)?.[1];\n\t\t\tlogger.log(\n\t\t\t\t` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : 'mobile'}${device ? ` — devices reach ${new URL(device).hostname}` : ''}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst local = `http://localhost:${app.port}`;\n\t\tconst url = Object.entries(appUrls).find(\n\t\t\t([id]) => appKey(id) === appName,\n\t\t)?.[1];\n\t\tlogger.log(\n\t\t\t` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`,\n\t\t);\n\t}\n\tlogger.log('');\n\n\t// Find the config file path for GKM_CONFIG_PATH\n\tconst configFiles = ['gkm.config.ts', 'gkm.config.js', 'gkm.config.json'];\n\tlet configPath = '';\n\tfor (const file of configFiles) {\n\t\tconst fullPath = join(workspace.root, file);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconfigPath = fullPath;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Every app turbo starts, as this workspace lists them. Each backend app's\n\t// own `gkm dev` registers too, with its status and its data APIs.\n\tconst discovery = await joinDiscovery({\n\t\trole: 'workspace',\n\t\tport: discoveryPort(workspace.dev),\n\t\tworkspace: {\n\t\t\tname: workspace.name,\n\t\t\troot: workspace.root,\n\t\t\tstage: workspace.stages.local,\n\t\t},\n\t\tallowedOrigins: workspace.dev?.allowedOrigins ?? [],\n\t\t...(reconciled.manifest ? { manifest: reconciled.manifest } : {}),\n\t\tapps: buildOrder.flatMap((name) => {\n\t\t\tconst app = workspace.apps[name];\n\t\t\tif (!app) return [];\n\t\t\tconst publicUrl = Object.entries(appUrls).find(\n\t\t\t\t([id]) => appKey(id) === name,\n\t\t\t)?.[1];\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tport: app.port,\n\t\t\t\t\t...(publicUrl ? { publicUrl } : {}),\n\t\t\t\t\tstatus: 'starting' as const,\n\t\t\t\t\treloads: 0,\n\t\t\t\t\tdataApis: [],\n\t\t\t\t},\n\t\t\t];\n\t\t}),\n\t});\n\tannounce(discovery);\n\n\t// Prepare environment variables\n\t// Order matters: secrets first, then dependencies (dependencies can override)\n\tconst turboEnv: Record<string, string> = {\n\t\t...process.env,\n\t\t...secretsEnv,\n\t\tNODE_ENV: 'development',\n\t\t// Inject config path so child processes can find the workspace config\n\t\t...(configPath ? { GKM_CONFIG_PATH: configPath } : {}),\n\t\t// Each app reconciles again, and must point at the same fakes.\n\t\t...(options.fake ? { [FAKE_ENV]: '1' } : {}),\n\t\t// The connect URL was printed above; the apps need not repeat it.\n\t\t[DISCOVERY_QUIET_ENV]: '1',\n\t};\n\n\t// Spawn turbo run dev\n\tlogger.log(\n\t\t`🚀 Starting ${appCount} app(s) — each builds before it answers, and says so when it is ready`,\n\t);\n\n\tconst turboProcess = spawn('pnpm', ['turbo', 'run', 'dev', ...turboFilter], {\n\t\tcwd: workspace.root,\n\t\tstdio: 'inherit',\n\t\tenv: turboEnv,\n\t\tdetached: true,\n\t});\n\n\t// No file watcher needed — frontend apps import API clients directly\n\t// from backend packages via workspace dependencies.\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down workspace...');\n\t\tcloseFakes(fakes);\n\t\tvoid discovery.leave();\n\n\t\t// Kill turbo process group\n\t\tconst pid = turboProcess.pid;\n\t\tif (pid) {\n\t\t\ttry {\n\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\t// Process already dead\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Force kill after timeout if processes are still alive\n\t\tsetTimeout(() => {\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tprocess.exit(0);\n\t\t}, 3000);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Wait for turbo to exit\n\treturn new Promise((resolve, reject) => {\n\t\tturboProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Turbo error:', error);\n\t\t\treject(error);\n\t\t});\n\n\t\tturboProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0) {\n\t\t\t\treject(new Error(`Turbo exited with code ${code}`));\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Run any TypeScript file with secret injection.\n * Does not require gkm.config.ts.\n */\nasync function entryDevCommand(options: DevOptions): Promise<void> {\n\tconst { entry, watch = true } = options;\n\n\tif (!entry) {\n\t\tthrow new Error('--entry requires a file path');\n\t}\n\n\tconst entryPath = resolve(process.cwd(), entry);\n\n\tif (!existsSync(entryPath)) {\n\t\tthrow new Error(`Entry file not found: ${entryPath}`);\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials (loads workspace config, secrets, injects PORT)\n\t// Only pass explicitPort if --port was actually specified by the user\n\tconst { credentials, resolvedPort, secretsJsonPath, appName } =\n\t\tawait prepareEntryCredentials({\n\t\t\texplicitPort: options.portExplicit ? options.port : undefined,\n\t\t});\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName} (port ${resolvedPort})`);\n\t}\n\n\tlogger.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);\n\n\tif (Object.keys(credentials).length > 1) {\n\t\tlogger.log(\n\t\t\t`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`,\n\t\t);\n\t}\n\n\t// Create wrapper entry that injects secrets before importing user's file\n\tconst wrapperDir = join(process.cwd(), '.gkm');\n\tawait mkdir(wrapperDir, { recursive: true });\n\tconst wrapperPath = join(wrapperDir, 'entry-wrapper.ts');\n\tawait createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);\n\n\t// Start with tsx\n\tconst runner = new EntryRunner(wrapperPath, entryPath, watch, resolvedPort);\n\tawait runner.start();\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\t\trunner.stop();\n\t\tprocess.exit(0);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Keep the process alive\n\tawait new Promise(() => {});\n}\n\n/**\n * Runs and watches a TypeScript entry file using tsx.\n */\nclass EntryRunner {\n\tprivate childProcess: ChildProcess | null = null;\n\tprivate watcher: ReturnType<typeof chokidar.watch> | null = null;\n\tprivate isRunning = false;\n\n\tconstructor(\n\t\tprivate wrapperPath: string,\n\t\tprivate entryPath: string,\n\t\tprivate watch: boolean,\n\t\tprivate port: number,\n\t) {}\n\n\tasync start(): Promise<void> {\n\t\tawait this.runProcess();\n\n\t\tif (this.watch) {\n\t\t\t// Watch the entry file's directory for changes\n\t\t\tconst watchDir = dirname(this.entryPath);\n\n\t\t\tthis.watcher = chokidar.watch(watchDir, {\n\t\t\t\tignored: /(^|[/\\\\])\\../,\n\t\t\t\tpersistent: true,\n\t\t\t\tignoreInitial: true,\n\t\t\t});\n\n\t\t\tlet restartTimeout: NodeJS.Timeout | null = null;\n\n\t\t\tthis.watcher.on('change', (path) => {\n\t\t\t\tlogger.log(`📝 File changed: ${path}`);\n\n\t\t\t\t// Debounce restarts\n\t\t\t\tif (restartTimeout) {\n\t\t\t\t\tclearTimeout(restartTimeout);\n\t\t\t\t}\n\n\t\t\t\trestartTimeout = setTimeout(async () => {\n\t\t\t\t\tlogger.log('🔄 Restarting...');\n\t\t\t\t\tawait this.restart();\n\t\t\t\t}, 300);\n\t\t\t});\n\n\t\t\tlogger.log(`👀 Watching for changes in: ${watchDir}`);\n\t\t}\n\t}\n\n\tprivate async runProcess(): Promise<void> {\n\t\t// Pass PORT as environment variable\n\t\tconst env = {\n\t\t\t...process.env,\n\t\t\tPORT: String(this.port),\n\t\t\tNODE_OPTIONS: withOwningTsconfigJsx(process.env.NODE_OPTIONS),\n\t\t};\n\n\t\tthis.childProcess = spawn(\n\t\t\t...tsxCommand(dirname(this.wrapperPath), [this.wrapperPath]),\n\t\t\t{\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv,\n\t\t\t\tdetached: true,\n\t\t\t},\n\t\t);\n\n\t\tthis.isRunning = true;\n\n\t\tthis.childProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Process error:', error);\n\t\t});\n\n\t\tthis.childProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0 && code !== 143) {\n\t\t\t\t// 143 = SIGTERM\n\t\t\t\tlogger.error(`❌ Process exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t});\n\n\t\t// Give the process a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t\tif (this.isRunning) {\n\t\t\tlogger.log('');\n\t\t\tlogger.log(\n\t\t\t\t` \\x1b[32m✓ Ready\\x1b[0m at \\x1b[36mhttp://localhost:${this.port}\\x1b[0m`,\n\t\t\t);\n\t\t\tlogger.log('');\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tthis.stopProcess();\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\tawait this.runProcess();\n\t}\n\n\tstop(): void {\n\t\tthis.watcher?.close();\n\t\tthis.stopProcess();\n\t}\n\n\tprivate stopProcess(): void {\n\t\tif (this.childProcess && this.isRunning) {\n\t\t\tconst pid = this.childProcess.pid;\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.childProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\t}\n}\n\n/**\n * Generate the content of the dev server entry file (server.ts).\n * Uses dynamic import for createApp so Credentials are populated\n * before any app modules evaluate.\n * @internal Exported for testing\n */\nexport function generateServerEntryContent(options: {\n\tsecretsJsonPath?: string;\n\truntime?: Runtime;\n\tenableOpenApi?: boolean;\n\tappImportPath?: string;\n\t/**\n\t * `app.ts` is a surface serving itself — it exports the construct's own\n\t * `app`, with no `createApp` around it to start.\n\t */\n\tselfServing?: boolean;\n}): string {\n\tconst {\n\t\tsecretsJsonPath,\n\t\truntime = 'node',\n\t\tenableOpenApi = false,\n\t\tappImportPath = './app.js',\n\t\tselfServing = false,\n\t} = options;\n\n\t// Exit with the `gkm dev` that started this server. Dev stops it on a\n\t// signal, but a dev process killed outright — SIGKILL, a closed terminal, a\n\t// crashed parent — never gets to, and the server kept its port: the next\n\t// `gkm dev` found it taken and started somewhere nothing points at.\n\tconst parentWatch = `// Exit when the gkm dev that started this server is gone.\nconst __gkmDevPid = Number(process.env.GKM_DEV_PID);\nif (__gkmDevPid) {\n setInterval(() => {\n try {\n process.kill(__gkmDevPid, 0);\n } catch {\n process.exit(0);\n }\n }, 1000).unref();\n}\n\n`;\n\n\tconst credentialsInjection = secretsJsonPath\n\t\t? `import { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets via globalThis (must happen before app import)\nconst secretsPath = '${secretsJsonPath}';\nif (existsSync(secretsPath)) {\n const __secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));\n globalThis.__gkm_credentials__ = __secrets;\n Object.assign(process.env, __secrets);\n}\n\n`\n\t\t: '';\n\n\tconst serveCode =\n\t\truntime === 'bun'\n\t\t\t? `Bun.serve({\n port,\n fetch: app.fetch,\n });`\n\t\t\t: `const { serve } = await import('@hono/node-server');\n const server = serve({\n fetch: app.fetch,\n port,\n });\n // Inject WebSocket support if available\n const injectWs = (app as any).__injectWebSocket;\n if (injectWs) {\n injectWs(server);\n console.log('🔌 Telescope real-time updates enabled');\n }`;\n\n\tif (selfServing) {\n\t\treturn `#!/usr/bin/env node\n/**\n * Development server entry point for a surface that serves itself\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// Dynamic import so Credentials are populated before the surface evaluates\nconst { app } = await import('${appImportPath}');\n\n${serveCode.replace(/^ {4}/gm, '')}\n`;\n\t}\n\n\treturn `#!/usr/bin/env node\n/**\n * Development server entry point\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// Dynamic import so Credentials are populated before env.ts evaluates\nconst { createApp } = await import('${appImportPath}');\n\n// createApp is async to support optional WebSocket setup\nconst { app, start } = await createApp(undefined, ${enableOpenApi});\n\n// Start the server\nstart({\n port,\n serve: async (app, port) => {\n ${serveCode}\n },\n}).catch((error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n});\n`;\n}\n\n/**\n * The discovery endpoint's connect URL, Jupyter-style: the token in it is what\n * lets a console read what this machine is running.\n */\nfunction announce(discovery: DiscoverySession): void {\n\tlogger.log(`🧭 Discovery: ${discovery.connectUrl}`);\n}\n\n/** Run `fn` with `console.log` muted — warnings and errors still print. */\nasync function quietly<T>(fn: () => Promise<T>): Promise<T> {\n\tconst log = console.log;\n\tconsole.log = () => {};\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\tconsole.log = log;\n\t}\n}\n\n/**\n * How to run a TypeScript entry with the app's own tsx.\n *\n * Straight through node rather than `npx tsx`: npx reads the developer's npm\n * config on every start and warned about each key it did not recognise — nine\n * lines per app, per restart, about nothing gkm does.\n */\nfunction tsxCommand(appRoot: string, args: string[]): [string, string[]] {\n\ttry {\n\t\tconst cli = createRequire(join(appRoot, 'package.json')).resolve('tsx/cli');\n\t\treturn [process.execPath, [cli, ...args]];\n\t} catch {\n\t\treturn ['npx', ['tsx', ...args]];\n\t}\n}\n\n/** A port this app must serve on is held by something else. */\nexport class DevPortInUse extends Error {\n\tconstructor(\n\t\treadonly port: number,\n\t\t/** What holds it, when `lsof` could say — `node (pid 123)`. */\n\t\treadonly holder: string | undefined,\n\t) {\n\t\tsuper(\n\t\t\t`Port ${port} is already in use${holder ? ` by ${holder}` : ''}. ` +\n\t\t\t\t'It is the port this app is provisioned on — the one every other ' +\n\t\t\t\t'app and its CORS origins point at — so dev will not move off it. ' +\n\t\t\t\t'Stop what is holding it (often a dev server a previous run left ' +\n\t\t\t\t'behind), or pass -p/--port to run this app somewhere else.',\n\t\t);\n\t\tthis.name = 'DevPortInUse';\n\t}\n}\n\n/** Apps whose provisioned ports are held before the workspace starts. */\n/**\n * This workspace's own apps are already running — left by a previous start.\n *\n * Only these are refused: a port another project holds is moved off instead\n * (see `assignAppPorts`), but moving off our own would start a second copy.\n */\nexport class WorkspacePortsInUse extends Error {\n\tconstructor(readonly held: readonly AppRunning[]) {\n\t\tsuper(\n\t\t\t`This workspace's apps are already running:\\n${held\n\t\t\t\t.map(\n\t\t\t\t\t({ app, port, holder }) =>\n\t\t\t\t\t\t` ${app}: ${port} — ${describeHolder(holder)}`,\n\t\t\t\t)\n\t\t\t\t.join('\\n')}\\n` +\n\t\t\t\t'A previous `gkm dev` left them behind. Stop them (kill the pids above) ' +\n\t\t\t\t'and start again. Nothing was started.',\n\t\t);\n\t\tthis.name = 'WorkspacePortsInUse';\n\t}\n}\n\n/** What is listening on a port, as `command (pid N)`, if `lsof` can tell. */\nfunction listenerOn(port: number): string | undefined {\n\ttry {\n\t\tconst out = execSync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -Fpc`, {\n\t\t\tencoding: 'utf8',\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t});\n\t\tconst pid = out.match(/^p(\\d+)/m)?.[1];\n\t\tconst command = out.match(/^c(.+)$/m)?.[1];\n\t\treturn pid ? `${command ?? 'a process'} (pid ${pid})` : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nclass DevServer {\n\tprivate serverProcess: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate actualPort: number;\n\tprivate startTime = Date.now();\n\n\tconstructor(\n\t\tprivate requestedPort: number,\n\t\tprivate portExplicit: boolean,\n\t\tprivate enableOpenApi: boolean,\n\t\tprivate telescope: NormalizedTelescopeConfig | undefined,\n\t\t/** Where the database's JSON API is served, when one is declared. */\n\t\tprivate databaseApi: string | undefined,\n\t\tprivate runtime: Runtime = 'node',\n\t\tprivate appRoot: string = process.cwd(),\n\t\tprivate secretsJsonPath?: string,\n\t\t/** Whether `app.ts` is a surface serving itself rather than `createApp`. */\n\t\tpublic selfServing = false,\n\t) {\n\t\tthis.actualPort = requestedPort;\n\t}\n\n\t/** What the ready line calls this app. */\n\tlabel = 'server';\n\n\t/** Told when the server is ready, reloading, or exits on its own. */\n\tonStatus: ((status: AppStatus) => void) | undefined;\n\n\t/** The port it is serving on. */\n\tget port(): number {\n\t\treturn this.actualPort;\n\t}\n\n\t/**\n\t * Where the app is reached — its HTTPS address behind the edge, when it has\n\t * one. The local port is only what the edge forwards to.\n\t */\n\tpublicUrl: string | undefined;\n\n\tasync start(): Promise<void> {\n\t\tthis.startTime = Date.now();\n\t\tif (this.isRunning) {\n\t\t\tawait this.stop();\n\t\t}\n\n\t\t// Check port availability\n\t\tif (this.portExplicit) {\n\t\t\t// Port was explicitly specified - throw if unavailable\n\t\t\tconst available = await isPortAvailable(this.requestedPort);\n\t\t\tif (!available) {\n\t\t\t\tthrow new DevPortInUse(\n\t\t\t\t\tthis.requestedPort,\n\t\t\t\t\tlistenerOn(this.requestedPort),\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.actualPort = this.requestedPort;\n\t\t} else {\n\t\t\t// Find an available port starting from the default\n\t\t\tthis.actualPort = await findAvailablePort(this.requestedPort);\n\n\t\t\tif (this.actualPort !== this.requestedPort) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst serverEntryPath = join(this.appRoot, '.gkm', 'server', 'server.ts');\n\n\t\t// Create server entry file\n\t\tawait this.createServerEntry();\n\n\t\t// Start the server using tsx (TypeScript execution)\n\t\t// Use detached: true so we can kill the entire process tree\n\t\tthis.serverProcess = spawn(\n\t\t\t...tsxCommand(this.appRoot, [\n\t\t\t\tserverEntryPath,\n\t\t\t\t'--port',\n\t\t\t\tthis.actualPort.toString(),\n\t\t\t]),\n\t\t\t{\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t\tNODE_ENV: 'development',\n\t\t\t\t\t// So the server can exit with this process — see the entry.\n\t\t\t\t\tGKM_DEV_PID: String(process.pid),\n\t\t\t\t\t// The app runs from its own directory, and tsx compiles only\n\t\t\t\t\t// what that tsconfig includes with its options — so a\n\t\t\t\t\t// construct's `.tsx` in the workspace would lose its JSX\n\t\t\t\t\t// settings. See `bin/owning-tsconfig-jsx.mjs`.\n\t\t\t\t\tNODE_OPTIONS: withOwningTsconfigJsx(process.env.NODE_OPTIONS),\n\t\t\t\t},\n\t\t\t\tdetached: true,\n\t\t\t},\n\t\t);\n\n\t\tthis.isRunning = true;\n\n\t\tthis.serverProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Server error:', error);\n\t\t});\n\n\t\tconst child = this.serverProcess;\n\t\tchild.on('exit', (code, signal) => {\n\t\t\tif (code !== null && code !== 0 && signal !== 'SIGTERM') {\n\t\t\t\tlogger.error(`❌ Server exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t\t// Still the current server, so nothing here stopped it: it exited on\n\t\t\t// its own. `stop()` lets go of the one it kills before it dies.\n\t\t\tif (this.serverProcess === child) this.onStatus?.('stopped');\n\t\t});\n\n\t\t// Give the server a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\n\t\tif (this.isRunning) {\n\t\t\tconst local = `http://localhost:${this.actualPort}`;\n\t\t\tconst address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;\n\t\t\tconst seconds = ((Date.now() - this.startTime) / 1000).toFixed(1);\n\t\t\tlogger.log(\n\t\t\t\t`\\x1b[32m✓\\x1b[0m ${this.label} ready in ${seconds}s ${address}`,\n\t\t\t);\n\n\t\t\t// What the generated app mounts. An app that serves itself — an auth\n\t\t\t// server — mounts none of it.\n\t\t\tconst tools = this.selfServing\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\t...(this.enableOpenApi ? ['docs /__docs'] : []),\n\t\t\t\t\t\t...(this.telescope ? [`telescope ${this.telescope.path}`] : []),\n\t\t\t\t\t\t...(this.databaseApi ? [`db ${this.databaseApi}`] : []),\n\t\t\t\t\t];\n\t\t\tif (tools.length > 0) logger.log(` ${tools.join(' · ')}`);\n\t\t\tthis.onStatus?.('ready');\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst port = this.actualPort;\n\n\t\tif (this.serverProcess && this.isRunning) {\n\t\t\tconst pid = this.serverProcess.pid;\n\n\t\t\t// Use SIGKILL directly since the server ignores SIGTERM\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process might already be dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.serverProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\n\t\t// Also kill any processes still holding the port\n\t\tthis.killProcessesOnPort(port);\n\t}\n\n\tprivate killProcessesOnPort(port: number): void {\n\t\ttry {\n\t\t\t// Whatever is *listening* on the port — the server this replaces.\n\t\t\t// Without `-sTCP:LISTEN`, lsof also lists every client connected to\n\t\t\t// it, so a restart killed the browser, the web app's server, or the\n\t\t\t// test runner that happened to hold a keep-alive socket.\n\t\t\texecSync(\n\t\t\t\t`lsof -ti tcp:${port} -sTCP:LISTEN | xargs kill -9 2>/dev/null || true`,\n\t\t\t\t{ stdio: 'ignore' },\n\t\t\t);\n\t\t} catch {\n\t\t\t// Ignore errors - port may already be free\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tconst portToReuse = this.actualPort;\n\t\tthis.onStatus?.('reloading');\n\t\tawait this.stop();\n\n\t\t// Wait for port to be released (up to 3 seconds)\n\t\tlet attempts = 0;\n\t\twhile (attempts < 30) {\n\t\t\tif (await isPortAvailable(portToReuse)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\t\t\tattempts++;\n\t\t}\n\n\t\t// Force reuse the same port\n\t\tthis.requestedPort = portToReuse;\n\t\tawait this.start();\n\t}\n\n\tprivate async createServerEntry(): Promise<void> {\n\t\tconst { writeFile: fsWriteFile } = await import('node:fs/promises');\n\n\t\tconst serverPath = join(this.appRoot, '.gkm', 'server', 'server.ts');\n\n\t\tconst content = generateServerEntryContent({\n\t\t\tsecretsJsonPath: this.secretsJsonPath,\n\t\t\truntime: this.runtime,\n\t\t\tenableOpenApi: this.enableOpenApi,\n\t\t\tselfServing: this.selfServing,\n\t\t});\n\n\t\tawait fsWriteFile(serverPath, content);\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Function } from '@geekmidas/constructs/functions';\nimport type { BuildContext } from '../build/types';\nimport type { FunctionInfo } from '../types';\nimport { runtimeFor } from './EndpointGenerator.js';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\nexport class FunctionGenerator extends ConstructGenerator<\n\tFunction<any, any, any, any, any, any, any, any, any, any>,\n\tFunctionInfo[]\n> {\n\tisConstruct(\n\t\tvalue: any,\n\t): value is Function<any, any, any, any, any, any, any, any, any, any> {\n\t\treturn Function.isFunction(value);\n\t}\n\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<\n\t\t\tFunction<any, any, any, any, any, any, any, any, any, any>\n\t\t>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<FunctionInfo[]> {\n\t\tconst target = options?.target ?? 'aws';\n\t\tconst logger = console;\n\t\tconst functionInfos: FunctionInfo[] = [];\n\n\t\tif (constructs.length === 0 || target === 'server') {\n\t\t\treturn functionInfos;\n\t\t}\n\n\t\t// Create functions subdirectory\n\t\tconst functionsDir = join(outputDir, 'functions');\n\t\tawait mkdir(functionsDir, { recursive: true });\n\n\t\t// Generate function handlers\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateFunctionHandler(\n\t\t\t\tfunctionsDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tcontext,\n\t\t\t\tconstruct.owner,\n\t\t\t);\n\n\t\t\tfunctionInfos.push({\n\t\t\t\tname: key,\n\t\t\t\thandler: relative(options?.root ?? process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t\tdependencies: construct.constructs,\n\t\t\t});\n\n\t\t\tlogger.log(`Generated function handler: ${key}`);\n\t\t}\n\n\t\treturn functionInfos;\n\t}\n\n\tprivate async generateFunctionHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\tcontext: BuildContext,\n\t\t/** The construct that owns this — its worker, or its surface. */\n\t\towner: string | undefined,\n\t): Promise<string> {\n\t\tconst handlerFileName = `${exportName}.ts`;\n\t\tconst handlerPath = join(outputDir, handlerFileName);\n\n\t\tconst relativePath = relative(dirname(handlerPath), sourceFile);\n\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\t// Imports the construct that owns this, and binds `envParser` and\n\t\t// `logger` off it — the objects it was declared with, rather than a\n\t\t// module path printed in from config.\n\t\tconst runtime = runtimeFor(context, dirname(handlerPath), owner);\n\n\t\tconst content = `import { AWSLambdaFunction } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\n${runtime.imports}\n${context.storageDrivers?.imports ?? ''}\n${runtime.bindings}\n${context.storageDrivers?.setup ? `\\n// The handler registers the drivers its target needs.\\n${context.storageDrivers.setup}\\n` : ''}\nconst adapter = new AWSLambdaFunction(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n}\n","import { Topic } from '@geekmidas/constructs/topic';\nimport type { BuildContext } from '../build/types';\nimport type { TopicInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\n/**\n * Discovers topics (`new Topic(…)`) into `manifest.topics`. A topic is a\n * *resource*, not a function — it has no handler to generate. Producers name it\n * with `.event(topic, …)` or `.dependsOn([topic])`, and subscribers bind with\n * `worker.topic(topic)`; this generator\n * only records the topic + its event contract so infra can provision the SNS\n * topic. Identical output for every provider (locally pg-boss routes by event\n * name, so there's nothing to run).\n */\nexport class TopicGenerator extends ConstructGenerator<\n\tTopic<any, any>,\n\tTopicInfo[]\n> {\n\tisConstruct(value: any): value is Topic<any, any> {\n\t\treturn Topic.isTopic(value);\n\t}\n\n\tasync build(\n\t\t_context: BuildContext,\n\t\tconstructs: GeneratedConstruct<Topic<any, any>>[],\n\t\t_outputDir: string,\n\t\t_options?: GeneratorOptions,\n\t): Promise<TopicInfo[]> {\n\t\tconst logger = console;\n\t\tconst topicInfos = constructs.map(({ construct }) => ({\n\t\t\tname: construct.name,\n\t\t\tevents: construct.eventTypes,\n\t\t}));\n\n\t\tfor (const topic of topicInfos) {\n\t\t\tlogger.log(`Discovered topic: ${topic.name}`);\n\t\t}\n\n\t\treturn topicInfos;\n\t}\n}\n","import type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\n\nimport type { CronInfo, FunctionInfo, RouteInfo } from '../types';\n\nexport interface ProcessedEndpoint {\n\tfile: string;\n\texportName: string;\n\tendpoint: Endpoint<any, any, any, any, any, any>;\n\trouteInfo: RouteInfo;\n}\n\nexport interface ProcessedFunction {\n\tfile: string;\n\texportName: string;\n\tfn: Function<any, any, any, any, any>;\n}\n\nexport interface ProcessedCron {\n\tfile: string;\n\texportName: string;\n\tcron: Cron<any, any, any, any>;\n\tschedule?: string;\n}\n\nexport interface NormalizedTelescopeConfig {\n\tenabled: boolean;\n\t/** Path to user's telescope module (if provided) */\n\ttelescopePath?: string;\n\t/** Import pattern for telescope (e.g., '{ telescope }' or 'telescope') */\n\ttelescopeImportPattern?: string;\n\t/** UI path for telescope dashboard */\n\tpath: string;\n\tignore: string[];\n\trecordBody: boolean;\n\tmaxEntries: number;\n\twebsocket: boolean;\n}\n\n/**\n * Where `gkm dev` serves the database's read-only JSON API\n * (`@geekmidas/db/introspect`). Under `/__gkm` with the rest of what the dev\n * server adds, so it cannot collide with an application route.\n */\nexport const DEV_DATABASE_API_PATH = '/__gkm/db';\n\n/**\n * The database the dev server's JSON API reads, and where it is declared.\n *\n * The API needs a client, and a client comes from a construct — so the entry\n * imports the declaration discovery already found and resolves it there. One\n * declared database is one browsable database; a project with none gets no\n * API, which is the correct answer rather than a stub.\n */\nexport interface DevDatabaseApi {\n\tpath: string;\n\tdatabase: { specifier: string; exportName: string };\n}\n\nexport interface NormalizedHooksConfig {\n\t/** Path to server hooks module */\n\tserverHooksPath: string;\n}\n\nexport interface NormalizedProductionConfig {\n\tenabled: boolean;\n\tbundle: boolean;\n\tminify: boolean;\n\thealthCheck: string;\n\tgracefulShutdown: boolean;\n\texternal: string[];\n\tsubscribers: 'include' | 'exclude';\n\topenapi: boolean;\n}\n\nexport interface BuildContext {\n\t/**\n\t * The surface this server serves, if the app declared one.\n\t *\n\t * Carried so the generated entry can set up CORS from the graph instead of a\n\t * hand-written hook: the origins arrive as `<ID>_TRUSTED_ORIGINS`, resolved\n\t * from whatever declared an edge to this surface.\n\t */\n\tsurface?: {\n\t\tid: string;\n\t\ttrustedOriginsKey: string;\n\t\t/**\n\t\t * Where the surface is declared, so the entry can import it.\n\t\t *\n\t\t * The logger a surface was given is an *object*, and a generator can\n\t\t * print a specifier but not an object — which is why the logger used to\n\t\t * be named in config as a module path. Discovery already knows the path,\n\t\t * so the entry imports the surface and reads the logger off it, and\n\t\t * nothing is written down twice.\n\t\t */\n\t\tmodule?: { specifier: string; exportName: string };\n\t\tcors?: {\n\t\t\tmaxAge?: number;\n\t\t\tcredentials?: boolean;\n\t\t\tallowHeaders?: readonly string[];\n\t\t\texposeHeaders?: readonly string[];\n\t\t};\n\t};\n\n\ttelescope?: NormalizedTelescopeConfig;\n\t/** The dev server's database JSON API. Never set for `gkm build`. */\n\tdatabaseApi?: DevDatabaseApi;\n\thooks?: NormalizedHooksConfig;\n\t/** Production build configuration */\n\tproduction?: NormalizedProductionConfig;\n\t/**\n\t * When true, optional env vars get a `?` suffix in each construct's\n\t * environment array (e.g. `PORT?` instead of `PORT`).\n\t */\n\tmarkOptional?: boolean;\n\t/**\n\t * Storage drivers the generated entry points should register.\n\t *\n\t * The scheme in an injected URL picks the driver, so registering is the entry\n\t * point's job — see `generators/drivers.ts`.\n\t */\n\tstorageDrivers?: import('../generators/drivers.js').RuntimeDrivers;\n\t/**\n\t * The constructs glob, so the build can emit the manifest once the routes it\n\t * folds in are known.\n\t */\n\tconstructGlobs?: string | readonly string[];\n\t/**\n\t * The backends this build registered drivers for.\n\t *\n\t * Recorded in the emitted manifest so a deploy reads the same answer rather\n\t * than choosing its own — see `reconcile/emit.ts`.\n\t */\n\tcacheBackend?: import('../types.js').CacheBackend;\n\t/**\n\t * The events brokers this build registered drivers for — empty when the app\n\t * declares no topic or queue. What a generated file decides from when it\n\t * has broker-specific code to include, such as SNS push subscriptions.\n\t */\n\teventsBackends?: readonly import('../types.js').EventsBackend[];\n\temailBackend?: import('../types.js').EmailBackend;\n\t/**\n\t * Every construct that can own a runnable, by id — the surfaces and the\n\t * workers — mapped to the module that exports it.\n\t *\n\t * What lets a generated cron import the worker that runs it rather than a\n\t * logger path from config.\n\t */\n\towners?: Record<string, { specifier: string; exportName: string }>;\n\t/**\n\t * What the production entry starts OpenTelemetry with, when\n\t * `OTEL_EXPORTER_OTLP_ENDPOINT` asks for it — see `generators/telemetry.ts`.\n\t */\n\ttelemetry?: import('../generators/telemetry.js').TelemetryContext;\n}\n\nexport interface ProviderBuildResult {\n\troutes: RouteInfo[];\n\tfunctions: FunctionInfo[];\n\tcrons: CronInfo[];\n}\n","import { resolve } from 'node:path';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { ConstructSource } from '../reconcile/discover.js';\nimport { type BuildContext, DEV_DATABASE_API_PATH } from './types';\n\n/**\n * What a generated entry imports its runtime from, read off the discovered\n * constructs: the surface it serves, every construct a runnable can be built\n * from, and the database the dev server's JSON API reads.\n *\n * `gkm build` and `gkm dev` both write entries that import the surface for its\n * logger and environment parser, so both ask here. A dev server that skipped it\n * had nothing to import them from.\n */\nexport function ownersContext(options: {\n\tdeclared: ConstructManifest;\n\tsources: Record<string, ConstructSource>;\n\tworkspaceRoot: string;\n\t/** The directory being built — the app a surface's `path` names. */\n\tappRoot: string;\n\t/** Whether to serve the database's JSON API — `gkm dev` only. */\n\tdatabaseApi?: boolean;\n}): Pick<BuildContext, 'owners' | 'surface' | 'databaseApi'> {\n\tconst { declared, sources, workspaceRoot, appRoot, databaseApi } = options;\n\n\t// Which surface this server answers on, so the entry can derive its CORS.\n\t//\n\t// The app's own API, not the auth server it may also mount: an auth surface\n\t// declares its own endpoints, and the origins that may call *it* are a\n\t// different list from the ones that may call the API.\n\tconst surfaces = restApis(declared);\n\tconst served = servedSurface(declared, workspaceRoot, appRoot);\n\tconst primary =\n\t\tserved ?? surfaces.find((d) => d.endpoints.length === 0) ?? surfaces[0];\n\n\t// Which database the JSON API reads: the one the app declared. A reader is\n\t// not a candidate — it is the same data through a role that cannot write,\n\t// so browsing it would be the same rows under a second name.\n\tconst browsable = Object.entries(declared).find(\n\t\t([, d]) => d.kind === 'database',\n\t);\n\tconst browsableSource = browsable ? sources[browsable[0]] : undefined;\n\n\t// Every construct something can be built from, by id. A generated cron\n\t// imports the worker that owns it; a generated handler imports its surface.\n\tconst owners: Record<string, { specifier: string; exportName: string }> = {};\n\tfor (const [id, declaration] of Object.entries(declared)) {\n\t\tif (declaration.kind !== 'rest-api' && declaration.kind !== 'worker')\n\t\t\tcontinue;\n\t\tconst source = sources[id];\n\t\tif (!source) continue;\n\t\towners[id] = { specifier: source.file, exportName: source.exportName };\n\t}\n\n\tconst primarySource = primary ? sources[primary.id] : undefined;\n\n\treturn {\n\t\towners,\n\t\t...(primary\n\t\t\t? {\n\t\t\t\t\tsurface: {\n\t\t\t\t\t\tid: primary.id,\n\t\t\t\t\t\ttrustedOriginsKey: provideKey(primary.id, 'trustedOrigins'),\n\t\t\t\t\t\t...(primary.cors ? { cors: primary.cors } : {}),\n\t\t\t\t\t\t...(primarySource\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\t\t\t\tspecifier: primarySource.file,\n\t\t\t\t\t\t\t\t\t\texportName: primarySource.exportName,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t\t...(databaseApi && browsableSource\n\t\t\t? {\n\t\t\t\t\tdatabaseApi: {\n\t\t\t\t\t\tpath: DEV_DATABASE_API_PATH,\n\t\t\t\t\t\tdatabase: {\n\t\t\t\t\t\t\tspecifier: browsableSource.file,\n\t\t\t\t\t\t\texportName: browsableSource.exportName,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/**\n * The endpoints one surface serves.\n *\n * One glob finds every surface's endpoints, wherever their files live. A build\n * keeps the ones built from the surface it serves; one built from no surface at\n * all has nowhere else to go.\n */\nexport function servedBy<T extends { construct: { surface?: { id: string } } }>(\n\tendpoints: T[],\n\tsurface: BuildContext['surface'],\n): T[] {\n\tif (!surface) return endpoints;\n\n\treturn endpoints.filter(\n\t\t({ construct }) =>\n\t\t\t!construct.surface || construct.surface.id === surface.id,\n\t);\n}\n\ntype RestApiDeclaration = Extract<\n\tConstructManifest[string],\n\t{ kind: 'rest-api' }\n>;\n\nfunction restApis(declared: ConstructManifest): RestApiDeclaration[] {\n\treturn Object.values(declared).filter(\n\t\t(d): d is RestApiDeclaration => d.kind === 'rest-api',\n\t);\n}\n\n/**\n * The surface whose declared `path` is the directory being built — asked of\n * every surface, because a workspace has several and each app's build serves\n * exactly one.\n */\nexport function servedSurface(\n\tdeclared: ConstructManifest,\n\tworkspaceRoot: string,\n\tappRoot: string,\n): RestApiDeclaration | undefined {\n\treturn restApis(declared).find(\n\t\t(d) => resolve(workspaceRoot, d.path) === resolve(appRoot),\n\t);\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport type { ConstructSource } from '../reconcile/discover.js';\nimport { servedSurface } from './owners';\n\n/** A construct that builds its own server — `BetterAuth` and its routes. */\ninterface ServesItself {\n\tserver(options: unknown): Promise<{ app: unknown }>;\n}\n\n/** Whether a construct serves itself, asked of the construct. */\nexport function servesItself(construct: unknown): construct is ServesItself {\n\treturn (\n\t\ttypeof (construct as { server?: unknown } | null)?.server === 'function'\n\t);\n}\n\n/**\n * The surface this app serves, when that surface serves itself.\n *\n * An auth server's routes are a wildcard the construct mounts, so a glob finds\n * nothing and the entry only has to start it. That used to be inferred —\n * \"nothing found, and the surface declares routes\" — which is a guess about\n * the construct from the outside. The construct can simply be asked.\n */\nexport function selfServingSurface(options: {\n\tdeclared: ConstructManifest;\n\tsources: Record<string, ConstructSource>;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}): { id: string; source: ConstructSource } | undefined {\n\tconst { declared, sources, workspaceRoot, appRoot } = options;\n\n\tconst served = servedSurface(declared, workspaceRoot, appRoot);\n\tconst source = served ? sources[served.id] : undefined;\n\n\tif (!served || !source || !servesItself(source.construct)) return undefined;\n\n\treturn { id: served.id, source };\n}\n\n/**\n * The entry for a surface that serves itself.\n *\n * Two lines, because the construct owns the serving. A generator writing the\n * mounts would be a second description of routes the declaration already\n * carries — which is how Better Auth came to be mounted by a hand-written hook,\n * and then served by nothing at all when that hook was deleted for duplicating\n * CORS the graph had started deriving.\n *\n * The import specifier comes from discovery, which globbed the file and\n * imported it. Nothing about the surface is named here.\n */\nexport async function writeSurfaceEntry(\n\toutputDir: string,\n\tsource: ConstructSource,\n): Promise<void> {\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst rel = relative(outputDir, source.file).replace(/\\.ts$/, '.js');\n\tconst specifier = rel.startsWith('.') ? rel : `./${rel}`;\n\n\tawait writeFile(\n\t\tjoin(outputDir, 'app.ts'),\n\t\t`/**\n * Generated entry for a surface that serves itself.\n *\n * Its routes, its CORS origins and its clients all come from the construct's\n * own declaration. This file exists only to start it.\n */\nimport { snifferContext } from '@geekmidas/constructs';\nimport { defaultEnvParser } from '@geekmidas/constructs/endpoints';\nimport { ${source.exportName} as surface } from '${specifier}';\n\nconst envParser = defaultEnvParser();\n\nexport const { app } = await surface.server({ envParser, context: snifferContext });\n\nexport default app;\n`,\n\t);\n}\n\n/**\n * The production server for a surface that serves itself.\n *\n * `app.ts` exports the construct's own Hono app and starts nothing, which is\n * what `gkm dev` wants: its server mounts the app beside its tools. An image\n * needs a process, so a production build starts one here — the health check\n * every image is probed on, the surface behind it, and the same bounded drain\n * on SIGTERM the generated route servers have. Without it an auth server had\n * no bundle to put in an image at all.\n */\nexport async function writeSurfaceServer(\n\toutputDir: string,\n\toptions: { healthCheck: string; gracefulShutdown: boolean },\n): Promise<string> {\n\tawait mkdir(outputDir, { recursive: true });\n\n\tconst shutdown = options.gracefulShutdown\n\t\t? `\n// Stop taking requests, let in-flight ones finish, then close what the\n// construct opened — bounded by GKM_SHUTDOWN_TIMEOUT_MS, under Docker's 10s\n// stop timeout, so the process exits on its own terms.\nlet shuttingDown = false;\nconst shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n const deadline = Number(process.env.GKM_SHUTDOWN_TIMEOUT_MS) || 8000;\n setTimeout(() => process.exit(1), deadline).unref();\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await runShutdownHooks((error) => console.error(error));\n process.exit(0);\n};\n\nprocess.on('SIGTERM', shutdown);\nprocess.on('SIGINT', shutdown);\n`\n\t\t: '';\n\n\tconst path = join(outputDir, 'server.ts');\n\tawait writeFile(\n\t\tpath,\n\t\t`#!/usr/bin/env node\n/**\n * Production server for a surface that serves itself.\n * Generated by 'gkm build --production'.\n */\nimport { serve } from '@hono/node-server';\nimport { Hono } from 'hono';\n${options.gracefulShutdown ? \"import { runShutdownHooks } from '@geekmidas/constructs';\\n\" : ''}import { app as surface } from './app.js';\n\nconst port = Number(process.env.PORT) || 3000;\n\nconst app = new Hono();\n// First, so a probe is answered without reaching the surface's own routes.\napp.get(${JSON.stringify(options.healthCheck)}, (c) =>\n c.json({ status: 'ok', timestamp: Date.now() }),\n);\napp.route('/', surface);\n\nconst server = serve({ fetch: app.fetch, port });\nconsole.log(JSON.stringify({ msg: 'Production server started', port }));\n${shutdown}`,\n\t);\n\n\treturn path;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { chmod, mkdir, rm, writeFile } from 'node:fs/promises';\nimport { join, relative, resolve } from 'node:path';\nimport type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\nimport type { Queue } from '@geekmidas/constructs/queue';\nimport type { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { Topic } from '@geekmidas/constructs/topic';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { loadAppConfig, loadConfig, loadWorkspaceConfig } from '../config';\nimport {\n\tnormalizeHooksConfig,\n\tnormalizeProductionConfig,\n\tnormalizeTelescopeConfig,\n} from '../dev';\nimport {\n\tCronGenerator,\n\tcacheBackendsIn,\n\tdriversFor,\n\tEndpointGenerator,\n\teventsBackendsIn,\n\tFunctionGenerator,\n\ttype GeneratedConstruct,\n\tQueueGenerator,\n\tSubscriberGenerator,\n\tTopicGenerator,\n\tWorkerGenerator,\n\tworkerBundleName,\n\tworkerEntryDir,\n} from '../generators';\nimport { telemetryFor } from '../generators/telemetry';\nimport { generateOpenApi } from '../openapi.js';\nimport { type ConstructSource, discover } from '../reconcile/discover.js';\nimport {\n\ttype Backends,\n\tmanifestModule,\n\twithCompute,\n\twithRoutes,\n} from '../reconcile/emit.js';\nimport { CommandFailed, DEFAULT_TIMEOUT_MS } from '../run';\nimport { LocalSandbox } from '../sandbox/local';\nimport { keyFingerprint } from '../secrets/encryption';\nimport type {\n\tBuildOptions,\n\tBuildResult,\n\tCacheBackend,\n\tCronInfo,\n\tEventsBackend,\n\tFunctionInfo,\n\tGkmConfig,\n\tMainProvider,\n\tQueueInfo,\n\tRouteInfo,\n\tRoutes,\n\tSubscriberInfo,\n} from '../types';\nimport { DEFAULT_EMAIL } from '../types.js';\nimport {\n\tcacheBackendFor,\n\teventsBackendFor,\n\tproviderOf,\n} from '../workspace/backends.js';\nimport {\n\tallConstructGlobs,\n\tgetAppBuildOrder,\n\tgetAppGkmConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport { ownersContext, servedBy } from './owners';\nimport {\n\tselfServingSurface,\n\twriteSurfaceEntry,\n\twriteSurfaceServer,\n} from './surfaceEntry';\nimport type {\n\tBuildContext,\n\tNormalizedHooksConfig,\n\tNormalizedProductionConfig,\n\tNormalizedTelescopeConfig,\n} from './types';\nimport { type WorkerUnit, workerUnits } from './workers';\n\nconst logger = console;\n\n/**\n * Where `gkm build --stage` leaves the key its bundle's secrets were encrypted\n * with, beside the bundle in `.gkm/server/` and readable by its owner alone.\n */\nexport const MASTER_KEY_FILE = 'master.key';\n\n/**\n * What a build run at the workspace root reads.\n *\n * One backend app there, and it is that app's config, so its own `openapi`\n * and `telescope` settings still apply. Otherwise it is the workspace's: every\n * construct glob, and the backends they resolve to.\n */\nfunction rootGkmConfig(workspace: NormalizedWorkspace): GkmConfig {\n\tconst backends = Object.entries(workspace.apps).filter(\n\t\t([, app]) => app.type === 'backend',\n\t);\n\tconst only = backends.length === 1 ? backends[0] : undefined;\n\tconst own = only ? getAppGkmConfig(workspace, only[0]) : undefined;\n\n\treturn (\n\t\town ?? {\n\t\t\tstages: workspace.stages,\n\t\t\t...(workspace.deploy ? { deploy: workspace.deploy } : {}),\n\t\t\tconstructs: allConstructGlobs(workspace),\n\t\t}\n\t);\n}\n\n/** Directories under `.gkm/` that the removed per-provider builds wrote. */\nconst SUPERSEDED_OUTPUT = [\n\t'aws-apigatewayv1',\n\t'aws-apigatewayv2',\n\t'aws-lambda',\n];\n\n/** Whether `--provider` named something a build can target. */\nexport function isMainProvider(value: string): value is MainProvider {\n\treturn value === 'aws' || value === 'server';\n}\n\nexport class UnknownBuildProvider extends Error {\n\tconstructor(readonly provider: string) {\n\t\tsuper(\n\t\t\t`'${provider}' is not a build target. Pass --provider aws or --provider server, or leave it out to build for where gkm.config.ts deploys.`,\n\t\t);\n\t\tthis.name = 'UnknownBuildProvider';\n\t}\n}\n\n/** `--cache` named something that is not a cache backend. */\nexport class UnknownCacheBackend extends Error {\n\tconstructor(readonly backend: string) {\n\t\tsuper(\n\t\t\t`'${backend}' is not a cache backend. Pass --cache upstash, elasticache, db or redis, or leave it out to register the deploy target's.`,\n\t\t);\n\t\tthis.name = 'UnknownCacheBackend';\n\t}\n}\n\nexport async function buildCommand(\n\toptions: BuildOptions,\n): Promise<BuildResult> {\n\t// Load config with workspace detection\n\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t// Route to workspace build mode for multi-app workspaces\n\t// BUT only if we're at the workspace root (prevents recursive builds when\n\t// Turbo runs gkm build in each app subdirectory)\n\tif (loadedConfig.type === 'workspace') {\n\t\tconst cwd = resolve(process.cwd());\n\t\tconst workspaceRoot = resolve(loadedConfig.workspace.root);\n\t\tconst isAtWorkspaceRoot = cwd === workspaceRoot;\n\n\t\t// Turbo only when there is a subdirectory for it to descend into. With\n\t\t// every app at the root — or no apps at all — routing through it\n\t\t// re-enters this same directory: turbo runs the root package's `build`,\n\t\t// which is `gkm build`, which arrives here again.\n\t\tconst someAppIsElsewhere = Object.values(loadedConfig.workspace.apps).some(\n\t\t\t(app) => resolve(workspaceRoot, app.path) !== workspaceRoot,\n\t\t);\n\n\t\tif (isAtWorkspaceRoot && someAppIsElsewhere) {\n\t\t\tlogger.log('📦 Detected workspace configuration');\n\t\t\treturn workspaceBuildCommand(loadedConfig.workspace, options);\n\t\t}\n\t}\n\n\t// At the root there is no app to pick: the build reads every construct the\n\t// globs find and writes one manifest and a spec per surface. Asking\n\t// package.json which app this is was a question only a subdirectory has.\n\tconst config =\n\t\tloadedConfig.type !== 'workspace'\n\t\t\t? await loadConfig()\n\t\t\t: resolve(process.cwd()) === resolve(loadedConfig.workspace.root)\n\t\t\t\t? rootGkmConfig(loadedConfig.workspace)\n\t\t\t\t: (await loadAppConfig()).gkmConfig;\n\n\t// Where it deploys decides what it builds: one Lambda per construct for\n\t// AWS, one process for a server. `--provider` overrides it for a Dockerfile,\n\t// which builds a server whatever the project deploys to.\n\tconst target = options.provider ?? providerOf(loadedConfig.workspace);\n\tconst workspaceRoot = loadedConfig.workspace.root;\n\tconst appRoot = process.cwd();\n\n\tconst output = await buildOneApp({\n\t\tconfig,\n\t\toptions,\n\t\tworkspace: loadedConfig.workspace,\n\t\tappRoot,\n\t\ttarget,\n\t});\n\n\t// Inside an app, its handlers are all there is to write: the manifest is\n\t// the application's, and only the root has all of it.\n\tif (resolve(appRoot) === resolve(workspaceRoot)) {\n\t\tawait writeManifest({\n\t\t\tworkspaceRoot,\n\t\t\ttarget,\n\t\t\tbuilds: output.built ? [output.built] : [],\n\t\t\tconstructs: await declaredIn(config, workspaceRoot),\n\t\t\tbackends: backendsOf(loadedConfig.workspace),\n\t\t});\n\t}\n\n\treturn output;\n}\n\n/** What the workspace declares, read through a config's globs. */\nasync function declaredIn(\n\tconfig: GkmConfig,\n\tcwd: string,\n): Promise<ConstructManifest> {\n\treturn discover({ patterns: config.constructs, cwd });\n}\n\n/**\n * The backend choices the manifest records — answered by the deploy target,\n * the same place reconcile and the build's drivers read them.\n */\nfunction backendsOf(workspace: { deploy?: { default?: string } }): {\n\tcache: CacheBackend;\n\temail: typeof DEFAULT_EMAIL;\n} {\n\treturn {\n\t\tcache: cacheBackendFor(providerOf(workspace)),\n\t\temail: DEFAULT_EMAIL,\n\t};\n}\n\n/** One app's build, from its config and the command's options. */\nasync function buildOneApp(input: {\n\tconfig: GkmConfig;\n\toptions: BuildOptions;\n\tworkspace: NormalizedWorkspace;\n\tappRoot: string;\n\ttarget: MainProvider;\n}): Promise<AppBuildOutput> {\n\tconst { config, options, workspace, appRoot, target } = input;\n\n\t// One answer for which backends this app uses, read once — from the\n\t// deploy target, which is the same place reconcile reads it. The build\n\t// registers drivers for it and records it in the manifest, so a deploy\n\t// cannot pick differently and hand the running code a URL it has no driver\n\t// for.\n\t//\n\t// `--cache` is the one exception: the stack `gkm compose` runs has its own\n\t// Redis whatever the target, and its Dockerfiles say so.\n\tconst cacheBackend = options.cache ?? cacheBackendFor(providerOf(workspace));\n\tconst eventsBackend = eventsBackendFor(providerOf(workspace));\n\n\tconst production = normalizeProductionConfig(options.production ?? false);\n\tif (production) {\n\t\tlogger.log(`🏭 Building for PRODUCTION`);\n\t}\n\n\tlogger.log(`Building for ${target}`);\n\tlogger.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);\n\n\t// Normalize telescope configuration (disabled in production)\n\tconst telescope = production\n\t\t? undefined\n\t\t: normalizeTelescopeConfig(config.telescope);\n\tif (telescope) {\n\t\tlogger.log(`🔭 Telescope enabled at ${telescope.path}`);\n\t}\n\n\tconst hooks = normalizeHooksConfig(config.hooks, appRoot);\n\tif (hooks) {\n\t\tlogger.log(`🪝 Server hooks enabled`);\n\t}\n\n\treturn buildApp({\n\t\tconfig,\n\t\tworkspaceRoot: workspace.root,\n\t\tappRoot,\n\t\ttarget,\n\t\tenableOpenApi: options.enableOpenApi ?? false,\n\t\tcacheBackend,\n\t\teventsBackend,\n\t\tproduction,\n\t\ttelescope,\n\t\thooks,\n\t\tmarkOptional: options.markOptional ?? false,\n\t\tskipBundle: options.skipBundle ?? false,\n\t\tstage: options.stage,\n\t\tworkspaceName: workspace.name,\n\t\tworkspace,\n\t});\n}\n\n/** What one app's build needs, once its config has been read. */\nexport interface BuildAppInput {\n\tconfig: GkmConfig;\n\tworkspaceRoot: string;\n\t/** The app being built — the directory a surface's `path` names. */\n\tappRoot: string;\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget: MainProvider;\n\tenableOpenApi: boolean;\n\tcacheBackend: CacheBackend;\n\t/**\n\t * The broker the target puts topics and queues on. Its driver is registered\n\t * only when the app declares one — see `eventsBackendsIn`.\n\t */\n\teventsBackend: EventsBackend;\n\tproduction?: NormalizedProductionConfig;\n\ttelescope?: NormalizedTelescopeConfig;\n\t/**\n\t * Serve the declared database's read-only JSON API at `/__gkm/db`. Only\n\t * `gkm dev` asks: it hands every row to whoever can reach the port.\n\t */\n\tdatabaseApi?: boolean;\n\thooks?: NormalizedHooksConfig;\n\tmarkOptional?: boolean;\n\tskipBundle?: boolean;\n\tstage?: string;\n\t/** Re-import changed modules — `gkm dev` rebuilding after an edit. */\n\tbustCache?: boolean;\n\t/** The workspace's name — telemetry's `service.namespace`. */\n\tworkspaceName?: string;\n\t/**\n\t * The workspace the app is in. A production server build reads it to know\n\t * which workers this app carries the entries of — see `workerUnits`.\n\t */\n\tworkspace?: NormalizedWorkspace;\n\t/**\n\t * Generate a server even when the globs find nothing.\n\t *\n\t * A build with nothing in it has nothing to deploy. A dev server with\n\t * nothing in it is how a project starts: it runs, and the first endpoint\n\t * written appears on the next rebuild.\n\t */\n\tserveEmpty?: boolean;\n}\n\nexport interface AppBuildOutput extends BuildResult {\n\t/**\n\t * The surface the entry starts, when the app's surface serves itself — its\n\t * `app.ts` exports the construct's own `app`, with no `createApp` to call.\n\t */\n\tselfServing?: string;\n\t/** Where the generated server serves the database's JSON API, if it does. */\n\tdatabaseApi?: string;\n\t/** What it generated, for the application's manifest. */\n\tbuilt?: AppBuild;\n}\n\n/** One app's generated handlers, as the application's manifest records them. */\nexport interface AppBuild {\n\t/** The surface its endpoints are served on. */\n\tsurface?: string;\n\troutes: RouteInfo[];\n\tfunctions: FunctionInfo[];\n\tcrons: CronInfo[];\n\tsubscribers: SubscriberInfo[];\n\tqueues: QueueInfo[];\n}\n\n/**\n * Write the application's manifest: every declared construct, with what each\n * app generated folded into it.\n *\n * The manifest belongs to the whole application, so only the root writes it —\n * once, after every app has built, from the constructs the workspace declares.\n * An app's own build generates its handlers and nothing else.\n */\nexport async function writeManifest(input: {\n\tworkspaceRoot: string;\n\ttarget: MainProvider;\n\tbuilds: readonly AppBuild[];\n\tconstructs: ConstructManifest;\n\tbackends: Backends;\n}): Promise<void> {\n\tconst { workspaceRoot, target, builds, constructs, backends } = input;\n\tconst manifestDir = join(workspaceRoot, '.gkm', 'manifest');\n\tawait mkdir(manifestDir, { recursive: true });\n\n\t// One manifest, for the target this build is for. The other target's,\n\t// left by an earlier build, would describe an application that is not\n\t// being deployed.\n\tconst other = target === 'aws' ? 'server' : 'aws';\n\tawait rm(join(manifestDir, `${other}.ts`), { force: true });\n\n\t// Each app's routes go to the surface it serves; then the compute every\n\t// app generated, which nests in the queue or topic that triggers it.\n\tconst withServed = builds.reduce(\n\t\t(manifest, build) =>\n\t\t\twithRoutes(\n\t\t\t\tmanifest,\n\t\t\t\tbuild.routes.filter((route) => route.method !== 'ALL'),\n\t\t\t\t{\n\t\t\t\t\tperRoute: true,\n\t\t\t\t\t...(build.surface ? { surface: build.surface } : {}),\n\t\t\t\t},\n\t\t\t),\n\t\tconstructs,\n\t);\n\tconst folded = withCompute(withServed, {\n\t\tfunctions: builds.flatMap((build) => build.functions),\n\t\tcrons: builds.flatMap((build) => build.crons),\n\t\tqueues: builds.flatMap((build) => build.queues),\n\t\tsubscribers: builds.flatMap((build) => build.subscribers),\n\t});\n\n\tconst path = join(manifestDir, `${target}.ts`);\n\tawait writeFile(path, manifestModule(folded, backends));\n\tlogger.log(`Manifest: ${relative(process.cwd(), path)}`);\n}\n\n/**\n * Turn one app's constructs into its generated entry.\n *\n * `gkm build` and `gkm dev` both run this. They used to be two copies of it,\n * and every time the build learned something about constructs — that the\n * entry takes its logger from the surface, that an auth server serves itself —\n * dev did not, and failed on exactly the apps the build had learned to handle.\n */\nexport async function buildApp(input: BuildAppInput): Promise<AppBuildOutput> {\n\tconst {\n\t\tconfig,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t\ttarget,\n\t\tenableOpenApi,\n\t\tcacheBackend,\n\t\teventsBackend,\n\t\tproduction,\n\t\ttelescope,\n\t\tdatabaseApi,\n\t\thooks,\n\t\tbustCache = false,\n\t} = input;\n\n\tconst constructGlobs = config.constructs;\n\n\t// Discovery imports application code, so it runs once here and everything\n\t// downstream reads what it wrote — a deploy config calling it would evaluate\n\t// the whole runtime graph inside its own toolchain. It runs before the build\n\t// context rather than after the generators because the entry point's drivers\n\t// are decided from it.\n\tconst constructSources: Record<string, ConstructSource> = {};\n\tconst background: Record<string, string[]> = {};\n\tconst declared = constructGlobs\n\t\t? await discover({\n\t\t\t\tpatterns: constructGlobs,\n\t\t\t\tcwd: appRoot,\n\t\t\t\tbustCache,\n\t\t\t\tsources: constructSources,\n\t\t\t\tbackground,\n\t\t\t})\n\t\t: {};\n\n\t// A surface that serves itself is started, not generated for: its routes\n\t// are the construct's, and the entry only has to call it.\n\tconst selfServing = selfServingSurface({\n\t\tdeclared,\n\t\tsources: constructSources,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t});\n\n\tif (selfServing) {\n\t\tawait writeSurfaceEntry(\n\t\t\tjoin(appRoot, '.gkm', 'server'),\n\t\t\tselfServing.source,\n\t\t);\n\t\tlogger.log(\n\t\t\t`Generated a server for ${selfServing.id} from its own declaration`,\n\t\t);\n\n\t\t// An image needs a process that listens, which the dev entry is not.\n\t\tif (production?.bundle && !input.skipBundle) {\n\t\t\tconst outputDir = join(appRoot, '.gkm', 'server');\n\t\t\tconst entryPoint = await writeSurfaceServer(outputDir, production);\n\t\t\tconst { bundleServer } = await import('./bundler');\n\t\t\tawait bundleServer({\n\t\t\t\tentryPoint,\n\t\t\t\toutputDir: join(outputDir, 'dist'),\n\t\t\t\tminify: production.minify,\n\t\t\t\tsourcemap: false,\n\t\t\t\texternal: production.external,\n\t\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t\t});\n\t\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);\n\t\t}\n\n\t\treturn { selfServing: selfServing.id };\n\t}\n\n\tconst derived = ownersContext({\n\t\tdeclared,\n\t\tsources: constructSources,\n\t\tworkspaceRoot,\n\t\tappRoot,\n\t\tdatabaseApi,\n\t});\n\n\t// The broker, only when something declares a topic or a queue: a project\n\t// with no events registers nothing and never resolves `@geekmidas/events`.\n\tconst eventsBackends = eventsBackendsIn(declared, eventsBackend);\n\n\tconst buildContext: BuildContext = {\n\t\t...derived,\n\t\ttelescope,\n\t\thooks,\n\t\tproduction,\n\t\tconstructGlobs,\n\t\tcacheBackend,\n\t\t// Mail is SMTP everywhere; the provider is whatever the stage's URL\n\t\t// names, so there is no choice to read here.\n\t\temailBackend: DEFAULT_EMAIL,\n\t\t// Both halves of \"where does the cache live\": the declaration for one\n\t\t// that named its database, and the deploy target's default for one that\n\t\t// named nowhere. Reading only the default registers a driver for a\n\t\t// protocol the target never composes.\n\t\tstorageDrivers: driversFor({\n\t\t\tappRoot,\n\t\t\tcache: cacheBackendsIn(declared, cacheBackend),\n\t\t\tevents: eventsBackends,\n\t\t}),\n\t\teventsBackends,\n\t\tmarkOptional: input.markOptional ?? false,\n\t\t...(production && {\n\t\t\ttelemetry: telemetryFor({\n\t\t\t\tappRoot,\n\t\t\t\tsurfaceId: derived.surface?.id,\n\t\t\t\tworkspaceName: input.workspaceName,\n\t\t\t}),\n\t\t}),\n\t};\n\n\t// Initialize generators\n\tconst endpointGenerator = new EndpointGenerator();\n\tconst functionGenerator = new FunctionGenerator();\n\tconst cronGenerator = new CronGenerator();\n\tconst subscriberGenerator = new SubscriberGenerator();\n\tconst queueGenerator = new QueueGenerator();\n\tconst topicGenerator = new TopicGenerator();\n\n\t// One glob, every kind.\n\t//\n\t// Six globs was six things to keep in step, and a handler in the wrong\n\t// directory simply never loaded. It was never necessary: each generator\n\t// already filters what it loads by a type predicate — `Endpoint.isEndpoint`,\n\t// `Cron.isCron` — so which *kind* a module exports comes from the value, and\n\t// the glob only ever had to say where to look. It says it once.\n\tconst code = constructGlobs;\n\n\tconst [\n\t\tloadedEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t] = await Promise.all([\n\t\tendpointGenerator.load(code, appRoot, bustCache),\n\t\tfunctionGenerator.load(code, appRoot, bustCache),\n\t\tcronGenerator.load(code, appRoot, bustCache),\n\t\tsubscriberGenerator.load(code, appRoot, bustCache),\n\t\tqueueGenerator.load(code, appRoot, bustCache),\n\t\ttopicGenerator.load(code, appRoot, bustCache),\n\t]);\n\n\tconst allEndpoints = servedBy(loadedEndpoints, derived.surface);\n\n\tlogger.log(`Found ${allEndpoints.length} endpoints`);\n\tlogger.log(`Found ${allFunctions.length} functions`);\n\tlogger.log(`Found ${allCrons.length} crons`);\n\tlogger.log(`Found ${allSubscribers.length} subscribers`);\n\tlogger.log(`Found ${allQueues.length} queues`);\n\tlogger.log(`Found ${allTopics.length} topics`);\n\n\tif (\n\t\t!input.serveEmpty &&\n\t\tallEndpoints.length === 0 &&\n\t\tallFunctions.length === 0 &&\n\t\tallCrons.length === 0 &&\n\t\tallSubscribers.length === 0 &&\n\t\tallQueues.length === 0 &&\n\t\tallTopics.length === 0\n\t) {\n\t\tlogger.log(\n\t\t\t'No endpoints, functions, crons, subscribers, queues, or topics found to process',\n\t\t);\n\t\treturn {};\n\t}\n\n\t// A RestApi's production image answers HTTP and nothing else. Queues,\n\t// crons and subscribers belong to a Worker — the process with no port —\n\t// even when they sit in the API's directory, so the server it builds leaves\n\t// them out rather than running them beside the routes.\n\tif (production?.subscribers === 'include' && derived.surface) {\n\t\tbuildContext.production = { ...production, subscribers: 'exclude' };\n\t\tconst left = [\n\t\t\t[allCrons.length, 'cron'],\n\t\t\t[allQueues.length, 'queue consumer'],\n\t\t\t[allSubscribers.length, 'subscriber'],\n\t\t]\n\t\t\t.filter(([n]) => (n as number) > 0)\n\t\t\t.map(([n, what]) => `${n} ${what}${n === 1 ? '' : 's'}`);\n\t\tif (left.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t`Serving ${derived.surface.id} only: leaving out ${left.join(', ')} — they run in a Worker's image`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst result = await buildForTarget(\n\t\ttarget,\n\t\tbuildContext,\n\t\tappRoot,\n\t\tworkspaceRoot,\n\t\tendpointGenerator,\n\t\tfunctionGenerator,\n\t\tcronGenerator,\n\t\tsubscriberGenerator,\n\t\tqueueGenerator,\n\t\ttopicGenerator,\n\t\tallEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t\tenableOpenApi,\n\t\tinput.skipBundle ?? false,\n\t\tinput.stage,\n\t);\n\n\t// Each Worker this app carries: its own entry, and — bundling — its own\n\t// bundle beside the server's, which the worker's image copies out.\n\tif (target === 'server' && production?.enabled && input.workspace) {\n\t\tconst appName = Object.entries(input.workspace.apps).find(\n\t\t\t([, app]) =>\n\t\t\t\tresolve(input.workspace!.root, app.path) === resolve(appRoot),\n\t\t)?.[0];\n\t\tconst hosted = workerUnits(input.workspace, declared, background).filter(\n\t\t\t(unit) => unit.app === appName,\n\t\t);\n\t\tawait buildWorkers({\n\t\t\tcontext: buildContext,\n\t\t\tworkers: hosted,\n\t\t\tserverDir: join(appRoot, '.gkm', 'server'),\n\t\t\tcrons: allCrons,\n\t\t\tqueues: allQueues,\n\t\t\tsubscribers: allSubscribers,\n\t\t\tbundle: Boolean(production.bundle && !input.skipBundle),\n\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t});\n\t}\n\n\t// One spec per surface, from the endpoints the build already loaded rather\n\t// than from a second discovery pass over the same files.\n\tawait generateOpenApi(\n\t\tallEndpoints.map(({ construct }) => construct),\n\t\t{ openapi: config.openapi, root: workspaceRoot },\n\t);\n\n\treturn {\n\t\t...result,\n\t\t...(buildContext.databaseApi\n\t\t\t? { databaseApi: buildContext.databaseApi.path }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Write each worker's entry — and, for an image, bundle it — from the\n * runnables built from that worker, and nothing built from another.\n */\nasync function buildWorkers(input: {\n\tcontext: BuildContext;\n\tworkers: readonly WorkerUnit[];\n\tserverDir: string;\n\tcrons: GeneratedConstruct<Cron<any, any, any, any>>[];\n\tqueues: GeneratedConstruct<Queue<any, any, any, any, any, any>>[];\n\tsubscribers: GeneratedConstruct<\n\t\tSubscriber<any, any, any, any, any, any, any>\n\t>[];\n\tbundle: boolean;\n\tstage?: string;\n}): Promise<void> {\n\tconst generator = new WorkerGenerator();\n\tfor (const worker of input.workers) {\n\t\tconst owned = <T extends { construct: { owner?: string } }>(list: T[]) =>\n\t\t\tlist.filter(({ construct }) => construct.owner === worker.id);\n\t\tconst crons = owned(input.crons);\n\t\tconst queues = owned(input.queues);\n\t\tconst subscribers = owned(input.subscribers);\n\n\t\tconst entryPoint = await generator.build({\n\t\t\tcontext: input.context,\n\t\t\tworkerId: worker.id,\n\t\t\toutputDir: workerEntryDir(input.serverDir, worker.id),\n\t\t\tcrons,\n\t\t\tqueues,\n\t\t\tsubscribers,\n\t\t});\n\t\tlogger.log(\n\t\t\t`Generated worker ${worker.id}: ${crons.length} crons, ${queues.length} queues, ${subscribers.length} subscribers`,\n\t\t);\n\n\t\tif (!input.bundle) continue;\n\t\tconst { bundleServer } = await import('./bundler');\n\t\tconst outfile = workerBundleName(worker.id);\n\t\tawait bundleServer({\n\t\t\tentryPoint,\n\t\t\toutputDir: join(input.serverDir, 'dist'),\n\t\t\toutfile,\n\t\t\tminify: input.context.production?.minify ?? false,\n\t\t\tsourcemap: false,\n\t\t\texternal: input.context.production?.external ?? [],\n\t\t\t...(input.stage ? { stage: input.stage } : {}),\n\t\t\tconstructs: [...crons, ...queues, ...subscribers].map((c) => c.construct),\n\t\t});\n\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/${outfile}`);\n\t}\n}\n\nasync function buildForTarget(\n\ttarget: MainProvider,\n\tcontext: BuildContext,\n\tappRoot: string,\n\tworkspaceRoot: string,\n\tendpointGenerator: EndpointGenerator,\n\tfunctionGenerator: FunctionGenerator,\n\tcronGenerator: CronGenerator,\n\tsubscriberGenerator: SubscriberGenerator,\n\tqueueGenerator: QueueGenerator,\n\ttopicGenerator: TopicGenerator,\n\tendpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],\n\tfunctions: GeneratedConstruct<Function<any, any, any, any>>[],\n\tcrons: GeneratedConstruct<Cron<any, any, any, any>>[],\n\tsubscribers: GeneratedConstruct<\n\t\tSubscriber<any, any, any, any, any, any, any>\n\t>[],\n\tqueues: GeneratedConstruct<Queue<any, any, any, any, any, any>>[],\n\ttopics: GeneratedConstruct<Topic<any, any>>[],\n\tenableOpenApi: boolean,\n\tskipBundle: boolean,\n\tstage?: string,\n): Promise<AppBuildOutput> {\n\t// The handlers live beside the app they import. What they are goes into\n\t// the application's manifest, which the root writes, so every path is\n\t// measured from there.\n\tconst outputDir = join(appRoot, '.gkm', target);\n\n\t// What an older build wrote and nothing writes now — the per-provider trees\n\t// and an app-level manifest — would otherwise sit beside the real output\n\t// forever, read by whoever opens `.gkm/` first.\n\tawait Promise.all(\n\t\t[\n\t\t\t...SUPERSEDED_OUTPUT.map((dir) => join(appRoot, '.gkm', dir)),\n\t\t\t...(appRoot === workspaceRoot ? [] : [join(appRoot, '.gkm', 'manifest')]),\n\t\t].map((dir) => rm(dir, { recursive: true, force: true })),\n\t);\n\n\t// A fresh tree for AWS, so a deleted endpoint's handler goes with it. Not\n\t// for the server: `gkm dev` rebuilds into it while its process runs.\n\tif (target === 'aws') await rm(outputDir, { recursive: true, force: true });\n\tawait mkdir(outputDir, { recursive: true });\n\n\tlogger.log(`\\nGenerating handlers for ${target}`);\n\tconst options = { target, root: workspaceRoot };\n\n\t// Build all constructs in parallel.\n\t// context.markOptional is forwarded to each generator so that\n\t// getEnvironment({ markOptional }) produces `VARNAME?` for optional vars.\n\tconst [\n\t\troutes,\n\t\tfunctionInfos,\n\t\tcronInfos,\n\t\tsubscriberInfos,\n\t\tqueueInfos,\n\t\ttopicInfos,\n\t] = await Promise.all([\n\t\tendpointGenerator.build(context, endpoints, outputDir, {\n\t\t\t...options,\n\t\t\tenableOpenApi,\n\t\t}),\n\t\tfunctionGenerator.build(context, functions, outputDir, options),\n\t\tcronGenerator.build(context, crons, outputDir, options),\n\t\tsubscriberGenerator.build(context, subscribers, outputDir, options),\n\t\tqueueGenerator.build(context, queues, outputDir, options),\n\t\ttopicGenerator.build(context, topics, outputDir, options),\n\t]);\n\n\tlogger.log(\n\t\t`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${target}`,\n\t);\n\n\t// What the manifest folds into the declarations they belong to.\n\tconst fields = {\n\t\t...(context.surface ? { surface: context.surface.id } : {}),\n\t\tfunctions: functionInfos,\n\t\tcrons: cronInfos,\n\t\tqueues: queueInfos,\n\t\tsubscribers: subscriberInfos,\n\t};\n\n\tif (target === 'server') {\n\t\t// Every endpoint, as on AWS — its method, path, edges and authorizer —\n\t\t// served by the one process: the app's entry is each one's handler.\n\t\tconst handler = relative(workspaceRoot, join(outputDir, 'app.ts'));\n\t\tconst built: AppBuild = {\n\t\t\t...fields,\n\t\t\troutes: await Promise.all(\n\t\t\t\tendpoints.map(async ({ construct }) => ({\n\t\t\t\t\tpath: construct._path,\n\t\t\t\t\tmethod: construct.method,\n\t\t\t\t\thandler,\n\t\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t\t}),\n\t\t\t\t\tdependencies: construct.constructs,\n\t\t\t\t\tauthorizer: construct.authorizer?.name ?? 'none',\n\t\t\t\t})),\n\t\t\t),\n\t\t};\n\n\t\t// Bundle for production if enabled\n\t\tlet masterKey: string | undefined;\n\t\tif (context.production?.bundle && !skipBundle) {\n\t\t\tlogger.log(`\\n📦 Bundling production server...`);\n\t\t\tconst { bundleServer } = await import('./bundler');\n\n\t\t\t// Collect all constructs for environment variable validation\n\t\t\tconst allConstructs = [\n\t\t\t\t...endpoints.map((e) => e.construct),\n\t\t\t\t...functions.map((f) => f.construct),\n\t\t\t\t...crons.map((c) => c.construct),\n\t\t\t\t...subscribers.map((s) => s.construct),\n\t\t\t\t...queues.map((q) => q.construct),\n\t\t\t];\n\n\t\t\tconst bundleResult = await bundleServer({\n\t\t\t\tentryPoint: join(outputDir, 'server.ts'),\n\t\t\t\toutputDir: join(outputDir, 'dist'),\n\t\t\t\tminify: context.production.minify,\n\t\t\t\tsourcemap: false,\n\t\t\t\texternal: context.production.external,\n\t\t\t\tstage,\n\t\t\t\tconstructs: allConstructs,\n\t\t\t});\n\t\t\tmasterKey = bundleResult.masterKey;\n\t\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);\n\n\t\t\t// The key is written, not printed: it decrypts every secret of the\n\t\t\t// stage, and build output lands in CI logs and scrollback. The\n\t\t\t// fingerprint is enough to tell which key a build used.\n\t\t\tif (masterKey) {\n\t\t\t\tconst keyPath = join(outputDir, MASTER_KEY_FILE);\n\t\t\t\tawait writeFile(keyPath, `${masterKey}\\n`, { mode: 0o600 });\n\t\t\t\tawait chmod(keyPath, 0o600);\n\t\t\t\tlogger.log(`\\n🔐 Secrets encrypted for deployment`);\n\t\t\t\tlogger.log(\n\t\t\t\t\t` Run with GKM_MASTER_KEY set to the key in ${relative(appRoot, keyPath)} (fingerprint ${keyFingerprint(masterKey)})`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn { masterKey, built };\n\t}\n\n\treturn {\n\t\tbuilt: { ...fields, routes },\n\t};\n}\n\n/**\n * Result of building a single app in a workspace.\n */\nexport interface AppBuildResult {\n\tappName: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tsuccess: boolean;\n\toutputPath?: string;\n\terror?: string;\n}\n\n/**\n * Result of workspace build command.\n */\nexport interface WorkspaceBuildResult extends BuildResult {\n\tapps: AppBuildResult[];\n}\n\n/**\n * Detect available package manager.\n * @internal Exported for testing\n */\nexport function detectPackageManager(): 'pnpm' | 'npm' | 'yarn' {\n\tif (existsSync('pnpm-lock.yaml')) return 'pnpm';\n\tif (existsSync('yarn.lock')) return 'yarn';\n\treturn 'npm';\n}\n\n/**\n * The program and argv that run turbo's build.\n *\n * `filters` names the packages to build. Passing none lets turbo infer its own\n * scope from the working directory, which for a workspace root means the\n * workspace package itself — and since that package's `build` script is\n * `gkm build`, inferring is how you get a build that runs itself forever.\n * `workspaceBuildCommand` always names the apps.\n *\n * An array, not a command string: the filters are package names read from the\n * workspace, and each must reach turbo as one argument whatever it holds. Each\n * is `--filter=<name>`, so even a name starting with `-` stays a filter value.\n *\n * @internal Exported for testing\n */\nexport function getTurboArgs(\n\tpm: 'pnpm' | 'npm' | 'yarn',\n\tfilters: string | readonly string[] = [],\n\t/** Build only the named packages, not what they depend on. */\n\t{ only = false }: { only?: boolean } = {},\n): [bin: string, args: string[]] {\n\tconst list = typeof filters === 'string' ? [filters] : filters;\n\tconst turbo = [\n\t\t'turbo',\n\t\t'run',\n\t\t'build',\n\t\t...list.map((f) => `--filter=${f}`),\n\t\t...(only ? ['--only'] : []),\n\t];\n\tswitch (pm) {\n\t\tcase 'pnpm':\n\t\t\treturn ['pnpm', ['exec', ...turbo]];\n\t\tcase 'yarn':\n\t\t\treturn ['yarn', turbo];\n\t\tcase 'npm':\n\t\t\treturn ['npx', turbo];\n\t}\n}\n\n/**\n * The package names turbo should build: one per app in the workspace.\n *\n * Read from each app's own `package.json`, because that is the name turbo\n * knows it by — and the name `loadAppConfig` reads back when turbo runs\n * `gkm build` inside the app, which is what routes that invocation to the\n * single-app path instead of back here.\n *\n * An app without a `package.json` is not a package turbo can run, so it is\n * reported rather than silently skipped.\n *\n * @internal Exported for testing\n */\nexport function turboFilters(\n\tworkspace: NormalizedWorkspace,\n\t{ exclude }: { exclude?: NormalizedAppConfig['type'] } = {},\n): {\n\tfilters: string[];\n\tunpackaged: string[];\n} {\n\tconst filters: string[] = [];\n\tconst unpackaged: string[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === exclude) continue;\n\t\tconst name = appPackageName(workspace, appName);\n\t\tif (name) filters.push(name);\n\t\telse unpackaged.push(appName);\n\t}\n\n\treturn { filters, unpackaged };\n}\n\n/**\n * The package name turbo knows an app by, from its own `package.json`.\n *\n * Not the app's key: `api` in the workspace is `@shop/api` to turbo, and a\n * filter naming the key matches nothing.\n */\nexport function appPackageName(\n\tworkspace: NormalizedWorkspace,\n\tappName: string,\n): string | undefined {\n\tconst app = workspace.apps[appName];\n\tif (!app) return undefined;\n\n\tconst pkgPath = join(workspace.root, app.path, 'package.json');\n\tif (!existsSync(pkgPath)) return undefined;\n\n\tconst name = JSON.parse(readFileSync(pkgPath, 'utf8')).name;\n\treturn typeof name === 'string' && name.length > 0 ? name : undefined;\n}\n\n/**\n * Build all apps in a workspace using Turbo for dependency-ordered parallel builds.\n * @internal Exported for testing\n */\nexport async function workspaceBuildCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: BuildOptions,\n): Promise<WorkspaceBuildResult> {\n\tconst results: AppBuildResult[] = [];\n\tconst apps = Object.entries(workspace.apps);\n\tconst backendApps = apps.filter(([, app]) => app.type === 'backend');\n\tconst frontendApps = apps.filter(([, app]) => app.type === 'web');\n\n\tlogger.log(`\\n🏗️ Building workspace: ${workspace.name}`);\n\tlogger.log(\n\t\t` Backend apps: ${backendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\tlogger.log(\n\t\t` Frontend apps: ${frontendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\n\tif (options.production) {\n\t\tlogger.log(` 🏭 Production mode enabled`);\n\t}\n\n\t// Get build order (topologically sorted by dependencies)\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlogger.log(` Build order: ${buildOrder.join(' → ')}`);\n\n\ttry {\n\t\t// The backends here, in this process, because the manifest is the\n\t\t// application's: the root builds each one, then writes it once from\n\t\t// everything they generated and everything the workspace declares.\n\t\tconst target = options.provider ?? providerOf(workspace);\n\t\tconst builds: AppBuild[] = [];\n\t\tfor (const appName of buildOrder) {\n\t\t\tconst app = workspace.apps[appName];\n\t\t\tconst config = getAppGkmConfig(workspace, appName);\n\t\t\tif (!app || app.type !== 'backend' || !config) continue;\n\n\t\t\tlogger.log(`\\n⚙️ ${appName}`);\n\t\t\tconst output = await buildOneApp({\n\t\t\t\tconfig,\n\t\t\t\toptions,\n\t\t\t\tworkspace,\n\t\t\t\tappRoot: join(workspace.root, app.path),\n\t\t\t\ttarget,\n\t\t\t});\n\t\t\tif (output.built) builds.push(output.built);\n\t\t}\n\n\t\tawait writeManifest({\n\t\t\tworkspaceRoot: workspace.root,\n\t\t\ttarget,\n\t\t\tbuilds,\n\t\t\tconstructs: await discover({\n\t\t\t\tpatterns: allConstructGlobs(workspace),\n\t\t\t\tcwd: workspace.root,\n\t\t\t}),\n\t\t\tbackends: backendsOf(workspace),\n\t\t});\n\n\t\t// Everything else is its own toolchain's — Vite, Next — through turbo.\n\t\tconst { filters, unpackaged } = turboFilters(workspace, {\n\t\t\texclude: 'backend',\n\t\t});\n\t\tif (unpackaged.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No package.json for workspace app(s): ${unpackaged.join(', ')}. ` +\n\t\t\t\t\t`Each app needs one — turbo builds packages, and gkm reads the ` +\n\t\t\t\t\t`name back to know which app it is building.`,\n\t\t\t);\n\t\t}\n\t\tconst pm = detectPackageManager();\n\t\tconst [turboBin, turboArgs] = getTurboArgs(pm, filters, { only: true });\n\n\t\tif (filters.length > 0) {\n\t\t\tlogger.log(`\\n📦 Using ${pm} with Turbo for the other apps...\\n`);\n\t\t\tlogger.log(`Running: ${[turboBin, ...turboArgs].join(' ')}`);\n\n\t\t\t// In the sandbox: the apps' build scripts are the project's code,\n\t\t\t// and see the sandbox's environment rather than this process's —\n\t\t\t// no deploy credential, no registry login. A remote cache's token\n\t\t\t// is passed on only by the default sandbox, for a project the host\n\t\t\t// already trusts.\n\t\t\tconst sandbox =\n\t\t\t\toptions.sandbox ??\n\t\t\t\tnew LocalSandbox({ root: workspace.root, passEnv: ['TURBO_TOKEN'] });\n\t\t\tconst built = await sandbox.exec(turboBin, turboArgs, {\n\t\t\t\tcwd: workspace.root,\n\t\t\t\tenv: {\n\t\t\t\t\t...sandbox.env,\n\t\t\t\t\t// Pass production flag to builds\n\t\t\t\t\tNODE_ENV: options.production ? 'production' : 'development',\n\t\t\t\t},\n\t\t\t\ttimeoutMs: DEFAULT_TIMEOUT_MS,\n\t\t\t\toutput: 'inherit',\n\t\t\t});\n\t\t\tif (built.exitCode !== 0) {\n\t\t\t\tthrow new CommandFailed(\n\t\t\t\t\tturboBin,\n\t\t\t\t\tturboArgs,\n\t\t\t\t\tbuilt.exitCode,\n\t\t\t\t\tbuilt.signal as NodeJS.Signals | null,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Mark all apps as successful\n\t\tfor (const [appName, app] of apps) {\n\t\t\tconst outputPath = getAppOutputPath(workspace, appName, app);\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: true,\n\t\t\t\toutputPath,\n\t\t\t});\n\t\t}\n\n\t\tlogger.log(`\\n✅ Workspace build complete!`);\n\n\t\t// No OpenAPI pass here. Each backend's build above wrote its surfaces'\n\t\t// clients to the root's `.gkm/client/<surface>.ts` before turbo built\n\t\t// the sites that import them as `@<name>/client/<surface>`.\n\n\t\t// Summary\n\t\tlogger.log(`\\n📋 Build Summary:`);\n\t\tfor (const result of results) {\n\t\t\tconst icon =\n\t\t\t\tresult.type === 'backend'\n\t\t\t\t\t? '⚙️'\n\t\t\t\t\t: result.type === 'mobile'\n\t\t\t\t\t\t? '📱'\n\t\t\t\t\t\t: '🌐';\n\t\t\tlogger.log(\n\t\t\t\t` ${icon} ${result.appName}: ${result.outputPath || 'built'}`,\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tconst errorMessage =\n\t\t\terror instanceof Error ? error.message : 'Build failed';\n\t\tlogger.log(`\\n❌ Build failed: ${errorMessage}`);\n\n\t\t// Mark all apps as failed\n\t\tfor (const [appName, app] of apps) {\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t});\n\t\t}\n\n\t\tthrow error;\n\t}\n\n\treturn { apps: results };\n}\n\n/**\n * Get the output path for a built app.\n */\nfunction getAppOutputPath(\n\tworkspace: NormalizedWorkspace,\n\t_appName: string,\n\tapp: NormalizedAppConfig,\n): string {\n\tconst appPath = join(workspace.root, app.path);\n\n\tif (app.type === 'mobile') {\n\t\t// Mobile builds are produced by the framework's own toolchain\n\t\t// (e.g. EAS Build) — no local output path.\n\t\treturn '';\n\t}\n\tif (app.type === 'web') {\n\t\tswitch (app.framework) {\n\t\t\tcase 'vite':\n\t\t\tcase 'tanstack-start':\n\t\t\t\treturn join(appPath, 'dist');\n\t\t\tcase 'remix':\n\t\t\t\treturn join(appPath, 'build');\n\t\t\tdefault:\n\t\t\t\treturn join(appPath, '.next');\n\t\t}\n\t}\n\t// Backend .gkm output\n\treturn join(appPath, '.gkm');\n}\n\n/** Format routes for logging. */\nfunction formatRoutes(routes: Routes): string {\n\treturn Array.isArray(routes) ? routes.join(', ') : routes;\n}\n","/**\n * `gkm compose` — a workspace's APIs and sites for one stage, as one Docker\n * Compose stack behind Caddy.\n *\n * A convenience over `gkm deploy --target compose`: the stage defaults to the\n * local one, `--build`/`--pull` choose the images whatever `--tag` says, and\n * `--down` stops the stack. Everything else — the order, the image check, the\n * state, the health checks — is the compose target's, run through the same\n * `deploy()` as any other target, so there is one way a stack comes up.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { loadWorkspaceConfig } from '../config';\nimport { deploy } from '../deploy/deploy';\nimport { parseDevServices } from '../deploy/devServices';\nimport { deployIdentity } from '../deploy/identity.js';\nimport type { DeployResult } from '../deploy/types';\nimport {\n\ttype ComposeDeps,\n\ttype ComposeImage,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\ttype ComposeRun,\n\tcomposeTarget,\n\tstackOverrideFile,\n} from '../target/compose/index';\nimport { dockerCompose, type StackRef } from './docker';\nimport { edgeDir, removeEdgeRoutes } from './edge';\nimport { type ImageDigests, parseDigests, pinnedRef } from './images';\nimport { type ComposeStack, composeProject, stackDir } from './stack';\nimport { EDGE_PROJECT } from './traefik';\n\nexport {\n\tComposeAppsUnhealthy,\n\tComposePinNeedsPull,\n\tComposePushNeedsBuild,\n\tEdgePortInvalid,\n\tedgePorts,\n\tgitRevision,\n\tNoGitRevision,\n\tRedisClientMissing,\n} from '../target/compose/index';\nexport {\n\tisMissingManifest,\n\tNetworkCreateFailed,\n\tPushDigestUnknown,\n} from './docker';\nexport { ComposeProxyClash } from './edge';\nexport {\n\tassertImagesExist,\n\tImageDigestMismatch,\n\tImageDigestMissing,\n\tImageDigestsInvalid,\n\tImageTagNotFound,\n\tRegistryRequired,\n\tRegistryUnreachable,\n\tsiteTag,\n} from './images';\nexport {\n\tLogsEndpointConflict,\n\tLogsPasswordMissing,\n\tLogsPasswordWeak,\n\tOPENOBSERVE_IMAGE,\n} from './logs';\nexport {\n\tLogsAllowEmpty,\n\tLogsAllowEntryInvalid,\n\tLogsPortInvalid,\n\tLogsRetentionInvalid,\n} from './logsConfig';\nexport {\n\tComposeStageUnknown,\n\tComposeTlsFileMissing,\n\tComposeTlsOnLocalStage,\n} from './proxy';\nexport {\n\tREDIS_MAXMEMORY,\n\tREDIS_PASSWORD_KEY,\n\tRedisPasswordMissing,\n\tSTACK_CACHE,\n} from './redis';\nexport {\n\tcomposeStack,\n\tEnvValueMultiline,\n\tLOG_ROTATION,\n\tNothingToCompose,\n\tStageSecretMissing,\n\tStageSeedMissing,\n} from './stack';\nexport {\n\tEDGE_NETWORK,\n\tEDGE_PROJECT,\n\tTRAEFIK_IMAGE,\n\ttraefikDynamic,\n} from './traefik';\n\nexport interface ComposeOptions {\n\t/** The stage to run. Always named: nothing defaults to the local stage. */\n\tstage: string;\n\t/** A release tag: pull every app's image at it, build nothing. */\n\ttag?: string;\n\t/** Build images here, whatever `--tag` says. */\n\tbuild?: boolean;\n\t/** Pull images, whatever `--tag` says — `latest` when no tag is given. */\n\tpull?: boolean;\n\t/**\n\t * With `--build`: push every image built to `deploy.registry`, and start\n\t * nothing — no provisioning, no `up`, nothing recorded. What CI runs.\n\t */\n\tpush?: boolean;\n\t/**\n\t * With `--push`, where each pushed image's `<ref>@sha256:…` is written,\n\t * as JSON by app. With `--tag`/`--pull`, the file to read them back from:\n\t * each image is pulled and run at its digest rather than its tag.\n\t */\n\tdigestsFile?: string;\n\t/** Write the files and print the plan; touch nothing else. */\n\tdryRun?: boolean;\n\t/** Stop the stage's stack. Its volumes are kept. */\n\tdown?: boolean;\n\t/** The workspace — the current directory when absent. */\n\tcwd?: string;\n\t/**\n\t * `--allow-dev-services minio,mailpit`: on a deployed stage, run MinIO\n\t * and Mailpit for the buckets and mail its secrets do not configure.\n\t */\n\tallowDevServices?: string | readonly string[];\n}\n\nexport interface ComposeResult {\n\tstack: ComposeStack;\n\t/** Every file written, absolute. */\n\tfiles: string[];\n\t/** Each app's recorded image — absent on a dry run. */\n\timages?: Record<string, ComposeImage>;\n\t/** What the deploy reports, as `gkm deploy --target compose` would. */\n\tdeploy: DeployResult;\n}\n\n/** `--build` and `--pull` together ask for two different things. */\nexport class ComposeModeConflict extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'--build and --pull ask for opposite things: build images from this ' +\n\t\t\t\t'checkout, or pull a tag CI pushed. Pass one of them.',\n\t\t);\n\t\tthis.name = 'ComposeModeConflict';\n\t}\n}\n\n/** Each pushed image as `<ref>@sha256:…`, by app. */\nfunction pushedDigests(run: ComposeRun): ImageDigests {\n\treturn Object.fromEntries(\n\t\tObject.entries(run.images)\n\t\t\t.filter(([, image]) => image.digest)\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([app, image]) => [app, pinnedRef(image.ref, image.digest!)]),\n\t);\n}\n\n/** `gkm compose`. */\nexport async function composeCommand(\n\toptions: ComposeOptions,\n\tdeps: Partial<ComposeDeps> = {},\n): Promise<ComposeResult | undefined> {\n\tif (options.build && options.pull) throw new ComposeModeConflict();\n\tif (options.push && !options.build) throw new ComposePushNeedsBuild();\n\tconst pulls = !options.build && (options.pull || options.tag !== undefined);\n\tif (options.digestsFile && !options.push && !pulls) {\n\t\tthrow new ComposePinNeedsPull();\n\t}\n\tconst allowDevServices = parseDevServices(options.allowDevServices);\n\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\t// Read here only for what the command adds: the project `--down` stops. The deploy loads it again, as it\n\t// loads every project, in its sandbox.\n\tconst { workspace } = await loadWorkspaceConfig(cwd);\n\tconst { stage } = options;\n\n\tif (options.down) {\n\t\tconst override = stackOverrideFile(workspace.root, stage);\n\t\tconst ref: StackRef = {\n\t\t\tproject: composeProject(deployIdentity(workspace, stage)),\n\t\t\tfile: join(workspace.root, stackDir(stage), 'docker-compose.yml'),\n\t\t\t...(existsSync(override) ? { overrides: [override] } : {}),\n\t\t\tcwd: workspace.root,\n\t\t};\n\t\t// Unregistered from the shared edge first, so it stops routing to the\n\t\t// stack before the stack stops. The edge keeps serving every other\n\t\t// stack — and keeps running.\n\t\tif (await removeEdgeRoutes(edgeDir(deps.env ?? process.env), ref.project)) {\n\t\t\tconsole.log(`🌐 Removed ${ref.project}'s routes from ${EDGE_PROJECT}.`);\n\t\t}\n\t\tawait (deps.docker ?? dockerCompose).down(ref);\n\t\tconsole.log(`🛑 Stopped ${ref.project}. Its volumes are kept.`);\n\t\treturn undefined;\n\t}\n\n\tlet finished: ComposeRun | undefined;\n\tconst mode = options.build ? 'build' : options.pull ? 'pull' : undefined;\n\tconst tag = options.tag ?? (options.pull ? 'latest' : undefined);\n\n\t// A pinned release: each image at the digest its push reported.\n\tconst pin =\n\t\toptions.digestsFile && pulls\n\t\t\t? {\n\t\t\t\t\tfile: options.digestsFile,\n\t\t\t\t\tdigests: parseDigests(\n\t\t\t\t\t\toptions.digestsFile,\n\t\t\t\t\t\tawait readFile(resolve(cwd, options.digestsFile), 'utf-8'),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: undefined;\n\n\tconst run = deploy({\n\t\tcwd,\n\t\tstage,\n\t\ttarget: 'compose',\n\t\t// The target with this command's switches, in place of the built-in.\n\t\ttargets: {\n\t\t\tcompose: composeTarget({\n\t\t\t\t...deps,\n\t\t\t\t...(mode ? { mode } : {}),\n\t\t\t\t...(options.push ? { push: true } : {}),\n\t\t\t\t...(pin ? { pin } : {}),\n\t\t\t\treport: (done) => {\n\t\t\t\t\tfinished = done;\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t\t...(tag ? { tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.push ? { buildOnly: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\tconst result = await run.result;\n\tif (!finished) return undefined;\n\n\tif (options.push && !options.dryRun) {\n\t\tconst digests = pushedDigests(finished);\n\t\tconsole.log(`\\n✅ Pushed ${Object.keys(digests).length} image(s):`);\n\t\tfor (const [app, ref] of Object.entries(digests)) {\n\t\t\tconsole.log(` ${app.padEnd(12)} ${ref}`);\n\t\t}\n\t\tif (options.digestsFile) {\n\t\t\tconst file = resolve(cwd, options.digestsFile);\n\t\t\tawait mkdir(dirname(file), { recursive: true });\n\t\t\tawait writeFile(file, `${JSON.stringify(digests, null, 2)}\\n`);\n\t\t\tconsole.log(`\\n📝 Wrote the digests to ${options.digestsFile}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tstack: finished.stack,\n\t\tfiles: finished.files,\n\t\t...(options.dryRun ? {} : { images: finished.images }),\n\t\tdeploy: result,\n\t};\n}\n","let _debug = false;\n\n/**\n * Enable debug mode globally.\n * When enabled, verbose error details are shown everywhere.\n */\nexport function enableDebug(): void {\n\t_debug = true;\n}\n\n/**\n * Check if debug mode is active.\n * Activated by `--debug` flag or `GKM_DEBUG=1` env var.\n */\nexport function isDebug(): boolean {\n\treturn _debug || process.env.GKM_DEBUG === '1';\n}\n\n/**\n * Log a message only when debug mode is active.\n */\nexport function debug(...args: unknown[]): void {\n\tif (isDebug()) {\n\t\tconsole.debug('[debug]', ...args);\n\t}\n}\n\n/**\n * Format a fatal error for display.\n * Always includes the full stack trace since these are process-ending errors.\n */\nexport function formatError(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tlet output = error.stack ?? error.message;\n\n\t// Include cause chain if present\n\tlet cause = error.cause;\n\twhile (cause) {\n\t\tif (cause instanceof Error) {\n\t\t\toutput += `\\n\\nCaused by: ${cause.stack ?? cause.message}`;\n\t\t\tcause = cause.cause;\n\t\t} else {\n\t\t\toutput += `\\n\\nCaused by: ${String(cause)}`;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn output;\n}\n\n/**\n * Format a non-fatal error for display.\n * Shows only the message by default, full stack in debug mode.\n */\nexport function formatWarning(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tif (!isDebug()) {\n\t\treturn error.message;\n\t}\n\n\treturn error.stack ?? error.message;\n}\n","import {\n\tgetDokployCredentials,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployRegistryId,\n} from '../auth';\nimport { DokployApi } from '../target/dokploy/dokploy-api';\nimport type { DokployDeployConfig } from './types';\n\nconst logger = console;\n\nexport interface DeployInitOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Project name (creates new or uses existing) */\n\tprojectName: string;\n\t/** Application name */\n\tappName: string;\n\t/** Use existing project ID instead of creating/finding */\n\tprojectId?: string;\n\t/** Registry ID in Dokploy (optional, uses stored if available) */\n\tregistryId?: string;\n}\n\nexport interface RegistrySetupOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Registry name (for display in Dokploy) */\n\tregistryName: string;\n\t/** Registry URL (e.g., ghcr.io, docker.io) */\n\tregistryUrl: string;\n\t/** Registry username */\n\tusername: string;\n\t/** Registry password or token */\n\tpassword: string;\n\t/** Image prefix (optional, e.g., org-name) */\n\timagePrefix?: string;\n}\n\n/**\n * Get the Dokploy API token from stored credentials or environment\n */\nasync function getApiToken(): Promise<string> {\n\tconst token = await getDokployToken();\n\tif (!token) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found.\\n' +\n\t\t\t\t'Run \"gkm login --service dokploy\" to authenticate, or set DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\treturn token;\n}\n\n/**\n * Get Dokploy endpoint from options or stored credentials\n */\nasync function getEndpoint(providedEndpoint?: string): Promise<string> {\n\tif (providedEndpoint) {\n\t\treturn providedEndpoint;\n\t}\n\n\tconst stored = await getDokployCredentials();\n\tif (stored) {\n\t\treturn stored.endpoint;\n\t}\n\n\tthrow new Error(\n\t\t'Dokploy endpoint not specified.\\n' +\n\t\t\t'Either run \"gkm login --service dokploy\" first, or provide --endpoint.',\n\t);\n}\n\n/**\n * Create a Dokploy API client\n */\nasync function createApi(endpoint: string): Promise<DokployApi> {\n\tconst token = await getApiToken();\n\treturn new DokployApi({ baseUrl: endpoint, token });\n}\n\n/**\n * Initialize Dokploy deployment configuration\n */\nexport async function deployInitCommand(\n\toptions: DeployInitOptions,\n): Promise<DokployDeployConfig> {\n\tconst {\n\t\tprojectName,\n\t\tappName,\n\t\tprojectId: existingProjectId,\n\t\tregistryId,\n\t} = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🚀 Initializing Dokploy deployment...`);\n\tlogger.log(` Endpoint: ${endpoint}`);\n\n\t// Step 1: Find or create project\n\tlet projectId: string;\n\n\tif (existingProjectId) {\n\t\tprojectId = existingProjectId;\n\t\tlogger.log(`\\n📁 Using existing project: ${projectId}`);\n\t} else {\n\t\tlogger.log(`\\n📁 Looking for project: ${projectName}`);\n\n\t\tconst projects = await api.listProjects();\n\t\tconst existingProject = projects.find(\n\t\t\t(p) => p.name.toLowerCase() === projectName.toLowerCase(),\n\t\t);\n\n\t\tif (existingProject) {\n\t\t\tprojectId = existingProject.projectId;\n\t\t\tlogger.log(` Found existing project: ${projectId}`);\n\t\t} else {\n\t\t\tlogger.log(` Creating new project...`);\n\t\t\tconst result = await api.createProject(projectName);\n\t\t\tprojectId = result.project.projectId;\n\t\t\tlogger.log(` ✓ Created project: ${projectId}`);\n\t\t}\n\t}\n\n\t// Step 2: Get project to find environment\n\tconst project = await api.getProject(projectId);\n\tlet environmentId: string;\n\n\tconst firstEnv = project.environments?.[0];\n\tif (firstEnv) {\n\t\tenvironmentId = firstEnv.environmentId;\n\t} else {\n\t\t// Create a default environment\n\t\tlogger.log(` Creating production environment...`);\n\t\tconst env = await api.createEnvironment(projectId, 'production');\n\t\tenvironmentId = env.environmentId;\n\t}\n\n\t// Step 3: Create application\n\tlogger.log(`\\n📦 Creating application: ${appName}`);\n\tconst application = await api.createApplication(\n\t\tappName,\n\t\tprojectId,\n\t\tenvironmentId,\n\t);\n\tlogger.log(` ✓ Created application: ${application.applicationId}`);\n\n\t// Step 4: Configure registry if provided\n\tif (registryId) {\n\t\tlogger.log(`\\n🔧 Configuring registry: ${registryId}`);\n\t\tawait api.updateApplication(application.applicationId, { registryId });\n\t\tlogger.log(` ✓ Registry configured`);\n\t} else {\n\t\t// List available registries\n\t\ttry {\n\t\t\tconst registries = await api.listRegistries();\n\t\t\tif (registries.length > 0) {\n\t\t\t\tlogger.log(`\\n📋 Available registries:`);\n\t\t\t\tfor (const reg of registries) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlogger.log(`\\n To use a registry, run with --registry-id <id>`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore registry listing errors\n\t\t}\n\t}\n\n\t// Step 5: Build config\n\tconst config: DokployDeployConfig = {\n\t\tendpoint,\n\t\tprojectId,\n\t\tapplicationId: application.applicationId,\n\t};\n\n\t// Nothing is written into gkm.config.ts: the ids are rediscovered by name\n\t// on the next deploy and remembered in the state file.\n\tlogger.log(`\\n✅ Dokploy deployment initialized!`);\n\tlogger.log(`\\n📋 Configuration:`);\n\tlogger.log(` Project ID: ${projectId}`);\n\tlogger.log(` Application ID: ${application.applicationId}`);\n\tlogger.log(`\\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);\n\tlogger.log(`\\n📝 Next steps:`);\n\tlogger.log(` 1. Initialize secrets: gkm secrets:init --stage production`);\n\tlogger.log(` 2. Deploy: gkm deploy --stage production`);\n\n\treturn config;\n}\n\n/**\n * List available Dokploy resources\n */\nexport async function deployListCommand(options: {\n\tendpoint?: string;\n\tresource: 'projects' | 'registries';\n}): Promise<void> {\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tconst { resource } = options;\n\n\tif (resource === 'projects') {\n\t\tlogger.log(`\\n📁 Projects in ${endpoint}:`);\n\t\tconst projects = await api.listProjects();\n\n\t\tif (projects.length === 0) {\n\t\t\tlogger.log(' No projects found');\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const project of projects) {\n\t\t\tlogger.log(`\\n ${project.name} (${project.projectId})`);\n\t\t\tif (project.description) {\n\t\t\t\tlogger.log(` ${project.description}`);\n\t\t\t}\n\t\t}\n\t} else if (resource === 'registries') {\n\t\tlogger.log(`\\n🐳 Registries in ${endpoint}:`);\n\t\tconst registries = await api.listRegistries();\n\n\t\tif (registries.length === 0) {\n\t\t\tlogger.log(' No registries configured');\n\t\t\tlogger.log(' Run \"gkm registry:setup\" to configure a registry');\n\t\t\treturn;\n\t\t}\n\n\t\tconst storedRegistryId = await getDokployRegistryId();\n\n\t\tfor (const registry of registries) {\n\t\t\tconst isDefault = registry.registryId === storedRegistryId;\n\t\t\tconst marker = isDefault ? ' (default)' : '';\n\t\t\tlogger.log(\n\t\t\t\t`\\n ${registry.registryName}${marker} (${registry.registryId})`,\n\t\t\t);\n\t\t\tlogger.log(` URL: ${registry.registryUrl}`);\n\t\t\tlogger.log(` Username: ${registry.username}`);\n\t\t\tif (registry.imagePrefix) {\n\t\t\t\tlogger.log(` Prefix: ${registry.imagePrefix}`);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Setup a Docker registry in Dokploy\n */\nexport async function registrySetupCommand(\n\toptions: RegistrySetupOptions,\n): Promise<string> {\n\tconst { registryName, registryUrl, username, password, imagePrefix } =\n\t\toptions;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🐳 Setting up Docker registry in Dokploy...`);\n\tlogger.log(` Endpoint: ${endpoint}`);\n\n\t// Check if registry with same URL already exists\n\tconst existingRegistries = await api.listRegistries();\n\tconst existing = existingRegistries.find(\n\t\t(r) =>\n\t\t\tr.registryUrl === registryUrl ||\n\t\t\tr.registryName.toLowerCase() === registryName.toLowerCase(),\n\t);\n\n\tlet registryId: string;\n\n\tif (existing) {\n\t\tlogger.log(`\\n📋 Found existing registry: ${existing.registryName}`);\n\t\tlogger.log(` Updating credentials...`);\n\n\t\tawait api.updateRegistry(existing.registryId, {\n\t\t\tregistryName,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\timagePrefix,\n\t\t});\n\n\t\tregistryId = existing.registryId;\n\t\tlogger.log(` ✓ Registry updated: ${registryId}`);\n\t} else {\n\t\tlogger.log(`\\n📦 Creating registry: ${registryName}`);\n\n\t\tconst registry = await api.createRegistry(\n\t\t\tregistryName,\n\t\t\tregistryUrl,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\t{ imagePrefix },\n\t\t);\n\n\t\tregistryId = registry.registryId;\n\t\tlogger.log(` ✓ Registry created: ${registryId}`);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\tlogger.log(`\\n💾 Saved registry ID to ~/.gkm/credentials.json`);\n\n\tlogger.log(`\\n✅ Registry setup complete!`);\n\tlogger.log(`\\n📋 Registry Details:`);\n\tlogger.log(` ID: ${registryId}`);\n\tlogger.log(` Name: ${registryName}`);\n\tlogger.log(` URL: ${registryUrl}`);\n\tlogger.log(` Username: ${username}`);\n\tif (imagePrefix) {\n\t\tlogger.log(` Prefix: ${imagePrefix}`);\n\t}\n\n\tlogger.log(\n\t\t`\\n📝 The registry ID is now stored and will be used automatically`,\n\t);\n\tlogger.log(` when deploying with \"gkm deploy --target dokploy\"`);\n\n\treturn registryId;\n}\n\n/**\n * Use an existing registry (set as default)\n */\nexport async function registryUseCommand(options: {\n\tendpoint?: string;\n\tregistryId: string;\n}): Promise<void> {\n\tconst { registryId } = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🔧 Setting default registry...`);\n\n\t// Verify the registry exists\n\ttry {\n\t\tconst registry = await api.getRegistry(registryId);\n\t\tlogger.log(` Found registry: ${registry.registryName}`);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Registry not found: ${registryId}\\n` +\n\t\t\t\t'Run \"gkm deploy:list registries\" to see available registries.',\n\t\t);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\n\tlogger.log(`\\n✅ Default registry set: ${registryId}`);\n\tlogger.log(` This registry will be used for future deployments.`);\n}\n","/**\n * State Management CLI Commands\n *\n * Commands for managing deployment state across local and remote stores.\n *\n * Every command goes through a `StateStore`, the same one deploy writes\n * through: a v1 state is migrated on the way, resource records travel with\n * the state, and a copy is a conditional write — so `state:push` cannot\n * silently replace what a deploy wrote a moment earlier.\n */\n\nimport { loadWorkspaceConfig } from '../config';\nimport type { NormalizedWorkspace } from '../workspace/types';\nimport { LocalStateStore } from './LocalStateStore';\nimport {\n\tcreateStateStore,\n\ttype ResourceRecord,\n\ttype StateStore,\n\ttype StoredStageState,\n} from './StateStore';\nimport type { DokployStageState } from './state';\n\n/** What `state:show` prints in place of a secret. */\nexport const MASKED = '********';\n\n/**\n * A copy of `state` with every secret replaced by `MASKED`: database\n * passwords, generated secrets and the backup IAM keys. `state:show` is run\n * to look up ids, in terminals and CI logs; nothing it prints should be\n * usable as a credential.\n */\nexport function maskStateSecrets(state: DokployStageState): DokployStageState {\n\tconst masked: DokployStageState = structuredClone(state);\n\n\tfor (const credentials of Object.values(masked.appCredentials ?? {})) {\n\t\tcredentials.dbPassword = MASKED;\n\t}\n\tfor (const secrets of Object.values(masked.generatedSecrets ?? {})) {\n\t\tfor (const name of Object.keys(secrets)) {\n\t\t\tsecrets[name] = MASKED;\n\t\t}\n\t}\n\tif (masked.backups) {\n\t\tmasked.backups.iamAccessKeyId = MASKED;\n\t\tmasked.backups.iamSecretAccessKey = MASKED;\n\t}\n\n\treturn masked;\n}\n\nexport interface StateCommandOptions {\n\tstage: string;\n}\n\n/**\n * Pull state from remote to local.\n * `gkm state:pull --stage=<stage>`\n */\nexport async function statePullCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst { local, remote } = await remoteAndLocal(workspace);\n\n\tconsole.log(`Pulling state for stage: ${options.stage}...`);\n\tconst pulled = await copyUnderLock(\n\t\tremote,\n\t\tlocal,\n\t\tlocal,\n\t\toptions.stage,\n\t\t'state:pull',\n\t);\n\n\tif (pulled) {\n\t\tconsole.log('State pulled successfully.');\n\t\tprintStateSummary(pulled.state);\n\t} else {\n\t\tconsole.log('No remote state found for this stage.');\n\t}\n}\n\n/**\n * Push local state to remote.\n * `gkm state:push --stage=<stage>`\n */\nexport async function statePushCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst { local, remote } = await remoteAndLocal(workspace);\n\n\tconsole.log(`Pushing state for stage: ${options.stage}...`);\n\t// Under the remote stage's lock: a push while a deploy of the stage runs\n\t// would replace the state that deploy is journaling into. It gets\n\t// `StateLocked` naming the deploy instead.\n\tconst pushed = await copyUnderLock(\n\t\tlocal,\n\t\tremote,\n\t\tremote,\n\t\toptions.stage,\n\t\t'state:push',\n\t);\n\n\tif (pushed) {\n\t\tconsole.log('State pushed successfully.');\n\t\tprintStateSummary(pushed.state);\n\t} else {\n\t\tconsole.log('No local state found for this stage.');\n\t}\n}\n\n/**\n * Show current state.\n * `gkm state:show --stage=<stage>`\n */\nexport async function stateShowCommand(\n\toptions: StateCommandOptions & { json?: boolean },\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\t// The store deploy writes through — the remote one when there is one, read\n\t// directly, so a stale local copy is never what this shows.\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tconst stored = await store.read(options.stage);\n\n\tif (!stored) {\n\t\tconsole.log(`No state found for stage: ${options.stage}`);\n\t\treturn;\n\t}\n\n\tconst state = maskStateSecrets(stored.state);\n\n\tif (options.json) {\n\t\tconsole.log(JSON.stringify(state, null, 2));\n\t} else {\n\t\tprintStateDetails(state);\n\t\tprintUnfinished(stored.resources);\n\t}\n}\n\n/**\n * Release a stage's deploy lock, whoever holds it.\n * `gkm state:unlock --stage=<stage>`\n *\n * For a run that crashed with the lock held. Releasing a lock a live run\n * holds lets a second run race it, so the holder is printed for the caller\n * to check.\n */\nexport async function stateUnlockCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tconst store = await createStateStore({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tconst holder = await store.forceUnlock(options.stage);\n\n\tif (!holder) {\n\t\tconsole.log(`Stage ${options.stage} was not locked.`);\n\t\treturn;\n\t}\n\n\tconsole.log(\n\t\t`Released the lock on stage ${options.stage}, held by ${holder.owner}@${holder.host} (pid ${holder.pid}) since ${holder.acquiredAt}.`,\n\t);\n}\n\n/**\n * Compare local and remote state.\n * `gkm state:diff --stage=<stage>`\n */\nexport async function stateDiffCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\tconst stores = await remoteAndLocal(workspace, [\n\t\t'Diff requires a remote provider to compare against.',\n\t]);\n\n\tconsole.log(`Comparing state for stage: ${options.stage}...\\n`);\n\tconst [localStored, remoteStored] = await Promise.all([\n\t\tstores.local.read(options.stage),\n\t\tstores.remote.read(options.stage),\n\t]);\n\tconst local = localStored?.state ?? null;\n\tconst remote = remoteStored?.state ?? null;\n\n\tif (!local && !remote) {\n\t\tconsole.log('No state found (local or remote).');\n\t\treturn;\n\t}\n\n\tif (!local) {\n\t\tconsole.log('Local: (none)');\n\t} else {\n\t\tconsole.log(`Local: Last deployed ${local.lastDeployedAt}`);\n\t}\n\n\tif (!remote) {\n\t\tconsole.log('Remote: (none)');\n\t} else {\n\t\tconsole.log(`Remote: Last deployed ${remote.lastDeployedAt}`);\n\t}\n\n\tconsole.log('');\n\n\t// Compare applications\n\tconst localApps = local?.applications ?? {};\n\tconst remoteApps = remote?.applications ?? {};\n\tconst allApps = new Set([\n\t\t...Object.keys(localApps),\n\t\t...Object.keys(remoteApps),\n\t]);\n\n\tif (allApps.size > 0) {\n\t\tconsole.log('Applications:');\n\t\tfor (const app of allApps) {\n\t\t\tconst localId = localApps[app];\n\t\t\tconst remoteId = remoteApps[app];\n\n\t\t\tif (localId === remoteId) {\n\t\t\t\tconsole.log(` ${app}: ${localId ?? '(none)'}`);\n\t\t\t} else if (!localId) {\n\t\t\t\tconsole.log(` ${app}: (none) -> ${remoteId} [REMOTE ONLY]`);\n\t\t\t} else if (!remoteId) {\n\t\t\t\tconsole.log(` ${app}: ${localId} -> (none) [LOCAL ONLY]`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ${app}: ${localId} (local) != ${remoteId} (remote) [MISMATCH]`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compare services\n\tconst localServices = local?.services ?? {};\n\tconst remoteServices = remote?.services ?? {};\n\n\tif (\n\t\tObject.keys(localServices).length > 0 ||\n\t\tObject.keys(remoteServices).length > 0\n\t) {\n\t\tconsole.log('\\nServices:');\n\t\tconst serviceKeys = new Set([\n\t\t\t...Object.keys(localServices),\n\t\t\t...Object.keys(remoteServices),\n\t\t]);\n\n\t\tfor (const key of serviceKeys) {\n\t\t\tconst localVal = localServices[key as keyof typeof localServices];\n\t\t\tconst remoteVal = remoteServices[key as keyof typeof remoteServices];\n\n\t\t\tif (localVal === remoteVal) {\n\t\t\t\tconsole.log(` ${key}: ${localVal ?? '(none)'}`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ${key}: ${localVal ?? '(none)'} (local) != ${remoteVal ?? '(none)'} (remote)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Resource records: only where the two disagree, since agreeing records\n\t// repeat the applications and services above.\n\tconst localRecords = localStored?.resources ?? {};\n\tconst remoteRecords = remoteStored?.resources ?? {};\n\tconst differing = [\n\t\t...new Set([...Object.keys(localRecords), ...Object.keys(remoteRecords)]),\n\t].filter(\n\t\t(key) =>\n\t\t\tdescribeRecord(localRecords[key]) !== describeRecord(remoteRecords[key]),\n\t);\n\n\tif (differing.length > 0) {\n\t\tconsole.log('\\nResources:');\n\t\tfor (const key of differing) {\n\t\t\tconsole.log(\n\t\t\t\t` ${key}: ${describeRecord(localRecords[key])} (local) != ${describeRecord(remoteRecords[key])} (remote)`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * The stage's local store and its remote one — or, for a workspace that keeps\n * state only locally, the reason there is nothing to move it between.\n */\nasync function remoteAndLocal(\n\tworkspace: NormalizedWorkspace,\n\thint: readonly string[] = [\n\t\t'Add a remote provider in gkm.config.ts:',\n\t\t' state: { provider: \"ssm\", region: \"us-east-1\" }',\n\t],\n): Promise<{ local: LocalStateStore; remote: StateStore }> {\n\tif (!workspace.state || workspace.state.provider === 'local') {\n\t\tconsole.error('No remote state provider configured.');\n\t\tfor (const line of hint) console.error(line);\n\t\tprocess.exit(1);\n\t}\n\n\treturn {\n\t\tlocal: new LocalStateStore(workspace.root),\n\t\tremote: await createStateStore({\n\t\t\tconfig: workspace.state,\n\t\t\tworkspaceRoot: workspace.root,\n\t\t\tworkspaceName: workspace.name,\n\t\t}),\n\t};\n}\n\n/**\n * Makes `to` hold exactly what `from` holds for `stage` — its state and its\n * resource records — while holding `locked`'s lock for the stage. Every\n * write is conditional on the version just read, so anything that changes\n * `to` mid-copy raises `StateVersionConflict` rather than being overwritten.\n */\nasync function copyUnderLock(\n\tfrom: StateStore,\n\tto: StateStore,\n\tlocked: StateStore,\n\tstage: string,\n\toperation: string,\n): Promise<StoredStageState | null> {\n\tconst lock = await locked.lock(stage, { operation });\n\ttry {\n\t\treturn await copyStage(from, to, stage);\n\t} finally {\n\t\tawait lock.release();\n\t}\n}\n\n/** @internal Exported for testing */\nexport async function copyStage(\n\tfrom: StateStore,\n\tto: StateStore,\n\tstage: string,\n): Promise<StoredStageState | null> {\n\tconst source = await from.read(stage);\n\tif (!source) return null;\n\n\tconst target = await to.read(stage);\n\tlet version = await to.write(stage, source.state, {\n\t\texpectedVersion: target?.version ?? null,\n\t});\n\n\t// The source's records, exactly: one only the target has describes a\n\t// resource the source does not know about, and keeping it would make the\n\t// copy something neither side wrote.\n\tfor (const key of Object.keys(target?.resources ?? {})) {\n\t\tif (key in source.resources) continue;\n\t\tversion = await to.deleteResource(stage, key, {\n\t\t\texpectedVersion: version,\n\t\t});\n\t}\n\tfor (const { updatedAt: _stamped, ...record } of Object.values(\n\t\tsource.resources,\n\t)) {\n\t\tversion = await to.putResource(stage, record, {\n\t\t\texpectedVersion: version,\n\t\t});\n\t}\n\n\treturn source;\n}\n\nfunction describeRecord(record: ResourceRecord | undefined): string {\n\tif (!record) return '(none)';\n\treturn record.id ? `${record.status} ${record.id}` : record.status;\n}\n\n/** Resources a run marked `pending` and never saw created. */\nfunction printUnfinished(resources: Record<string, ResourceRecord>): void {\n\tconst pending = Object.values(resources).filter(\n\t\t(record) => record.status === 'pending',\n\t);\n\tif (pending.length === 0) return;\n\n\tconsole.log('');\n\tconsole.log('Unfinished (a deploy stopped while creating these):');\n\tfor (const record of pending) {\n\t\tconsole.log(` ${record.key}`);\n\t}\n}\n\nfunction printStateSummary(state: DokployStageState): void {\n\tconst appCount = Object.keys(state.applications).length;\n\tconst hasPostgres = !!state.services.postgresId;\n\tconst hasRedis = !!state.services.redisId;\n\n\tconsole.log(` Stage: ${state.stage}`);\n\tconsole.log(` Applications: ${appCount}`);\n\tconsole.log(` Postgres: ${hasPostgres ? 'configured' : 'none'}`);\n\tconsole.log(` Redis: ${hasRedis ? 'configured' : 'none'}`);\n\tconsole.log(` Last deployed: ${state.lastDeployedAt}`);\n}\n\nfunction printStateDetails(state: DokployStageState): void {\n\tconsole.log(`Stage: ${state.stage}`);\n\tconsole.log(`Environment ID: ${state.environmentId}`);\n\tconsole.log(`Last Deployed: ${state.lastDeployedAt}`);\n\tconsole.log('');\n\n\tconsole.log('Applications:');\n\tconst apps = Object.entries(state.applications);\n\tif (apps.length === 0) {\n\t\tconsole.log(' (none)');\n\t} else {\n\t\tfor (const [name, id] of apps) {\n\t\t\tconsole.log(` ${name}: ${id}`);\n\t\t}\n\t}\n\tconsole.log('');\n\n\tconsole.log('Services:');\n\tif (!state.services.postgresId && !state.services.redisId) {\n\t\tconsole.log(' (none)');\n\t} else {\n\t\tif (state.services.postgresId) {\n\t\t\tconsole.log(` Postgres: ${state.services.postgresId}`);\n\t\t}\n\t\tif (state.services.redisId) {\n\t\t\tconsole.log(` Redis: ${state.services.redisId}`);\n\t\t}\n\t}\n\n\tconst credentials = Object.entries(state.appCredentials ?? {});\n\tif (credentials.length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('Database Credentials:');\n\t\tfor (const [app, { dbUser, dbPassword }] of credentials) {\n\t\t\tconsole.log(` ${app}: ${dbUser} / ${dbPassword}`);\n\t\t}\n\t}\n\n\tconst generated = Object.entries(state.generatedSecrets ?? {});\n\tif (generated.length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('Generated Secrets:');\n\t\tfor (const [app, secrets] of generated) {\n\t\t\tfor (const [name, value] of Object.entries(secrets)) {\n\t\t\t\tconsole.log(` ${app}.${name}: ${value}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (state.backups) {\n\t\tconsole.log('');\n\t\tconsole.log('Backups:');\n\t\tconsole.log(` Bucket: ${state.backups.bucketName}`);\n\t\tconsole.log(` IAM User: ${state.backups.iamUserName}`);\n\t\tconsole.log(` IAM Access Key: ${state.backups.iamAccessKeyId}`);\n\t\tconsole.log(` IAM Secret Key: ${state.backups.iamSecretAccessKey}`);\n\t}\n\n\tif (state.dnsVerified && Object.keys(state.dnsVerified).length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('DNS Verified:');\n\t\tfor (const [hostname, info] of Object.entries(state.dnsVerified)) {\n\t\t\tconsole.log(` ${hostname}: ${info.serverIp} (${info.verifiedAt})`);\n\t\t}\n\t}\n}\n","import { randomBytes } from 'node:crypto';\nimport type {\n\tSecretServiceName,\n\tServiceCredentials,\n\tStageSecrets,\n} from './types';\n\n/**\n * Generate a secure random password using URL-safe base64 characters.\n * @param length Password length (default: 32)\n */\nexport function generateSecurePassword(length = 32): string {\n\treturn randomBytes(Math.ceil((length * 3) / 4))\n\t\t.toString('base64url')\n\t\t.slice(0, length);\n}\n\n/** Default service configurations (localhost for local dev via Docker port mapping) */\nconst SERVICE_DEFAULTS: Record<\n\tSecretServiceName,\n\tOmit<ServiceCredentials, 'password'>\n> = {\n\tpostgres: {\n\t\thost: 'localhost',\n\t\tport: 5432,\n\t\tusername: 'app',\n\t\tdatabase: 'app',\n\t},\n\tredis: {\n\t\thost: 'localhost',\n\t\tport: 6379,\n\t\tusername: 'default',\n\t},\n\tminio: {\n\t\thost: 'localhost',\n\t\tport: 9000,\n\t\tusername: 'app',\n\t\tbucket: 'app',\n\t},\n\tmailpit: {\n\t\thost: 'localhost',\n\t\tport: 1025,\n\t\tusername: 'app',\n\t},\n\tlocalstack: {\n\t\thost: 'localhost',\n\t\tport: 4566,\n\t\tusername: 'localstack',\n\t\tregion: 'us-east-1',\n\t},\n};\n\n/**\n * Generate credentials for a specific service.\n */\nexport function generateServiceCredentials(\n\tservice: SecretServiceName,\n): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS[service];\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t};\n}\n\n/**\n * Generate credentials for multiple services.\n */\nexport function generateServicesCredentials(\n\tservices: SecretServiceName[],\n): StageSecrets['services'] {\n\tconst result: StageSecrets['services'] = {};\n\n\tfor (const service of services) {\n\t\tresult[service] = generateServiceCredentials(service);\n\t}\n\n\treturn result;\n}\n\n/**\n * Generate connection URL for PostgreSQL.\n */\nexport function generatePostgresUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, database } = creds;\n\treturn `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;\n}\n\n/**\n * Generate connection URL for Redis.\n */\nexport function generateRedisUrl(creds: ServiceCredentials): string {\n\tconst { password, host, port } = creds;\n\treturn `redis://:${encodeURIComponent(password)}@${host}:${port}`;\n}\n\n/**\n * Generate endpoint URL for MinIO (S3-compatible).\n */\nexport function generateMinioEndpoint(creds: ServiceCredentials): string {\n\tconst { host, port } = creds;\n\treturn `http://${host}:${port}`;\n}\n\n/**\n * Generate a LocalStack-compatible access key ID.\n * Must start with 'LSIA' prefix and be at least 20 characters.\n * @see https://docs.localstack.cloud/aws/capabilities/config/credentials/\n */\nexport function generateLocalStackAccessKeyId(): string {\n\tconst suffix = randomBytes(12).toString('base64url').slice(0, 16);\n\treturn `LSIA${suffix}`;\n}\n\n/**\n * Generate connection URLs from service credentials.\n */\nexport function generateConnectionUrls(\n\tservices: StageSecrets['services'],\n): StageSecrets['urls'] {\n\tconst urls: StageSecrets['urls'] = {};\n\n\tif (services.postgres) {\n\t\turls.DATABASE_URL = generatePostgresUrl(services.postgres);\n\t}\n\n\tif (services.redis) {\n\t\turls.REDIS_URL = generateRedisUrl(services.redis);\n\t}\n\n\tif (services.minio) {\n\t\turls.STORAGE_ENDPOINT = generateMinioEndpoint(services.minio);\n\t}\n\n\tif (services.mailpit) {\n\t\turls.SMTP_HOST = services.mailpit.host;\n\t\turls.SMTP_PORT = String(services.mailpit.port);\n\t}\n\n\treturn urls;\n}\n\n/**\n * Generate LocalStack service credentials with LSIA-prefixed access key.\n */\nexport function generateLocalStackCredentials(): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS.localstack;\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t\taccessKeyId: generateLocalStackAccessKeyId(),\n\t};\n}\n\n/**\n * Create a new StageSecrets object with generated credentials.\n * @param stage - The deployment stage (e.g., 'development', 'production')\n * @param services - List of services to generate credentials for\n * @param options - Optional configuration\n * @param options.projectName - Project name used to derive the database name (e.g., 'myapp' → 'myapp_dev')\n */\nexport function createStageSecrets(\n\tstage: string,\n\tservices: SecretServiceName[],\n\toptions?: { projectName?: string },\n): StageSecrets {\n\tconst now = new Date().toISOString();\n\tconst serviceCredentials = generateServicesCredentials(services);\n\n\t// Override service defaults with project-derived names if provided\n\tif (options?.projectName) {\n\t\tif (serviceCredentials.postgres) {\n\t\t\tserviceCredentials.postgres.database = `${options.projectName.replace(/-/g, '_')}_dev`;\n\t\t}\n\t\tif (serviceCredentials.minio) {\n\t\t\tserviceCredentials.minio.bucket = options.projectName;\n\t\t\tserviceCredentials.minio.username = options.projectName;\n\t\t}\n\t}\n\n\tconst urls = generateConnectionUrls(serviceCredentials);\n\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: serviceCredentials,\n\t\turls,\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Rotate password for a specific service.\n */\nexport function rotateServicePassword(\n\tsecrets: StageSecrets,\n\tservice: SecretServiceName,\n): StageSecrets {\n\tconst currentCreds = secrets.services[service];\n\tif (!currentCreds) {\n\t\tthrow new Error(`Service \"${service}\" not configured in secrets`);\n\t}\n\n\tconst newCreds: ServiceCredentials = {\n\t\t...currentCreds,\n\t\tpassword: generateSecurePassword(),\n\t};\n\n\tconst newServices = {\n\t\t...secrets.services,\n\t\t[service]: newCreds,\n\t};\n\n\treturn {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tservices: newServices,\n\t\turls: generateConnectionUrls(newServices),\n\t};\n}\n","/**\n * What a migration file is called: a UTC timestamp, then a name.\n *\n * Kept apart from the commands so the scaffold can name the migration it\n * writes the same way `gkm migration` does, without loading a migrator.\n */\n\n/** UTC `YYYYMMDDHHmmss` — sorts as text, and reads as a date. */\nexport function stamp(now = new Date()): string {\n\treturn now\n\t\t.toISOString()\n\t\t.replace(/\\.\\d+Z$/, '')\n\t\t.replace(/\\D/g, '');\n}\n\n/** `Add workouts` → `add_workouts`: the part of a file name after its stamp. */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n\t\t.replace(/[^a-zA-Z0-9]+/g, '_')\n\t\t.replace(/^_+|_+$/g, '')\n\t\t.toLowerCase();\n}\n","/**\n * What a scaffolded project declares, and the keys that derive from it.\n *\n * One place, because three generators need the same three facts: the template\n * writes `new KyselyDatabase<Database, 'Acme'>('Acme')`, the test setup reads\n * `ACME_OWNER_URL` to migrate, and Studio reads `ACME_URL` to connect. Deriving\n * all of them from `@geekmidas/manifest`'s own helpers is what keeps a\n * scaffolded project agreeing with the runtime that discovers it — the same\n * reason the constructs own both faces at runtime.\n */\n\nimport { migrationFolder, provideKey, serviceKey } from '@geekmidas/manifest';\nimport { stamp } from '../migrate/names.js';\nimport type { GeneratedFile, RoutesStructure } from './templates/index.js';\n\n/** The glob every generated config points at. One glob, every kind. */\nexport const CONSTRUCTS_GLOB = './src/constructs/**/*.ts';\n\n/**\n * Where a workspace keeps its constructs: at the root, beside the apps that\n * share them, rather than inside any one of them.\n */\nexport const WORKSPACE_CONSTRUCTS_GLOB = './constructs/**/*.ts';\n\n/**\n * Where each routes structure puts an app's handlers, relative to the app.\n *\n * `.ts` only, never `.tsx`: a TanStack site keeps its own `src/routes/`, and\n * this glob must not import a frontend's route components.\n */\nexport function routesGlob(structure: RoutesStructure): string {\n\tswitch (structure) {\n\t\tcase 'centralized-endpoints':\n\t\t\treturn './src/endpoints/**/*.ts';\n\t\tcase 'centralized-routes':\n\t\t\treturn './src/routes/**/*.ts';\n\t\tcase 'domain-based':\n\t\t\treturn './src/**/routes/*.ts';\n\t}\n}\n\nexport interface ScaffoldedConstruct {\n\t/** The canonical id — what the construct is declared under. */\n\tid: string;\n\t/** The key it is reached under in a handler's service record. */\n\tservice: string;\n\t/** The runtime URL key the target publishes. */\n\turlKey: string;\n}\n\nexport interface ScaffoldedDatabase extends ScaffoldedConstruct {\n\t/** The DDL role's URL — what migrations connect as. */\n\townerUrlKey: string;\n}\n\n/**\n * Plain ids — `Database`, not `Shop`.\n *\n * The workspace `name` already scopes every physical name\n * (`production-shop-database`), so an id that carried the project too\n * would say it twice: `production-shop-shop-cache`. Within a\n * workspace the constructs are declared once, at its root, so there is no\n * second app's `Database` to collide with.\n */\nfunction scaffolded(id: string): ScaffoldedConstruct {\n\treturn { id, service: serviceKey(id), urlKey: provideKey(id, 'url') };\n}\n\n/** The database a project declares. */\nexport function databaseFor(): ScaffoldedDatabase {\n\treturn {\n\t\t...scaffolded('Database'),\n\t\townerUrlKey: provideKey('Database', 'ownerUrl'),\n\t};\n}\n\n/** The bucket a project declares. */\nexport const storageFor = (): ScaffoldedConstruct => scaffolded('Uploads');\n\n/** The mail sender a project declares. */\nexport const emailFor = (): ScaffoldedConstruct => scaffolded('Mail');\n\n/** The cache a project declares. */\nexport const cacheFor = (): ScaffoldedConstruct => scaffolded('Cache');\n\n/**\n * The files a project's declared database needs.\n *\n * Shared by every template, so a worker and an API declare the same database\n * the same way — and so the schema type, the migration, and the id the test\n * setup reads all come from one place.\n */\nexport function databaseFiles(): GeneratedFile[] {\n\tconst db = databaseFor();\n\n\treturn [\n\t\t{\n\t\t\tpath: 'src/constructs/database.ts',\n\t\t\tcontent: `import { KyselyDatabase } from '@geekmidas/constructs/database/kysely';\nimport { CamelCasePlugin, type Generated } from 'kysely';\n\n/**\n * Your database schema. Add tables here.\n *\n * camelCase, because of the plugin below: the columns are snake_case in\n * Postgres (\\`created_at\\`), and Kysely maps between the two.\n */\nexport interface Database {\n users: {\n id: Generated<string>;\n name: string;\n email: string;\n createdAt: Generated<Date>;\n };\n}\n\n/**\n * The app's database, declared once.\n *\n * The container, the database inside it, its roles and schema, and\n * \\`${db.urlKey}\\` all derive from this line — \\`gkm dev\\` reconciles them\n * before the server starts, which is why nothing lists \\`postgres\\` anywhere.\n *\n * Both type arguments or neither: TypeScript has no partial type-argument\n * inference, so passing only \\`Database\\` would leave the name at \\`string\\`\n * and widen the service key away from \\`${db.service}\\`.\n */\nexport const database = new KyselyDatabase<Database, '${db.id}'>('${db.id}', {\n // Yours to keep, change or remove. Every connection this construct opens —\n // every endpoint, the tests — uses it.\n plugins: [new CamelCasePlugin()],\n});\n`,\n\t\t},\n\t\tusersMigration(),\n\t];\n}\n\n/**\n * The table the scaffolded endpoints and factories expect.\n *\n * Its own function because a workspace's API needs it without the database\n * construct beside it — that one lives at the workspace root.\n */\nexport function usersMigration(): GeneratedFile {\n\treturn {\n\t\t// The table the scaffolded endpoints and factories expect, in the folder\n\t\t// named by the database construct. Applied by `gkm migrate`, and by the\n\t\t// test setup before any test runs.\n\t\tpath: `${migrationFolder(databaseFor().id)}/${stamp()}_create_users.ts`,\n\t\tcontent: `import type { Kysely } from 'kysely';\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n await db.schema\n .createTable('users')\n .addColumn('id', 'uuid', (col) =>\n col.primaryKey().defaultTo(db.fn('gen_random_uuid')),\n )\n .addColumn('name', 'varchar(255)', (col) => col.notNull())\n .addColumn('email', 'varchar(255)', (col) => col.notNull().unique())\n .addColumn('created_at', 'timestamptz', (col) =>\n col.notNull().defaultTo(db.fn('now')),\n )\n .execute();\n\n await db.schema\n .createIndex('users_email_idx')\n .on('users')\n .column('email')\n .execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n await db.schema.dropTable('users').execute();\n}\n`,\n\t};\n}\n\n/**\n * What a workspace's `constructs` glob reaches: the root constructs, and the\n * handlers of every app laid out the way `init` was told.\n *\n * Every app in `appsDir` (`apps/*`) rather than the API's own directory.\n * Endpoints are split by the surface they were built from, so naming one app\n * here would only decide which apps' endpoints are silently never loaded.\n */\nexport function workspaceConstructsGlobs(\n\tstructure: RoutesStructure,\n\tappsDir: string,\n): string[] {\n\treturn [\n\t\tWORKSPACE_CONSTRUCTS_GLOB,\n\t\t`./${appsDir}/*/${routesGlob(structure).replace(/^\\.\\//, '')}`,\n\t];\n}\n","import { CONSTRUCTS_GLOB, WORKSPACE_CONSTRUCTS_GLOB } from '../constructs.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * `AGENTS.md` and `CLAUDE.md` for a scaffolded project.\n *\n * A generated project is the first thing an agent sees, and without this it\n * sees only the output: a `gkm.config.ts` naming three keys, a `constructs/`\n * directory, and a build step that reads both. None of that says what the\n * shape *is*, so an agent reconstructs it from the framework it recognises —\n * and writes an Express app beside a `RestApi`, or restates in config what a\n * construct already declared, which is the exact mistake v10 exists to make\n * impossible.\n *\n * Instructions live in `AGENTS.md` because that is the file every tool reads.\n * `CLAUDE.md` imports it rather than copying it: two files saying the same\n * thing is two files to keep in step, and the copy that drifts is always the\n * one nobody opened.\n *\n * Content is derived from the same `TemplateOptions` the rest of the scaffold\n * is built from, so a project with no database gets no database section, and a\n * worker gets no endpoint guide. A guide that documents what was not generated\n * teaches the reader to distrust it.\n */\nexport function generateAgentFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\treturn [\n\t\t{ path: 'AGENTS.md', content: agentsContent(options, template) },\n\t\t{ path: 'CLAUDE.md', content: claudeContent() },\n\t];\n}\n\n/**\n * The import.\n *\n * `@AGENTS.md` rather than a link: Claude Code loads an `@` import into context\n * with the file that names it, and follows no links. A link left the\n * conventions one step away from an agent that never took it — it read the\n * pointer and nothing it pointed at.\n *\n * Deliberately not a summary — a summary is a second copy of the conventions\n * that ages independently of the first.\n */\nfunction claudeContent(): string {\n\treturn `# CLAUDE.md\n\n@AGENTS.md\n\nThe conventions for this project live in \\`AGENTS.md\\`, imported above. It is\nthe single copy, kept that way on purpose: anything repeated here would be a\nsecond thing to keep in step, and the stale one is always the copy nobody\nopened.\n`;\n}\n\nfunction agentsContent(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): string {\n\tconst { name, monorepo, telescope, packageManager } = options;\n\tconst { database } = options.constructs;\n\t// A workspace keeps its constructs at the root, beside the apps that share\n\t// them; a single app keeps them under its own `src/`. Writing the wrong one\n\t// here would be the first thing a reader checked and the first thing that\n\t// taught them not to trust the rest.\n\tconst constructsGlob = monorepo ? WORKSPACE_CONSTRUCTS_GLOB : CONSTRUCTS_GLOB;\n\tconst isWorker = template.name === 'worker';\n\tconst isServerless = template.name === 'serverless';\n\tconst run = packageManager === 'npm' ? 'npx' : `${packageManager} exec`;\n\n\tconst sections: string[] = [];\n\n\tsections.push(`# Agent conventions — ${name}\n\nRules for anyone, human or agent, writing code in this project. Built with\n[\\`@geekmidas/toolbox\\`](https://github.com/geekmidas/toolbox).\n\nRead this before adding a file. Most of what follows exists because the obvious\napproach from another framework produces something that compiles, runs, and is\nwrong in a way nothing catches.`);\n\n\tsections.push(`## The one idea\n\n**Constructs declare; config does not restate.**\n\nA construct — a \\`RestApi\\`, a database, a bucket, a topic — is the single\ndeclaration of a thing. The build reads those declarations and derives\neverything downstream from them: which containers exist, which apps get built,\nwhat the OpenAPI spec says, which env vars a process needs.\n\n\\`gkm.config.ts\\` holds only what no construct can answer:\n\n\\`\\`\\`typescript\nexport default defineWorkspace({\n name: '${name}',\n stages: { local: 'dev', deployed: ['staging', 'prod'], protected: ['prod'] },\n constructs: '${constructsGlob}',\n secrets: { enabled: true },\n});\n\\`\\`\\`\n\nIf you find yourself adding a key to config that names something already\ndeclared in a construct — a path, a port, a route, a container — stop. That is\nthe drift this design removes. The second copy is the one that goes wrong.`);\n\n\tsections.push(`## Layout\n\n\\`\\`\\`\n${layoutBlock(options, template)}\n\\`\\`\\`\n\nHandlers are found by **one glob**, and what kind a file exports is decided by\nthe value it exports, not by the directory it sits in.`);\n\n\tsections.push(`## Commands\n\n\\`\\`\\`bash\n${run} gkm dev # dev server, hot reload, services up, secrets injected\n${run} gkm build # production build\n${run} gkm test # tests, with secrets injected\n${run} gkm exec -- <cmd> # run any command with secrets injected\n${run} gkm openapi # regenerate the OpenAPI spec\n\\`\\`\\`\n\nSecrets are encrypted at rest and injected at run time:\n\n\\`\\`\\`bash\n${run} gkm secrets:set DATABASE_URL postgres://...\n${run} gkm secrets:show\n\\`\\`\\`\n\n**Never run a tool that needs project env vars directly.** It will see an empty\nenvironment and fail in a way that looks like a config bug. Go through\n\\`gkm exec --\\`, which is what injects them.`);\n\n\tif (!isWorker) sections.push(endpointSection(options));\n\tif (isWorker || isServerless) sections.push(backgroundSection(template));\n\tif (database)\n\t\tsections.push(databaseSection(), migrationsSection(), queriesSection());\n\n\tsections.push(`## Environment\n\nEnvironment is parsed once, through \\`envkit\\`, and never read from\n\\`process.env\\` directly:\n\n\\`\\`\\`typescript\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { Credentials } from '@geekmidas/envkit/credentials';\n\nexport const envParser = new EnvironmentParser({\n ...process.env,\n ...Credentials,\n});\n\nexport const config = envParser\n .create((get) => ({\n port: get('PORT').string().transform(Number).default(3000),\n }))\n .parse();\n\\`\\`\\`\n\n\\`Credentials\\` is what \\`gkm dev\\` and \\`gkm exec\\` inject. A bare\n\\`process.env.FOO\\` bypasses both the decryption and the validation, so it reads\nas \\`undefined\\` in exactly the environments that matter.`);\n\n\tsections.push(conventionsSection());\n\tsections.push(testingSection(database));\n\n\tif (telescope || database) {\n\t\tconst tools = [\n\t\t\ttelescope &&\n\t\t\t\t'**Telescope** — requests, exceptions and logs as JSON at `/__telescope/api`',\n\t\t\tdatabase &&\n\t\t\t\t'**Database API** — `gkm dev` serves the declared database, read-only, as JSON at `/__gkm/db`',\n\t\t].filter(Boolean);\n\n\t\tsections.push(`## Dev tools\n\n${tools.map((t) => `- ${t}`).join('\\n')}\n\nDerived from declared constructs and served only by \\`gkm dev\\`: nothing to wire up by hand, and no UI — JSON for whatever tool you point at it.`);\n\t}\n\n\tsections.push(`## Before you say it works\n\n\\`\\`\\`bash\n${run} gkm build\n\\`\\`\\`\n\nA build is the only thing that proves the manifest still resolves. Code that\ntypechecks can still declare two constructs with one id, or a handler no glob\nreaches — and neither shows up until something reads the graph.`);\n\n\treturn `${sections.join('\\n\\n')}\\n`;\n}\n\nfunction layoutBlock(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): string {\n\tconst { monorepo, apiPath } = options;\n\tconst { database } = options.constructs;\n\tconst isWorker = template.name === 'worker';\n\n\tif (monorepo) {\n\t\treturn `constructs/ # every construct: the surface, the database, topics\n${database ? 'db/<construct>/ # migrations/ and seeds/, one folder per database construct\\n' : ''}${apiPath}/ # the API app\ngkm.config.ts # name, constructs glob, secrets`;\n\t}\n\n\tconst lines = [\n\t\t'src/constructs/ # the surface, and anything it declares',\n\t\t'src/config/ # env parser, logger',\n\t];\n\n\tif (!isWorker) lines.push('src/endpoints/ # HTTP handlers');\n\tif (isWorker) {\n\t\tlines.push('src/crons/ # scheduled work');\n\t\tlines.push('src/subscribers/ # topic consumers');\n\t}\n\tif (database)\n\t\tlines.push(\n\t\t\t'db/<construct>/ # migrations/ and seeds/, one folder per database construct',\n\t\t);\n\n\tlines.push('gkm.config.ts # name, constructs glob, secrets');\n\n\treturn lines.join('\\n');\n}\n\nfunction endpointSection(options: TemplateOptions): string {\n\tconst { database } = options.constructs;\n\n\treturn `## Adding an endpoint\n\nAn endpoint is built **from the surface that serves it**. That is where its\nlogger, environment parser and authorizers come from, so none of them is passed\nper endpoint:\n\n\\`\\`\\`typescript\nimport { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const createUser = router\n .post('/users')\n .body(z.object({ name: z.string(), email: z.email() }))\n .output(z.object({ id: z.uuid() }))\n .handle(async ({ body, logger${database ? ', db' : ''} }) => {\n logger.info({ name: body.name }, 'creating user');\n${\n\tdatabase\n\t\t? ` const user = await db\n .insertInto('users')\n .values({ name: body.name, email: body.email })\n .returningAll()\n .executeTakeFirstOrThrow();\n\n return { id: user.id };`\n\t\t: ` return { id: crypto.randomUUID() };`\n}\n });\n\\`\\`\\`\n\n**Export it.** An endpoint that is never exported is never found — the glob\nloads the module and filters by value, so a handler assigned to a local\n\\`const\\` simply does not exist as far as the build is concerned.\n\n**Do not write an HTTP server.** No \\`express()\\`, no \\`new Hono()\\`, no\n\\`app.listen\\`. The entry is generated from the surface; a hand-written server\nbeside it is a second app that shadows the real one.\n\n### Branching the factory\n\nShare what a *group* of endpoints needs by branching once, in\n\\`src/router.ts\\`. A branch starts from the surface itself — there is no\nfactory object to reach through first:\n\n\\`\\`\\`typescript\nexport const router = api${database ? '.database(database)' : ''};\nexport const sessionRouter = router.session(/* … */);\n\\`\\`\\`\n\nA branch is a new factory; the surface is untouched, so a route built straight\nfrom \\`api\\` gets none of what the branch added. What one endpoint alone needs —\na bucket, a cache, another construct — goes on that endpoint with\n\\`.dependsOn([...])\\`, and arrives in \\`services\\`.\n\nBranch for a group, never for a single endpoint — a one-endpoint branch is\nindirection with nothing on the other side of it.`;\n}\n\nfunction backgroundSection(template: TemplateConfig): string {\n\tconst isWorker = template.name === 'worker';\n\n\treturn `## Background work\n\nCrons, subscribers and functions are declared the same way endpoints are: as\nexported values the build discovers.\n\n\\`\\`\\`typescript\n// a scheduled job, built from the worker that runs it\nimport { worker } from '../constructs/worker.ts';\n\nexport const cleanup = worker\n .cron('rate(1 day)')\n .handle(async ({ logger }) => {\n logger.info('cleaning up');\n });\n\\`\\`\\`\n\n\\`\\`\\`typescript\n// a topic subscriber\nimport { userEvents } from '../constructs/topics.ts';\nimport { worker } from '../constructs/worker.ts';\n\nexport const onUserCreated = worker\n .topic(userEvents)\n .subscribe(['user.created'])\n .handle(async ({ events, logger }) => {\n logger.info({ count: events.length }, 'handling user events');\n });\n\\`\\`\\`\n\nHandlers receive a **batch**, not one event. Both transports deliver in\nbatches, so a per-event round trip is a round trip per event for no reason.\n\n${\n\tisWorker\n\t\t? `This project is background work and nothing else — there is no HTTP surface\nto add routes to.`\n\t\t: `Declaring a topic is what makes the broker exist. Nothing lists it in config.`\n}`;\n}\n\nfunction databaseSection(): string {\n\treturn `## Database\n\nThe database is a **construct**, not a hand-rolled service. Declaring it is what\nmakes a Postgres exist locally and a database exist on deploy — nothing names\n\\`postgres\\` in config.\n\nThe router in \\`src/router.ts\\` names it — \\`api.database(database)\\` — and\nevery endpoint built from that router gets it as \\`db\\`, typed by the\nconstruct's schema:\n\n\\`\\`\\`typescript\nexport const listUsers = router\n .get('/users')\n .output(z.array(z.object({ id: z.uuid() })))\n .handle(async ({ db }) => {\n return db.selectFrom('users').selectAll().execute();\n });\n\\`\\`\\`\n\nAn endpoint that needs a different database names it itself, and gets that\none as \\`db\\` instead — the router's is unchanged for every other route:\n\n\\`\\`\\`typescript\nexport const monthly = router\n .get('/reports/monthly')\n .database(reports)\n .handle(async ({ db }) => db.selectFrom('totals').selectAll().execute());\n\\`\\`\\`\n\nQueries go through Kysely. Never open your own connection pool — the one the\nconstruct provides is the one that gets credentials, pooling and shutdown.`;\n}\n\nfunction migrationsSection(): string {\n\treturn `## Migrations and seeds\n\nEach database construct has its own folder, named after the construct:\n\\`Database\\` is \\`db/database/\\`, a tenant \\`AuthDatabase\\` is\n\\`db/auth-database/\\`. It holds two folders and nothing else:\n\n\\`\\`\\`\ndb/database/\n migrations/ # the schema's history, applied once each\n seeds/ # the reference data the app needs, run on every pass\n\\`\\`\\`\n\nEach construct keeps its own history, in its own schema, and is migrated and\nseeded as its own **owner** role — the role a handler runs as cannot create a\ntable.\n\n\\`\\`\\`bash\ngkm migration database add_workouts # db/database/migrations/20260930143012_add_workouts.ts\ngkm migration auth # Better Auth's schema change, as SQL\ngkm migrate # apply every construct's migrations, parents first\ngkm migrate database # apply one construct's\ngkm seed # migrate, then run every seed\ngkm dev --migrate # migrate before the apps start\ngkm dev --seed # migrate and seed before the apps start\n\\`\\`\\`\n\n- Migrations are \\`<UTC timestamp>_<name>.ts\\` exporting \\`up\\` (and\n \\`down\\`), or \\`.sql\\`, which runs whole. Never rename or edit one that has\n been applied — it is recorded by name. Change the schema with a new\n migration.\n- Write migrations with \\`Kysely<unknown>\\` and snake_case names: they are the\n SQL, and the camelCase plugin is the app's, not theirs.\n- \\`gkm migration auth\\` compares Better Auth's schema to its tenant and writes\n only the difference. Run it after adding a Better Auth plugin, and commit the\n file.\n- Seeds always run after migrations, never instead of them. Each is a\n \\`.ts\\` exporting \\`seed(db, { stage })\\`, or \\`.sql\\`, run in name\n order, in a transaction of its own.\n- **Seeds run on every stage, production included.** Write them to be safe\n there. A seed that belongs only somewhere checks the stage it is handed:\n \\`if (stage === 'production') return;\\`. A \\`.sql\\` seed has no stage, so\n it must be right everywhere.\n- Tests migrate and seed themselves: the root vitest config's\n \\`globalSetup: ['@geekmidas/cli/vitest']\\` does both for the test stage\n before any test runs. \\`gkm dev\\` without a flag only reports what is\n pending.\n- A deploy migrates before the new version goes live, so the old version runs\n against the new schema until it is replaced. Keep each migration compatible\n with the code before it: add a column in one release, stop using the old one,\n drop it in a later release.\n\n**Migrations hold schema, never data.** Tables, columns, constraints, indexes.\nNo inserts, updates or deletes against the application's rows.\n\n- **Reference data is a seed.** A permission catalogue, the roles and what\n they grant, a list of statuses — rows the app needs in order to run — are\n written by a seed in \\`db/<construct>/seeds/\\`, never by a migration.\n- **A seed is an upsert, run every time.** There is no history: every seed\n runs on every \\`gkm seed\\`, so changing what it writes and running it again\n is how the change is applied. Write \\`onConflict(…).doUpdateSet(…)\\` (or\n \\`doNothing()\\`), never a bare insert.\n- **Define it once, typed, where every app can import it.** A catalogue\n belongs in code, declared \\`as const\\` so its keys are a union type, and the\n seed writes the table from that constant — so the two cannot drift, and no\n test is needed to keep them in step. The API's guards, the web app's gates\n and a mobile app's gates all name the same keys, and a typo — or a removed\n permission still checked somewhere — fails to compile instead of failing\n closed at runtime.\n- **Sample data is factories'.** Demo users, a tournament for a test — those\n come from test factories, never a seed and never a migration.\n- **A backfill is the one data change a migration makes.** When a schema\n change needs existing rows transformed — a new non-null column filled from\n an old one — do it in the same migration, keyed on the rows it transforms.\n It never inserts rows that were not there.`;\n}\n\nfunction queriesSection(): string {\n\treturn `## Writing queries and relations\n\n**Names: snake_case in Postgres, camelCase in TypeScript.** Kysely's\n\\`CamelCasePlugin\\` does the mapping, and it is set where you can see it — on\nthe database construct in \\`constructs/database.ts\\`:\n\n\\`\\`\\`typescript\nexport const database = new KyselyDatabase<Database, 'Database'>('Database', {\n plugins: [new CamelCasePlugin()],\n});\n\\`\\`\\`\n\nIt is the project's plugin, not the toolbox's: keep it, change it, or remove it,\nbut do it there. It applies to every connection the construct opens: every\nendpoint, and the tests, which connect through the construct.\n\n- The \\`Database\\` interface is camelCase: \\`userId\\`, \\`createdAt\\`.\n- Migrations are the SQL, so they spell columns in snake_case.\n- A raw \\`sql\\` fragment is not rewritten. Refer to columns with\n \\`sql.ref('users.createdAt')\\` or \\`eb.ref(…)\\`, never inside the string.\n- A schema tenant takes its own options. Better Auth's tenant gets no plugin —\n its tables are its own.\n\n**Types.** \\`Generated<T>\\` for every column the database fills in (ids,\ndefaults, timestamps). Derive row types with \\`Selectable<Database['users']>\\`,\n\\`Insertable<…>\\` and \\`Updateable<…>\\` rather than writing them again.\n\n**Relations are foreign keys.** Every \\`*_id\\` column references its parent,\nwith its delete rule written out:\n\n\\`\\`\\`typescript\n.addColumn('user_id', 'uuid', (col) =>\n col.notNull().references('users.id').onDelete('cascade'),\n)\n\\`\\`\\`\n\n- \\`restrict\\` by default.\n- \\`cascade\\` only for rows that belong to the parent — a user's notifications.\n- \\`set null\\` for an optional link, on a nullable column.\n- Index every foreign key column. Postgres does not do it for you.\n\n**Reading related rows: one query, nested.** \\`jsonArrayFrom\\` and\n\\`jsonObjectFrom\\` from \\`kysely/helpers/postgres\\` return children already in\nthe shape of the response:\n\n\\`\\`\\`typescript\nimport { jsonArrayFrom } from 'kysely/helpers/postgres';\n\nconst user = await db\n .selectFrom('users')\n .select((eb) => [\n 'users.id',\n 'users.name',\n jsonArrayFrom(\n eb\n .selectFrom('notifications')\n .select(['notifications.id', 'notifications.body', 'notifications.createdAt'])\n .whereRef('notifications.userId', '=', 'users.id')\n .orderBy('notifications.createdAt', 'desc'),\n ).as('notifications'),\n ])\n .where('users.id', '=', id)\n .executeTakeFirstOrThrow();\n\\`\\`\\`\n\n- Never query once per row in a loop.\n- Use joins to filter, or for a flat result — not to build nested ones by hand.\n- Qualify columns (\\`users.id\\`) once a query touches more than one table.\n- Select the columns the response needs. \\`selectAll()\\` only returns a whole\n row.\n- Nested rows come back as JSON: a timestamp inside \\`jsonArrayFrom\\` is a\n string, not a \\`Date\\`. Say so in the output schema (\\`z.coerce.date()\\`).\n\n**Writes that touch several tables run in one transaction.** Use\n\\`withTransaction(db, async (trx) => …)\\` from \\`@geekmidas/db/kysely\\`: it joins\nthe transaction \\`db\\` already is — an endpoint with an auditor, a test —\ninstead of opening a second one.\n\n**Lists paginate by cursor**, with \\`paginatedSearch\\` from\n\\`@geekmidas/db/kysely/pagination\\`, not by offset.`;\n}\n\nfunction conventionsSection(): string {\n\treturn `## Conventions\n\n**Zod formats are top-level schemas.**\n\n\\`\\`\\`typescript\n// yes\nz.email()\nz.url()\nz.uuid()\n\n// no\nz.string().email()\nz.string().url()\n\\`\\`\\`\n\nZod 4 made each format a schema in its own right. The chained form still runs,\nbut it types as a \\`ZodString\\` carrying a check, so it cannot be composed or\nnarrowed — and it emits different JSON Schema, which means a published API\ncontract would depend on which spelling someone reached for.\n\n\\`envkit\\` is not affected: \\`get('ADMIN_EMAIL').string().email()\\` is its own\nbuilder, not Zod's. Leave it alone.\n\n**Style.** Two-space indent, single quotes, semicolons, trailing commas, 80\ncolumns. \\`import type\\` for type-only imports. Run the formatter rather than\nmatching it by hand.\n\n**Construct ids are unique.** Two constructs sharing an id fails discovery for\nthe whole project, not just the second one.`;\n}\n\nfunction testingSection(database: boolean): string {\n\treturn `## Testing\n\n**Integration over unit.** Prefer the real dependency to a mock — a real\ndatabase, a real cache. Mocks are for things you genuinely cannot run:\nthe filesystem, the clock, external HTTP (use MSW for that).\n\n**Test behaviour, not implementation.** Assert what the code did, not which\nfunctions it called on the way.\n\n\\`\\`\\`bash\n${database ? 'gkm test # starts services, injects secrets, then runs vitest' : 'gkm test'}\n\\`\\`\\`\n\nRun tests through \\`gkm test\\`, not \\`vitest\\` directly${\n\t\tdatabase\n\t\t\t? ' — it is what starts the database and injects the secrets the suite needs'\n\t\t\t: ''\n\t}.${\n\t\tdatabase\n\t\t\t? `\n\n**Factories, one per database.** \\`test/factories/<construct>.ts\\` at the\nproject root — \\`database.ts\\` for \\`Database\\` — exports\n\\`createFactory(db)\\`. A feature test gets each by service name, on that\ntest's transaction — the one \\`db.get\\` returns and its endpoints use — so\nask for it rather than importing and building one. Sign in the way a person\ndoes, through \\`browser.signIn\\`:\n\n\\`\\`\\`typescript\nit('reads a user', async ({ browser, db, factories }) => {\n const factory = await factories.get('database');\n const ada = await factory.insert('users', { email: 'ada@example.com' });\n\n await browser.signIn(ada.email);\n // … act through browser.api …\n\n const app = await db.get('database');\n // … assert on what was written …\n});\n\\`\\`\\``\n\t\t\t: ''\n\t}`;\n}\n","/**\n * Every third-party range `gkm init` writes, in one place.\n *\n * Templates used to pin their own copies, and those drifted: below the peer\n * ranges the `@geekmidas` packages declare (`kysely ~0.28` against a `~0.29.6`\n * peer is two copies of Kysely, and a `Kysely<DB>` from one is not assignable\n * to the other's), and below what the rest of the scaffold assumed (`turbo\n * ~2.3.0` ignores `$TURBO_ROOT$`, which the root `turbo.json` relies on). No\n * generator writes a version literal; a scan test holds them to that.\n *\n * Hand-maintained, unlike `versions.ts`, which `sync-versions` rewrites whole.\n * Current as of 2026-09-27, inside every `@geekmidas` peer range.\n */\nexport const DEPENDENCY_VERSIONS = {\n\t// Server\n\t'better-auth': '~1.7.6',\n\thono: '~4.13.9',\n\t// 1.x: 2.x changes the server entry this scaffold writes.\n\t'@hono/node-server': '~1.19.17',\n\tkysely: '~0.29.6',\n\tpg: '~8.23.0',\n\tpino: '~10.3.1',\n\tzod: '~4.6.5',\n\t// `@geekmidas/cloud`'s peer floor.\n\tsst: '~4.17.1',\n\n\t// Frontend\n\tnext: '~16.3.6',\n\treact: '~19.3.0',\n\t'react-dom': '~19.3.0',\n\t'@tanstack/react-query': '~5.104.0',\n\t'@tanstack/react-router': '~1.170.40',\n\t'@tanstack/react-start': '~1.168.59',\n\t'@tanstack/router-plugin': '~1.168.41',\n\ttailwindcss: '~4.3.3',\n\t'@tailwindcss/postcss': '~4.3.3',\n\t'@tailwindcss/vite': '~4.3.3',\n\t'@radix-ui/react-dialog': '~1.1.23',\n\t'@radix-ui/react-label': '~2.1.15',\n\t'@radix-ui/react-separator': '~1.1.15',\n\t'@radix-ui/react-slot': '~1.3.3',\n\t'@radix-ui/react-tabs': '~1.1.21',\n\t'@radix-ui/react-tooltip': '~1.2.16',\n\t'class-variance-authority': '~0.7.1',\n\tclsx: '~2.1.1',\n\t'lucide-react': '~1.48.0',\n\t'tailwind-merge': '~3.7.0',\n\n\t// Tooling\n\t'@biomejs/biome': '~2.5.14',\n\t// What `@geekmidas/testkit` itself depends on, so factories share one copy.\n\t'@faker-js/faker': '~10.6.0',\n\t// 2.4+ is what expands `$TURBO_ROOT$` in the root turbo.json.\n\tturbo: '~2.11.4',\n\n\t// Types. Node's follow the oldest runtime the packages support (22), so\n\t// nothing typechecks against an API that is not there.\n\t'@types/node': '~22.20.4',\n\t'@types/pg': '~8.23.1',\n\t'@types/react': '~19.3.0',\n\t'@types/react-dom': '~19.3.0',\n\t'@types/aws-lambda': '~8.10.163',\n} as const;\n\n/**\n * The build and test toolchain, at the versions the repository itself builds\n * and tests with (scripts/dependency-versions.json), so a scaffold compiles\n * with the compiler its own `@geekmidas` packages were checked against.\n */\nexport const TOOLCHAIN_VERSIONS = {\n\ttypescript: '~7.0.2',\n\ttsx: '~4.23.15',\n\tesbuild: '~0.28.2',\n\t// `@geekmidas/testkit` and `@geekmidas/db` declare this as their peer.\n\tvitest: '~5.0.2',\n\tvite: '~8.3.1',\n\t'@vitejs/plugin-react': '^6.1.1',\n} as const;\n\n/**\n * The Expo app's packages, which track an Expo SDK release (57) rather than\n * their own latest: SDK 57 is tested against exactly these, React Native and\n * React included, so they move when the SDK does.\n */\nexport const EXPO_VERSIONS = {\n\texpo: '~57.0.26',\n\t'expo-constants': '~57.0.20',\n\t'expo-dev-client': '~57.0.19',\n\t'expo-device': '~57.0.2',\n\t'expo-linking': '~57.0.11',\n\t'expo-router': '~57.0.24',\n\t'expo-splash-screen': '~57.0.9',\n\t'expo-status-bar': '~57.0.1',\n\t'expo-secure-store': '~57.0.4',\n\treact: '19.2.3',\n\t'react-dom': '19.2.3',\n\t'react-native': '0.86.3',\n\t'react-native-gesture-handler': '~2.32.0',\n\t'react-native-reanimated': '4.5.1',\n\t// Reanimated 4 runs its worklets on this, pinned by the SDK beside it.\n\t'react-native-worklets': '0.10.1',\n\t'react-native-safe-area-context': '~5.7.0',\n\t'react-native-screens': '~4.26.0',\n\t'react-native-web': '~0.21.0',\n\t'@react-navigation/native': '^7.1.0',\n\t'@babel/core': '^7.25.0',\n\t'@types/react': '~19.2.2',\n\tnativewind: '~4.2.0',\n\t// NativeWind 4 is built on Tailwind 3.\n\ttailwindcss: '~3.4.0',\n} as const;\n\n/**\n * The pnpm a pnpm scaffold runs under, through \\`packageManager\\`.\n *\n * Pinned in every layout. Without it Corepack takes the newest pnpm, and 11\n * fails the first install on dependencies with build scripts (esbuild) until\n * they are approved — a single-app scaffold that did not pin it could not\n * install at all.\n */\nexport const PNPM_VERSION = 'pnpm@10.13.1';\n\n/** The Biome config schema matching the Biome the scaffold installs. */\nexport const BIOME_SCHEMA = `https://biomejs.dev/schemas/${DEPENDENCY_VERSIONS['@biomejs/biome'].replace(/^[~^]/, '')}/schema.json`;\n","import { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n// Load package.json - handles both bundled (flat dist/) and source (nested src/init/)\nfunction loadPackageJson(): { version: string } {\n\ttry {\n\t\t// Try flat dist path first (../package.json from dist/)\n\t\treturn require('../package.json');\n\t} catch {\n\t\t// Fall back to nested source path (../../package.json from src/init/)\n\t\treturn require('../../package.json');\n\t}\n}\n\nconst pkg = loadPackageJson();\n\n/**\n * CLI version resolved from package.json at runtime\n */\nexport const CLI_VERSION = `~${pkg.version}`;\n\n/**\n * Package versions for @geekmidas packages\n *\n * AUTO-GENERATED (except CLI) - Do not edit manually\n * Run: pnpm --filter @geekmidas/cli sync-versions\n */\nexport const GEEKMIDAS_VERSIONS = {\n\t'@geekmidas/audit': '~10.0.0-alpha.78',\n\t'@geekmidas/auth': '~10.0.0-alpha.78',\n\t'@geekmidas/cache': '~10.0.0-alpha.78',\n\t'@geekmidas/client': '~10.0.0-alpha.78',\n\t'@geekmidas/cloud': '~10.0.0-alpha.78',\n\t'@geekmidas/constructs': '~10.0.0-alpha.78',\n\t'@geekmidas/db': '~10.0.0-alpha.78',\n\t'@geekmidas/emailkit': '~10.0.0-alpha.78',\n\t'@geekmidas/envkit': '~10.0.0-alpha.78',\n\t'@geekmidas/errors': '~10.0.0-alpha.78',\n\t'@geekmidas/events': '~10.0.0-alpha.78',\n\t'@geekmidas/logger': '~10.0.0-alpha.78',\n\t'@geekmidas/manifest': '~10.0.0-alpha.78',\n\t'@geekmidas/rate-limit': '~10.0.0-alpha.78',\n\t'@geekmidas/schema': '~10.0.0-alpha.78',\n\t'@geekmidas/services': '~10.0.0-alpha.78',\n\t'@geekmidas/storage': '~10.0.0-alpha.78',\n\t'@geekmidas/telescope': '~10.0.0-alpha.78',\n\t'@geekmidas/testkit': '~10.0.0-alpha.78',\n\t'@geekmidas/cli': CLI_VERSION,\n} as const;\n\nexport type GeekmidasPackage = keyof typeof GEEKMIDAS_VERSIONS;\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate auth app files for fullstack template\n * Uses better-auth with magic link authentication\n */\nexport function generateAuthAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/auth`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\t// package.json for auth app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\t// Both halves are `gkm`'s: the entry is generated from the `BetterAuth`\n\t\t// construct, so there is no source here for `tsc` to build or check.\n\t\tscripts: {\n\t\t\tdev: 'gkm dev',\n\t\t\tbuild: 'gkm build',\n\t\t},\n\t\t// What the generated entry and the construct behind it load. The\n\t\t// container is built from this package, so it names them itself rather\n\t\t// than leaning on the workspace root's.\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],\n\t\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t\t'@geekmidas/db': GEEKMIDAS_VERSIONS['@geekmidas/db'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\t\tkysely: DEPENDENCY_VERSIONS.kysely,\n\t\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/pg': DEPENDENCY_VERSIONS['@types/pg'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// tsconfig.json for auth app\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[`@${options.name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// .gitignore for auth app\n\tconst gitignore = `node_modules/\ndist/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/auth/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t// No `src/`. The auth server used to be a hand-written Hono app here — a\n\t\t// `src/index.ts` that read PORT, split `BETTER_AUTH_TRUSTED_ORIGINS` into\n\t\t// a CORS list, and mounted `/api/auth/*` itself, beside a `src/auth.ts`\n\t\t// that built the Better Auth instance and a `src/config/env.ts` to feed\n\t\t// it. Every line of that is the `BetterAuth` construct's now: the origins\n\t\t// come from whatever declared an edge to it, and the build generates the\n\t\t// entry, because the routes are a wildcard that no glob can find.\n\t\t//\n\t\t// What is left is the package the container is built from.\n\t\t{\n\t\t\tpath: 'apps/auth/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import type { StagesConfig } from '../../workspace/types.js';\n\n/** The `stages` block a generated gkm.config.ts declares, indented two spaces. */\nexport function stagesBlock(stages: StagesConfig): string {\n\tconst list = (names: readonly string[]) =>\n\t\t`[${names.map((name) => `'${name}'`).join(', ')}]`;\n\n\treturn `\n // Named by this project and read by every command: \\`gkm dev\\`, \\`exec\\` and\n // \\`test\\` run as \\`local\\`, and \\`gkm deploy --stage\\` accepts only \\`deployed\\`.\n stages: {\n local: '${stages.local}',\n deployed: ${list(stages.deployed)},${\n\t\t\tstages.protected?.length\n\t\t\t\t? `\n // Retained and protected on removal.\n protected: ${list(stages.protected)},`\n\t\t\t\t: ''\n\t\t}\n },`;\n}\n\n/**\n * The `STAGE` the scaffolded env config parses: one of the declared stages,\n * defaulting to the local one.\n */\nexport function stageEnv(stages: StagesConfig): string {\n\tconst names = [stages.local, ...stages.deployed]\n\t\t.map((name) => `'${name}'`)\n\t\t.join(', ');\n\n\treturn `get('STAGE').enum([${names}]).default('${stages.local}')`;\n}\n","import { CONSTRUCTS_GLOB, routesGlob } from '../constructs.js';\nimport { BIOME_SCHEMA } from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { stagesBlock } from './stages.js';\n\n/**\n * Vitest config for a database-enabled app.\n *\n * On its own, it is the root config and carries gkm's setup: the test stage\n * reconciled and every construct migrated, however the suite starts. In a\n * workspace the root config carries it instead — once, so no project filter\n * can skip it and nothing runs it twice.\n */\nconst vitestConfigFor = (\n\tmonorepo: boolean,\n) => `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n // Vite resolves tsconfig \\`paths\\` itself; no plugin needed.\n resolve: { tsconfigPaths: true },\n test: {\n environment: 'node',${\n\t\t\tmonorepo\n\t\t\t\t? ''\n\t\t\t\t: `\n // The test stage, reconciled and every database construct's migrations\n // applied, before any test runs — whether \\`gkm test\\` or plain\n // \\`vitest\\` started it.\n globalSetup: ['@geekmidas/cli/vitest'],`\n\t\t}\n },\n});\n`;\n\n/**\n * Generate configuration files (gkm.config.ts, tsconfig.json, biome.json, turbo.json)\n */\nexport function generateConfigFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { telescope, routesStructure } = options;\n\tconst isServerless = template.name === 'serverless';\n\tconst hasWorker = template.name === 'worker';\n\tconst isFullstack = options.template === 'fullstack';\n\n\tconst getRoutesGlob = () => routesGlob(routesStructure);\n\n\t// For fullstack template, generate workspace config at root\n\t// Single app config is still generated for non-fullstack monorepo setups\n\tif (isFullstack) {\n\t\t// Workspace config is generated in monorepo.ts for fullstack\n\t\treturn generateSingleAppConfigFiles(options, template, {\n\t\t\ttelescope,\n\t\t\troutesStructure,\n\t\t\tisServerless,\n\t\t\thasWorker,\n\t\t\tgetRoutesGlob,\n\t\t});\n\t}\n\n\t// Build gkm.config.ts for single-app\n\tlet gkmConfig = `import { defineConfig } from '@geekmidas/cli/config';\n\nexport default defineConfig({${stagesBlock(options.stages)}${\n\t\toptions.monorepo\n\t\t\t? ''\n\t\t\t: `\n // One glob, every kind. What reconcile reads to derive the containers this\n // app needs: a declared database is why a Postgres exists at all, so nothing\n // lists \\`postgres\\` anywhere.\n constructs: '${CONSTRUCTS_GLOB}',`\n\t}\n routes: '${getRoutesGlob()}',\n envParser: './src/config/env#envParser',\n logger: './src/config/logger#logger',`;\n\n\tif (isServerless || hasWorker) {\n\t\tgkmConfig += `\n functions: './src/functions/**/*.ts',`;\n\t}\n\n\tif (hasWorker) {\n\t\tgkmConfig += `\n crons: './src/crons/**/*.ts',\n subscribers: './src/subscribers/**/*.ts',`;\n\t}\n\n\tif (telescope) {\n\t\tgkmConfig += `\n telescope: {\n enabled: true,\n path: '/__telescope',\n },`;\n\t}\n\n\t// Always add openapi config: each surface's client is written to the\n\t// workspace root's `.gkm/client/`, imported as `@<name>/client/<surface>`\n\tgkmConfig += `\n openapi: {\n enabled: true,\n },`;\n\n\tgkmConfig += `\n});\n`;\n\n\t// Build tsconfig.json - extends root for monorepo, standalone for non-monorepo\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = options.monorepo\n\t\t? workspaceApiTsConfig(options.name)\n\t\t: {\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\ttarget: 'ES2022',\n\t\t\t\t\tmodule: 'NodeNext',\n\t\t\t\t\tmoduleResolution: 'NodeNext',\n\t\t\t\t\tlib: ['ES2022'],\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tesModuleInterop: true,\n\t\t\t\t\tskipLibCheck: true,\n\t\t\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\t\t\tresolveJsonModule: true,\n\t\t\t\t\tnoEmit: true,\n\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t// The monorepo and fullstack layouts already mapped this; a\n\t\t\t\t\t// single app did not, so every `~/…` import the templates write\n\t\t\t\t\t// — the api's `~/router.ts`, the worker's `~/constructs/worker.ts`\n\t\t\t\t\t// — resolved to nothing and the project failed on first build.\n\t\t\t\t\tpaths: {\n\t\t\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tinclude: ['src/**/*.ts'],\n\t\t\t\texclude: ['node_modules', 'dist'],\n\t\t\t};\n\n\t// Skip biome.json and turbo.json for monorepo (they're at root)\n\tif (options.monorepo) {\n\t\tconst files: GeneratedFile[] = [\n\t\t\t{\n\t\t\t\tpath: 'gkm.config.ts',\n\t\t\t\tcontent: gkmConfig,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: 'tsconfig.json',\n\t\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t\t},\n\t\t];\n\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'vitest.config.ts',\n\t\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t}\n\n\t// Build biome.json\n\tconst biomeConfig = {\n\t\t$schema: BIOME_SCHEMA,\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\t// Biome 2 moved import sorting into the assist, and `files.ignore` into\n\t\t// negated `includes`: the 1.x keys make it refuse the whole config.\n\t\tassist: { actions: { source: { organizeImports: 'on' } } },\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Tailwind v4's `@theme` and `@apply`, which the UI package's CSS uses.\n\t\tcss: { parser: { tailwindDirectives: true } },\n\t\tfiles: {\n\t\t\tincludes: [\n\t\t\t\t'**',\n\t\t\t\t'!**/node_modules',\n\t\t\t\t'!**/dist',\n\t\t\t\t'!**/.gkm',\n\t\t\t\t'!**/coverage',\n\t\t\t],\n\t\t},\n\t};\n\n\t// Build turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['dist/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: gkmConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.constructs.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * Helper to generate config files for API app in fullstack template\n * (workspace config is at root, so no gkm.config.ts for app)\n */\ninterface ConfigHelperOptions {\n\ttelescope: boolean;\n\troutesStructure: string;\n\tisServerless: boolean;\n\thasWorker: boolean;\n\tgetRoutesGlob: () => string;\n}\n\n/**\n * The tsconfig of an API inside a workspace.\n *\n * One definition for both ways of getting one — the fullstack template and\n * `--monorepo` — because the two copies had drifted: only one of them mapped\n * the root constructs, so in the other `@<name>/constructs/api.ts` fell through\n * to the `packages/` mapping and nothing could load the surface.\n */\nfunction workspaceApiTsConfig(name: string) {\n\treturn {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t// Before the wildcard below it: TypeScript takes the longest\n\t\t\t\t// matching prefix, so the constructs at the workspace root win\n\t\t\t\t// over `packages/constructs/src`, which is a different thing\n\t\t\t\t// with a colliding name.\n\t\t\t\t[`@${name}/constructs/*`]: ['../../constructs/*'],\n\t\t\t\t[`@${name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n}\n\nfunction generateSingleAppConfigFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n\t_helpers: ConfigHelperOptions,\n): GeneratedFile[] {\n\t// For fullstack, only generate tsconfig.json for the API app\n\t// The workspace gkm.config.ts is generated in monorepo.ts\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = workspaceApiTsConfig(options.name);\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.constructs.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigFor(Boolean(options.monorepo)),\n\t\t});\n\t}\n\n\treturn files;\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate environment-related files (.gitignore only).\n * Note: .env files are no longer generated. Use `gkm secrets:init` to initialize\n * encrypted secrets stored in `.gkm/secrets/{stage}.json` with keys stored at\n * `~/.gkm/keys/{namespace}/{project}/{stage}.key`.\n */\nexport function generateEnvFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tconst files: GeneratedFile[] = [];\n\n\t// Only add .gitignore for non-monorepo (monorepo has it at root)\n\tif (!options.monorepo) {\n\t\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Written by gkm from the constructs; your own docker-compose.yml is not\ndocker-compose.constructs.yml\n\n# Environment (legacy - use gkm secrets instead)\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n`;\n\t\tfiles.push({\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t});\n\t}\n\n\treturn files;\n}\n","/**\n * The GitHub workflows a scaffold ships with.\n *\n * - `ci.yml` — every pull request builds, lints, typechecks and tests.\n * - `release-drafter.yml` — merged pull requests accumulate in a draft\n * release, labelled from their titles.\n * - `deploy.yml` — when a deploy target was picked: a push to main deploys the\n * stages that are not protected, publishing the drafted release deploys the\n * protected ones.\n *\n * The deploy workflow names no stage. It reads `stages` from gkm.config.ts at\n * run time, so the config stays the one place stages are declared and a\n * workflow cannot fall out of step with it.\n */\n\nimport { projectKey } from '../../secrets/keystore.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/** How each package manager is set up, installs, and runs a script. */\nconst TOOLING = {\n\tpnpm: {\n\t\t// The version comes from \\`packageManager\\` in package.json, which only\n\t\t// the workspace scaffold pins; the action refuses both at once.\n\t\tsetup: ` - uses: pnpm/action-setup@v4\nPNPM_VERSION\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: pnpm\n`,\n\t\tinstall: 'pnpm install --frozen-lockfile',\n\t\trun: 'pnpm run',\n\t\texec: 'pnpm exec',\n\t},\n\tnpm: {\n\t\tsetup: ` - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: npm\n`,\n\t\tinstall: 'npm ci',\n\t\trun: 'npm run',\n\t\texec: 'npx --no-install',\n\t},\n\tyarn: {\n\t\tsetup: ` - run: corepack enable\n\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: yarn\n`,\n\t\tinstall: 'yarn install --immutable',\n\t\trun: 'yarn run',\n\t\texec: 'yarn',\n\t},\n\tbun: {\n\t\tsetup: ` - uses: oven-sh/setup-bun@v2\n`,\n\t\tinstall: 'bun install --frozen-lockfile',\n\t\trun: 'bun run',\n\t\texec: 'bunx',\n\t},\n} as const;\n\n/** The package manager's steps, with pnpm pinned where package.json does not. */\nfunction tooling(options: TemplateOptions) {\n\tconst pm = TOOLING[options.packageManager];\n\treturn {\n\t\t...pm,\n\t\tsetup: pm.setup.replace(\n\t\t\t'PNPM_VERSION\\n',\n\t\t\toptions.monorepo ? '' : ' with:\\n version: 10\\n',\n\t\t),\n\t};\n}\n\nfunction ci(options: TemplateOptions): string {\n\tconst pm = tooling(options);\n\n\treturn `name: CI\n\non:\n pull_request:\n branches: [main]\n\nconcurrency:\n group: \\${{ github.workflow }}-\\${{ github.ref }}\n cancel-in-progress: true\n\npermissions:\n contents: read\n\njobs:\n validate:\n name: Validate\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n\n - name: Build\n run: ${pm.run} build\n\n - name: Lint\n run: ${pm.run} lint\n\n - name: Typecheck\n run: ${pm.run} typecheck\n\n # \\`gkm test\\` starts the containers the declared constructs need (the\n # runner has Docker) and, with GKM_AUTO_SETUP, generates throwaway\n # secrets for the test stage — there is no key to share with CI.\n - name: Test\n timeout-minutes: 15\n run: ${pm.run} test:once\n env:\n CI: true\n GKM_AUTO_SETUP: 1\n`;\n}\n\nconst releaseDrafterWorkflow = `name: Release Drafter\n\non:\n push:\n branches: [main]\n pull_request:\n types: [opened, reopened, synchronize, edited]\n\npermissions:\n contents: read\n\njobs:\n draft:\n name: Update release draft\n runs-on: ubuntu-latest\n permissions:\n contents: write\n pull-requests: write\n steps:\n - uses: release-drafter/release-drafter@v6\n with:\n commitish: main\n env:\n GITHUB_TOKEN: \\${{ secrets.GITHUB_TOKEN }}\n`;\n\nfunction releaseDrafterConfig(options: TemplateOptions): string {\n\tconst mobile =\n\t\toptions.frontendFramework === 'expo'\n\t\t\t? ` - title: \"📱 Mobile\"\n labels: [mobile, ios, android]\n collapse-after: 10\n`\n\t\t\t: '';\n\n\treturn `name-template: \"v$RESOLVED_VERSION\"\ntag-template: \"v$RESOLVED_VERSION\"\n\ncategories:\n - title: \"✨ New Features\"\n labels: [feature, enhancement]\n collapse-after: 10\n - title: \"🐛 Bug Fixes\"\n labels: [bug, fix]\n collapse-after: 10\n${mobile} - title: \"🏗 Infrastructure\"\n labels: [infrastructure, ci]\n collapse-after: 10\n - title: \"📦 Dependencies\"\n labels: [dependencies]\n collapse-after: 5\n - title: \"🔒 Security\"\n labels: [security]\n - title: \"🧹 Maintenance\"\n labels: [chore, refactor]\n collapse-after: 5\n\nchange-template: \"- $TITLE @$AUTHOR (#$NUMBER)\"\nchange-title-escapes: '\\\\<*_&'\n\nversion-resolver:\n major:\n labels: [breaking-change, major]\n minor:\n labels: [feature, enhancement, minor]\n patch:\n labels: [bug, fix, chore, dependencies, patch]\n default: patch\n\n# Labelled from the conventional-commit prefix of the pull request title.\nautolabeler:\n - label: feature\n title: [\"/^feat/i\"]\n - label: bug\n title: [\"/^fix/i\"]\n - label: chore\n title: [\"/^chore/i\", \"/^refactor/i\"]\n - label: dependencies\n title: [\"/^deps/i\", \"/^chore\\\\\\\\(deps\\\\\\\\)/i\"]\n - label: ci\n title: [\"/^ci/i\"]\n - label: breaking-change\n title: [\"/^\\\\\\\\w+(\\\\\\\\(.+\\\\\\\\))?!:/\"]\n\ntemplate: |\n ## What's Changed\n\n $CHANGES\n\n **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION\n`;\n}\n\nfunction deploy(options: TemplateOptions): string {\n\tconst pm = tooling(options);\n\tconst sst = options.deployTarget === 'sst';\n\n\tconst credentials = sst\n\t\t? `\n # An IAM role GitHub assumes through OIDC — no long-lived AWS keys. Set\n # AWS_ROLE_ARN as a variable on each environment.\n - uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: \\${{ vars.AWS_ROLE_ARN }}\n aws-region: ${options.region}\n`\n\t\t: '';\n\n\t// A stage's secrets are read from its store by the deploy itself. SSM and\n\t// Secrets Manager need nothing but the role the job already assumed; the local file needs its\n\t// key, and the encrypted file itself, which a checkout of an ignored\n\t// `.gkm/` lacks.\n\t// Where the CLI looks for the stage's key: under the project's identity,\n\t// not under the checkout's folder name, which on a runner is the repo's.\n\tconst keyDir = `~/.gkm/keys/${projectKey({ name: options.name })}`;\n\tconst stageSecrets = sst\n\t\t? credentials\n\t\t: `\n # The stage's secrets are kept in the encrypted .gkm/secrets/<stage>.json,\n # and each environment holds its key as GKM_SECRETS_KEY. .gkm/ is\n # gitignored, so a checkout has the key but not the file: set\n # secrets.store in gkm.config.ts to a store CI can reach before deploying\n # from here.\n # Owner-only, as the CLI writes its own keys. The stage reaches the shell\n # as a variable, never pasted into the script: on a manual run it is\n # whatever was typed.\n - name: Stage secrets key\n run: |\n mkdir -p -m 700 ${keyDir}\n (umask 077 && printf '%s' \"$KEY\" > ${keyDir}/\"$STAGE\".key)\n env:\n KEY: \\${{ secrets.GKM_SECRETS_KEY }}\n STAGE: \\${{ matrix.stage }}\n`;\n\n\tconst deployEnv = sst\n\t\t? ''\n\t\t: `\n DOKPLOY_API_TOKEN: \\${{ secrets.DOKPLOY_API_TOKEN }}\n DOKPLOY_ENDPOINT: \\${{ vars.DOKPLOY_ENDPOINT }}`;\n\n\treturn `name: Deploy\n\n# Which stages exist, and which are protected, is read from \\`stages\\` in\n# gkm.config.ts — nothing here names one:\n#\n# push to main every deployed stage that is not protected\n# release published the protected stages (publish the drafted release)\n# run workflow the one stage you name\non:\n push:\n branches: [main]\n release:\n types: [published]\n workflow_dispatch:\n inputs:\n stage:\n description: A deployed stage from gkm.config.ts\n required: true\n\npermissions:\n contents: read\n id-token: write\n\njobs:\n stages:\n name: Pick stages\n runs-on: ubuntu-latest\n outputs:\n stages: \\${{ steps.pick.outputs.stages }}\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n\n - name: Read stages from gkm.config.ts\n id: pick\n run: |\n ${pm.exec} tsx -e \"\n import config from './gkm.config.ts';\n const { deployed, protected: kept = [] } = config.stages;\n const event = process.env.EVENT;\n if (event === 'workflow_dispatch' && !deployed.includes(process.env.STAGE)) {\n console.error('Not a deployed stage: ' + process.env.STAGE + ' (deployed: ' + deployed.join(', ') + ')');\n process.exit(1);\n }\n const stages =\n event === 'workflow_dispatch' ? [process.env.STAGE]\n : event === 'release' ? kept\n : deployed.filter((stage) => !kept.includes(stage));\n console.log('stages=' + JSON.stringify(stages));\n \" >> \"$GITHUB_OUTPUT\"\n env:\n EVENT: \\${{ github.event_name }}\n STAGE: \\${{ inputs.stage }}\n\n deploy:\n name: Deploy \\${{ matrix.stage }}\n needs: stages\n if: needs.stages.outputs.stages != '[]'\n runs-on: ubuntu-latest\n strategy:\n fail-fast: false\n matrix:\n stage: \\${{ fromJSON(needs.stages.outputs.stages) }}\n # One GitHub environment per stage: its secrets and variables, and any\n # approval rule you put on a protected one.\n environment: \\${{ matrix.stage }}\n concurrency:\n group: deploy-\\${{ matrix.stage }}\n cancel-in-progress: false\n steps:\n - uses: actions/checkout@v4\n\n${pm.setup}\n - name: Install\n run: ${pm.install}\n${stageSecrets}\n # Builds, releases and health-checks the stage through deploy.default\n # in gkm.config.ts, and fails the job if any of it fails.\n - name: Deploy\n run: ${pm.exec} gkm deploy --stage \"$STAGE\"\n env:\n STAGE: \\${{ matrix.stage }}${deployEnv}\n`;\n}\n\nexport function generateGithubFiles(options: TemplateOptions): GeneratedFile[] {\n\tconst files: GeneratedFile[] = [\n\t\t{ path: '.github/workflows/ci.yml', content: ci(options) },\n\t\t{\n\t\t\tpath: '.github/workflows/release-drafter.yml',\n\t\t\tcontent: releaseDrafterWorkflow,\n\t\t},\n\t\t{\n\t\t\tpath: '.github/release-drafter.yml',\n\t\t\tcontent: releaseDrafterConfig(options),\n\t\t},\n\t];\n\n\t// Only where a target was picked, and only for a workspace scaffold: the\n\t// one whose gkm.config.ts says where its stages deploy.\n\tif (options.monorepo && options.deployTarget !== 'none') {\n\t\tfiles.push({\n\t\t\tpath: '.github/workflows/deploy.yml',\n\t\t\tcontent: deploy(options),\n\t\t});\n\t}\n\n\treturn files;\n}\n","import { schemeBase } from '@geekmidas/manifest';\nimport {\n\tDEPENDENCY_VERSIONS,\n\tEXPO_VERSIONS,\n\tTOOLCHAIN_VERSIONS,\n} from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate an Expo mobile app for the fullstack template.\n *\n * Mirrors the structure of rezgo/apps/app: NativeWind for styling,\n * expo-router for navigation, better-auth + magic link, React Query\n * for data, all wired into the toolbox's typed API client.\n */\nexport function generateExpoAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/app`;\n\tconst modelsPackage = `@${options.name}/models`;\n\t// The slug is Expo's project name. The scheme — and the bundle id built on\n\t// it — is not written here: the \\`MobileApp\\` construct resolves it per\n\t// stage, and \\`app.config.ts\\` reads it from \\`APP_SCHEME\\`.\n\tconst slug = options.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\t// What the deployed auth server trusts: the same derivation, not a copy.\n\tconst scheme = schemeBase(options.name);\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tmain: 'expo-router/entry',\n\t\tprivate: true,\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- expo start -c',\n\t\t\tios: 'expo start --ios',\n\t\t\tandroid: 'expo start --android',\n\t\t\tweb: 'expo start --web',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@better-auth/expo': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@react-navigation/native': EXPO_VERSIONS['@react-navigation/native'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\texpo: EXPO_VERSIONS['expo'],\n\t\t\t'expo-constants': EXPO_VERSIONS['expo-constants'],\n\t\t\t'expo-dev-client': EXPO_VERSIONS['expo-dev-client'],\n\t\t\t'expo-device': EXPO_VERSIONS['expo-device'],\n\t\t\t'expo-linking': EXPO_VERSIONS['expo-linking'],\n\t\t\t'expo-router': EXPO_VERSIONS['expo-router'],\n\t\t\t'expo-secure-store': EXPO_VERSIONS['expo-secure-store'],\n\t\t\t'expo-splash-screen': EXPO_VERSIONS['expo-splash-screen'],\n\t\t\t'expo-status-bar': EXPO_VERSIONS['expo-status-bar'],\n\t\t\tnativewind: EXPO_VERSIONS['nativewind'],\n\t\t\treact: EXPO_VERSIONS['react'],\n\t\t\t'react-dom': EXPO_VERSIONS['react-dom'],\n\t\t\t'react-native': EXPO_VERSIONS['react-native'],\n\t\t\t'react-native-gesture-handler':\n\t\t\t\tEXPO_VERSIONS['react-native-gesture-handler'],\n\t\t\t'react-native-reanimated': EXPO_VERSIONS['react-native-reanimated'],\n\t\t\t'react-native-worklets': EXPO_VERSIONS['react-native-worklets'],\n\t\t\t'react-native-safe-area-context':\n\t\t\t\tEXPO_VERSIONS['react-native-safe-area-context'],\n\t\t\t'react-native-screens': EXPO_VERSIONS['react-native-screens'],\n\t\t\t'react-native-web': EXPO_VERSIONS['react-native-web'],\n\t\t\ttailwindcss: EXPO_VERSIONS['tailwindcss'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@babel/core': EXPO_VERSIONS['@babel/core'],\n\t\t\t'@types/react': EXPO_VERSIONS['@types/react'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\tconst appConfig = `import type { ConfigContext, ExpoConfig } from '@expo/config';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\n/**\n * What the app is built with, from the environment \\`gkm\\` injects — the\n * \\`MobileApp\\` construct's \\`.dependsOn([api, auth])\\` is where every value\n * here comes from, so none of it is written down.\n *\n * - \\`APP_SCHEME\\`: the URL scheme — \\`${scheme}\\`, the same on every stage.\n * - \\`EXPO_PUBLIC_API_URL\\` / \\`EXPO_PUBLIC_AUTH_URL\\`: where the servers\n * answer. Locally that is their own port on \\`localhost\\`, which\n * \\`config.ts\\` points at the machine Metro was served from.\n *\n * Read at runtime from \\`Constants.expoConfig.extra.config\\` — see \\`config.ts\\`.\n */\nconst config = new EnvironmentParser({ ...process.env })\n .create((get) => ({\n scheme: get('APP_SCHEME').string(),\n apiUrl: get('EXPO_PUBLIC_API_URL').string(),\n authUrl: get('EXPO_PUBLIC_AUTH_URL').string(),\n }))\n .parse();\n\nexport type Config = typeof config;\n\n// A bundle id and an Android package allow no hyphens; one per scheme, so\n// each stage installs beside the others.\nconst bundleId = \\`com.\\${config.scheme.replace(/[^a-z0-9]/g, '')}.app\\`;\n\nexport default function expoConfig({ config: base }: ConfigContext): ExpoConfig {\n return {\n ...base,\n name: '${options.name}',\n slug: '${slug}',\n version: '0.0.1',\n orientation: 'portrait',\n icon: './assets/icon.png',\n scheme: config.scheme,\n userInterfaceStyle: 'automatic',\n newArchEnabled: true,\n ios: {\n supportsTablet: true,\n bundleIdentifier: bundleId,\n },\n android: {\n package: bundleId,\n adaptiveIcon: {\n foregroundImage: './assets/adaptive-icon.png',\n backgroundColor: '#ffffff',\n },\n edgeToEdgeEnabled: true,\n },\n web: {\n output: 'static',\n },\n plugins: [\n 'expo-router',\n 'expo-secure-store',\n [\n 'expo-splash-screen',\n {\n image: './assets/splash.png',\n imageWidth: 200,\n resizeMode: 'contain',\n backgroundColor: '#ffffff',\n },\n ],\n ],\n experiments: {\n typedRoutes: true,\n },\n extra: { ...base.extra, config },\n };\n}\n`;\n\n\tconst easJson = {\n\t\tcli: {\n\t\t\tversion: '>= 10.2.1',\n\t\t\tappVersionSource: 'remote',\n\t\t},\n\t\tbuild: {\n\t\t\tdev: {\n\t\t\t\tdevelopmentClient: true,\n\t\t\t\tdistribution: 'internal',\n\t\t\t\t// Locally \\`gkm\\` injects the scheme and both URLs from the graph.\n\t\t\t\tenvironment: 'development',\n\t\t\t},\n\t\t\tpreview: {\n\t\t\t\tdistribution: 'internal',\n\t\t\t\tenvironment: 'preview',\n\t\t\t\t// EAS builds outside \\`gkm\\`, so a store build is told its scheme —\n\t\t\t\t// the bare one, which is what the deployed auth server trusts.\n\t\t\t\tenv: {\n\t\t\t\t\tAPP_SCHEME: scheme,\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t\tproduction: {\n\t\t\t\tautoIncrement: true,\n\t\t\t\tenvironment: 'production',\n\t\t\t\t// EAS builds outside \\`gkm\\`, so a store build is told its scheme —\n\t\t\t\t// the bare one, which is what the deployed auth server trusts.\n\t\t\t\tenv: {\n\t\t\t\t\tAPP_SCHEME: scheme,\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n\n\tconst babelConfig = `module.exports = function (api) {\n api.cache(true);\n return {\n presets: [\n ['babel-preset-expo', { jsxImportSource: 'nativewind' }],\n 'nativewind/babel',\n ],\n };\n};\n`;\n\n\tconst metroConfig = `const { getDefaultConfig } = require('expo/metro-config');\nconst { withNativeWind } = require('nativewind/metro');\n\nconst config = getDefaultConfig(__dirname);\n\nmodule.exports = withNativeWind(config, { input: './global.css' });\n`;\n\n\tconst tsConfig = {\n\t\textends: 'expo/tsconfig.base',\n\t\tcompilerOptions: {\n\t\t\tstrict: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\ttypes: ['nativewind/types'],\n\t\t\tpaths: {\n\t\t\t\t'@/*': ['./*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: [\n\t\t\t'**/*.ts',\n\t\t\t'**/*.tsx',\n\t\t\t'.expo/types/**/*.ts',\n\t\t\t'expo-env.d.ts',\n\t\t\t'nativewind-env.d.ts',\n\t\t],\n\t};\n\n\tconst tailwindConfig = `import type { Config } from 'tailwindcss';\n\nexport default {\n content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],\n presets: [require('nativewind/preset')],\n theme: {\n extend: {},\n },\n plugins: [],\n} satisfies Config;\n`;\n\n\tconst globalCss = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`;\n\n\tconst expoEnvDts = `/// <reference types=\"expo/types\" />\\n`;\n\n\tconst nativewindEnvDts = `/// <reference types=\"nativewind/types\" />\\n`;\n\n\tconst configTs = `import Constants from 'expo-constants';\nimport * as Device from 'expo-device';\nimport { Platform } from 'react-native';\n\nimport type { Config } from './app.config.ts';\n\nconst built = Constants.expoConfig?.extra?.config as Config;\n\n/** The host this device loaded the bundle from: Metro's, as the device sees it. */\nconst metro = (Constants.expoConfig?.hostUri ?? '').split(':')[0];\n\n/**\n * A private address on the local network — what a phone on the same Wi-Fi\n * reaches this machine on. A tunnel's \\`*.exp.direct\\` host is not one: a\n * tunnel forwards only Metro, so the servers are not behind it.\n */\nconst isLan = (host: string) =>\n /^10\\\\./.test(host) ||\n /^192\\\\.168\\\\./.test(host) ||\n /^172\\\\.(1[6-9]|2\\\\d|3[01])\\\\./.test(host);\n\n/** \\`localhost\\` from inside the Android emulator is the emulator itself. */\nconst isAndroidEmulator = Platform.OS === 'android' && !Device.isDevice;\n\n/**\n * A server's URL as this device reaches it.\n *\n * Locally the servers are injected as \\`http://localhost:<port>\\`. That is this\n * device only on the iOS simulator. The Android emulator reaches this machine\n * at \\`10.0.2.2\\`, and a phone at the LAN address Metro was served from.\n * Deployed URLs have no \\`localhost\\` in them and pass through untouched.\n */\nexport function reachable(url: string): string {\n const host = isLan(metro) ? metro : isAndroidEmulator ? '10.0.2.2' : undefined;\n if (!host) return url;\n return url.replace(/\\\\/\\\\/(localhost|127\\\\.0\\\\.0\\\\.1)(?=[:/]|$)/, \\`//\\${host}\\`);\n}\n\nexport const config = {\n scheme: built.scheme,\n apiUrl: reachable(built.apiUrl),\n authUrl: reachable(built.authUrl),\n};\n`;\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n});\n`;\n\n\tconst authClientTs = `import { expoClient, getSetCookie } from '@better-auth/expo/client';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport * as Linking from 'expo-linking';\nimport * as SecureStore from 'expo-secure-store';\nimport { useEffect } from 'react';\n\nimport { config } from '@/config.ts';\n\nexport const STORAGE_PREFIX = config.scheme;\nexport const COOKIE_STORE_KEY = \\`\\${STORAGE_PREFIX}_cookie\\`;\n\nexport const authClient = createAuthClient({\n baseURL: config.authUrl,\n plugins: [\n expoClient({\n scheme: config.scheme,\n storagePrefix: STORAGE_PREFIX,\n storage: SecureStore,\n }),\n magicLinkClient(),\n ],\n});\n\nexport const { signIn, useSession } = authClient;\n\n/**\n * Sign in from the emailed link.\n *\n * The link opens in the phone's browser, which is what receives the session\n * cookie — not the app. The auth server's Expo plugin carries the cookie on the\n * redirect back into the app (\\`?cookie=\\`), and this stores it where the\n * Expo client keeps its own, merged with what is already there, then tells the\n * client the session changed. The Expo client does this itself only for a\n * sign-in it opened (social); a link opened from mail arrives as a deep link.\n *\n * Called once, from the root layout.\n */\nexport function useSessionFromLink() {\n const url = Linking.useLinkingURL();\n\n useEffect(() => {\n const cookie = url ? Linking.parse(url).queryParams?.cookie : undefined;\n if (typeof cookie !== 'string') return;\n\n void (async () => {\n const previous = await SecureStore.getItemAsync(COOKIE_STORE_KEY);\n await SecureStore.setItemAsync(\n COOKIE_STORE_KEY,\n getSetCookie(cookie, previous ?? undefined),\n );\n authClient.$store.notify('$sessionSignal');\n })();\n }, [url]);\n}\n\nexport async function signOut() {\n try {\n await authClient.signOut();\n } finally {\n await SecureStore.deleteItemAsync(COOKIE_STORE_KEY);\n }\n}\n`;\n\n\tconst apiTs = `import { createApi } from '@${options.name}/client/api';\n\nimport { config } from '@/config.ts';\nimport { authClient } from './auth-client.ts';\nimport { queryClient } from './query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n return createApi({\n baseURL: config.apiUrl,\n queryClient,\n headers: options?.headers,\n onRequest: (cfg) => {\n const cookie = authClient.getCookie();\n const next = { ...cfg, credentials: 'omit' as const };\n if (cookie) {\n return {\n ...next,\n headers: { ...(next.headers ?? {}), Cookie: cookie },\n };\n }\n return next;\n },\n });\n}\n`;\n\n\tconst apiContextTsx = `import { createContext, type ReactNode, use } from 'react';\nimport type { createAppApi } from './api.ts';\n\nexport type Api = ReturnType<typeof createAppApi>;\n\nconst ApiContext = createContext<Api | null>(null);\n\nexport function ApiProvider({\n api,\n children,\n}: {\n api: Api;\n children: ReactNode;\n}) {\n return <ApiContext.Provider value={api}>{children}</ApiContext.Provider>;\n}\n\nexport function useApi(): Api {\n const api = use(ApiContext);\n if (!api) {\n throw new Error('useApi must be used within an ApiProvider');\n }\n return api;\n}\n`;\n\n\tconst layoutTsx = `import '../global.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { Stack, useRouter, useSegments } from 'expo-router';\nimport { StatusBar } from 'expo-status-bar';\nimport { useEffect, useMemo } from 'react';\nimport 'react-native-reanimated';\n\nimport { authClient, useSessionFromLink } from '@/lib/auth-client.ts';\nimport { ApiProvider } from '@/lib/api-context.tsx';\nimport { createAppApi } from '@/lib/api.ts';\nimport { queryClient } from '@/lib/query-client.ts';\n\nfunction AuthGate({ children }: { children: React.ReactNode }) {\n const router = useRouter();\n const segments = useSegments();\n const { data: session, isPending } = authClient.useSession();\n\n useEffect(() => {\n if (isPending) return;\n const onAuthRoute = segments[0] === 'login';\n if (!session && !onAuthRoute) {\n router.replace('/login');\n } else if (session && onAuthRoute) {\n router.replace('/');\n }\n }, [isPending, session, segments, router]);\n\n return <>{children}</>;\n}\n\nexport default function RootLayout() {\n const api = useMemo(() => createAppApi(), []);\n // The emailed sign-in link comes back as a deep link carrying the session.\n useSessionFromLink();\n\n return (\n <QueryClientProvider client={queryClient}>\n <ApiProvider api={api}>\n <AuthGate>\n <Stack screenOptions={{ headerShown: false }}>\n <Stack.Screen name=\"index\" />\n <Stack.Screen name=\"login\" />\n </Stack>\n </AuthGate>\n <StatusBar style=\"auto\" />\n </ApiProvider>\n </QueryClientProvider>\n );\n}\n`;\n\n\tconst indexTsx = `import { Pressable, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { signOut, useSession } from '@/lib/auth-client.ts';\nimport { useApi } from '@/lib/api-context.tsx';\n\nexport default function Home() {\n const { data: session } = useSession();\n const api = useApi();\n const { data: health } = api.useQuery('GET /health', {});\n\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <View className=\"flex-1 items-center justify-center gap-4 px-6\">\n <Text className=\"text-3xl font-bold text-slate-900\">\n Welcome to ${options.name}\n </Text>\n {session ? (\n <Text className=\"text-sm text-slate-500\">\n Signed in as {session.user.email}\n </Text>\n ) : null}\n {health ? (\n <Text className=\"text-xs text-slate-400\">\n API: {JSON.stringify(health)}\n </Text>\n ) : null}\n <Pressable\n onPress={signOut}\n className=\"mt-4 rounded-lg bg-slate-900 px-6 py-3\"\n >\n <Text className=\"font-semibold text-white\">Sign out</Text>\n </Pressable>\n </View>\n </SafeAreaView>\n );\n}\n`;\n\n\tconst loginTsx = `import * as Linking from 'expo-linking';\nimport { useState } from 'react';\nimport {\n KeyboardAvoidingView,\n Platform,\n Pressable,\n Text,\n TextInput,\n View,\n} from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { authClient } from '@/lib/auth-client.ts';\n\nconst EMAIL_RE = /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/;\n\nexport default function LoginScreen() {\n const [email, setEmail] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function handleSubmit() {\n if (!EMAIL_RE.test(email.trim())) {\n setError('Enter a valid email address');\n return;\n }\n setError(null);\n setSubmitting(true);\n\n const callbackURL = Linking.createURL('/').replace(/^(\\\\w+):\\\\/\\\\/\\\\//, '$1://');\n try {\n const result = await authClient.signIn.magicLink({\n email: email.trim(),\n callbackURL,\n });\n if (result.error) {\n setError(result.error.message ?? 'Could not send magic link');\n return;\n }\n setSent(true);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Something went wrong');\n } finally {\n setSubmitting(false);\n }\n }\n\n if (sent) {\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <View className=\"flex-1 items-center justify-center px-6\">\n <Text className=\"text-2xl font-bold text-slate-900\">\n Check your inbox\n </Text>\n <Text className=\"mt-3 text-center text-slate-500\">\n We sent a sign-in link to {email.trim()}\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n return (\n <SafeAreaView className=\"flex-1 bg-white\">\n <KeyboardAvoidingView\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n className=\"flex-1\"\n >\n <View className=\"flex-1 justify-center px-6\">\n <Text className=\"text-3xl font-bold text-slate-900\">Sign in</Text>\n <Text className=\"mt-1 text-sm text-slate-500\">\n We'll email you a one-time sign-in link.\n </Text>\n\n <Text className=\"mt-6 text-xs font-semibold uppercase text-slate-500\">\n Email\n </Text>\n <TextInput\n value={email}\n onChangeText={(v) => {\n setEmail(v);\n if (error) setError(null);\n }}\n autoCapitalize=\"none\"\n autoCorrect={false}\n keyboardType=\"email-address\"\n placeholder=\"you@example.com\"\n placeholderTextColor=\"#94a3b8\"\n editable={!submitting}\n className=\"mt-2 rounded-lg border border-slate-300 px-4 py-3\"\n />\n {error ? (\n <Text className=\"mt-2 text-sm text-red-600\">{error}</Text>\n ) : null}\n\n <Pressable\n onPress={handleSubmit}\n disabled={submitting}\n className=\"mt-6 items-center rounded-lg bg-slate-900 py-4 disabled:opacity-60\"\n >\n <Text className=\"font-semibold text-white\">\n {submitting ? 'Sending…' : 'Email me a sign-in link'}\n </Text>\n </Pressable>\n </View>\n </KeyboardAvoidingView>\n </SafeAreaView>\n );\n}\n`;\n\n\tconst gitignore = `node_modules/\n.expo/\ndist/\n*.log\n.env*.local\nios/\nandroid/\n.eas/\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/app/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/app.config.ts', content: appConfig },\n\t\t{\n\t\t\tpath: 'apps/app/eas.json',\n\t\t\tcontent: `${JSON.stringify(easJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/babel.config.js', content: babelConfig },\n\t\t{ path: 'apps/app/metro.config.js', content: metroConfig },\n\t\t{\n\t\t\tpath: 'apps/app/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/tailwind.config.ts', content: tailwindConfig },\n\t\t{ path: 'apps/app/global.css', content: globalCss },\n\t\t{ path: 'apps/app/expo-env.d.ts', content: expoEnvDts },\n\t\t{ path: 'apps/app/nativewind-env.d.ts', content: nativewindEnvDts },\n\t\t{ path: 'apps/app/config.ts', content: configTs },\n\t\t{ path: 'apps/app/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/app/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/app/lib/api.ts', content: apiTs },\n\t\t{ path: 'apps/app/lib/api-context.tsx', content: apiContextTsx },\n\t\t{ path: 'apps/app/app/_layout.tsx', content: layoutTsx },\n\t\t{ path: 'apps/app/app/index.tsx', content: indexTsx },\n\t\t{ path: 'apps/app/app/login.tsx', content: loginTsx },\n\t\t{ path: 'apps/app/.gitignore', content: gitignore },\n\t];\n}\n","import { TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/**\n * Generate packages/models for shared Zod schemas (monorepo only)\n */\nexport function generateModelsPackage(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\t// Package name based on project name\n\tconst packageName = `@${options.name}/models`;\n\n\t// package.json for models\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\texports: {\n\t\t\t'./*': './src/*.ts',\n\t\t},\n\t\tscripts: {\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {},\n\t\tdevDependencies: {\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// tsconfig.json for models - extends root config\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// common.ts - shared utility schemas\n\tconst commonTs = `import { z } from 'zod';\n\n// ============================================\n// Common Schemas\n// ============================================\n\nexport const IdSchema = z.uuid();\n\nexport const IdParamsSchema = z.object({\n id: IdSchema,\n});\n\nexport const TimestampsSchema = z.object({\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\nexport const PaginationSchema = z.object({\n page: z.coerce.number().int().positive().default(1),\n limit: z.coerce.number().int().positive().max(100).default(20),\n});\n\nexport const PaginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>\n z.object({\n items: z.array(itemSchema),\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n });\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type Id = z.infer<typeof IdSchema>;\nexport type IdParams = z.infer<typeof IdParamsSchema>;\nexport type Timestamps = z.infer<typeof TimestampsSchema>;\nexport type Pagination = z.infer<typeof PaginationSchema>;\n`;\n\n\t// user.ts - user-related schemas\n\tconst userTs = `import { z } from 'zod';\nimport { IdSchema, TimestampsSchema } from './common.ts';\n\n// ============================================\n// User Schemas\n// ============================================\n\nexport const UserSchema = z.object({\n id: IdSchema,\n email: z.email(),\n name: z.string().min(1).max(100),\n ...TimestampsSchema.shape,\n});\n\nexport const CreateUserSchema = UserSchema.omit({\n id: true,\n createdAt: true,\n updatedAt: true,\n});\n\nexport const UpdateUserSchema = CreateUserSchema.partial();\n\n// ============================================\n// Response Schemas\n// ============================================\n\nexport const UserResponseSchema = UserSchema.pick({\n id: true,\n name: true,\n email: true,\n});\n\nexport const ListUsersResponseSchema = z.object({\n users: z.array(UserSchema.pick({ id: true, name: true })),\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type User = z.infer<typeof UserSchema>;\nexport type CreateUser = z.infer<typeof CreateUserSchema>;\nexport type UpdateUser = z.infer<typeof UpdateUserSchema>;\nexport type UserResponse = z.infer<typeof UserResponseSchema>;\nexport type ListUsersResponse = z.infer<typeof ListUsersResponseSchema>;\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'packages/models/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/common.ts',\n\t\t\tcontent: commonTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/user.ts',\n\t\t\tcontent: userTs,\n\t\t},\n\t];\n}\n","/**\n * What a workspace needs to reach the host it was scaffolded for.\n *\n * The constructs are the same whichever target is picked — a `Database` is a\n * Postgres on Dokploy and an RDS instance on AWS, and nothing in the\n * application says which. What differs is around them: the deploy script, and\n * for SST the config SST runs and the packages that config imports.\n */\n\nimport { canonicalId } from '@geekmidas/manifest';\nimport { databaseFor, emailFor } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\nexport interface DeployPackage {\n\tscripts: Record<string, string>;\n\tdependencies: Record<string, string>;\n\tdevDependencies: Record<string, string>;\n}\n\n/** One `deploy:<stage>` script per deployed stage. */\nconst perStage = (\n\toptions: TemplateOptions,\n\tcommand: (stage: string) => string,\n): Record<string, string> =>\n\tObject.fromEntries(\n\t\toptions.stages.deployed.map((stage) => [`deploy:${stage}`, command(stage)]),\n\t);\n\nexport function deployPackage(options: TemplateOptions): DeployPackage {\n\tswitch (options.deployTarget) {\n\t\tcase 'dokploy':\n\t\t\treturn {\n\t\t\t\tscripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),\n\t\t\t\tdependencies: {},\n\t\t\t\tdevDependencies: {},\n\t\t\t};\n\t\tcase 'sst': {\n\t\t\tconst v = GEEKMIDAS_VERSIONS;\n\t\t\treturn {\n\t\t\t\t// `gkm deploy` builds `.gkm/manifest/aws.ts` — all `sst.config.ts`\n\t\t\t\t// reads; it never imports the application — then runs\n\t\t\t\t// `sst deploy` and checks what it released.\n\t\t\t\tscripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),\n\t\t\t\t// What `@geekmidas/cloud/sst` imports. They are optional peers of\n\t\t\t\t// the cloud package, so nothing installs them unless asked.\n\t\t\t\tdependencies: {\n\t\t\t\t\t'@geekmidas/cloud': v['@geekmidas/cloud'],\n\t\t\t\t\t'@geekmidas/db': v['@geekmidas/db'],\n\t\t\t\t\t'@geekmidas/envkit': v['@geekmidas/envkit'],\n\t\t\t\t\t'@geekmidas/events': v['@geekmidas/events'],\n\t\t\t\t\t'@geekmidas/manifest': v['@geekmidas/manifest'],\n\t\t\t\t\t'@geekmidas/storage': v['@geekmidas/storage'],\n\t\t\t\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t\t\t},\n\t\t\t\tdevDependencies: { sst: DEPENDENCY_VERSIONS.sst },\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn { scripts: {}, dependencies: {}, devDependencies: {} };\n\t}\n}\n\nexport function generateDeployFiles(options: TemplateOptions): GeneratedFile[] {\n\tif (options.deployTarget !== 'sst') return [];\n\tif (!options.region) throw new SstNeedsRegion();\n\n\tconst db = databaseFor();\n\tconst mail = emailFor();\n\tconst hasDatabase = options.constructs.database;\n\n\t// Provider inputs keyed by construct id: the two things a neutral\n\t// declaration cannot carry. `fromManifest` types its overrides from the\n\t// manifest, so leaving either out is a type error in sst.config.ts.\n\tconst inputs = [\n\t\t...(hasDatabase\n\t\t\t? [\n\t\t\t\t\t` // RDS needs a network. Created here rather than assumed, because a\n // VPC with NAT is a monthly cost in an account that may already\n // have one — replace it with \\`sst.aws.Vpc.get(…)\\` if so.\n ${db.id}: { vpc },`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(options.constructs.mail\n\t\t\t? [\n\t\t\t\t\t` // Every provider rejects an unverified sender, so there is no\n // default — \\`fromManifest\\` requires it, by the manifest's types.\n ${mail.id}: { from: process.env.MAIL_FROM as string },`,\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\n\treturn [\n\t\t{\n\t\t\tpath: 'sst.config.ts',\n\t\t\tcontent: `/// <reference path=\"./.sst/platform/config.d.ts\" />\n\n/**\n * ${options.name} on AWS.\n *\n * No bucket, cluster, queue or IAM is listed here: they come from the\n * constructs the application declares, through \\`fromManifest\\`. What is here\n * is what varies by stage, and the inputs a declaration cannot carry.\n *\n * Deploy with \\`gkm deploy --stage <stage>\\`, which builds the manifest first.\n */\nconst region = '${options.region}';\n\n/** From \\`stages.protected\\` in gkm.config.ts. */\nconst PROTECTED: string[] = ${JSON.stringify(options.stages.protected ?? []).replace(/\"/g, \"'\")};\n\nexport default $config({\n app(input) {\n return {\n name: '${options.name}',\n // Any other stage is disposable; a protected one's database should not\n // vanish because somebody removed a stack.\n removal: PROTECTED.includes(input?.stage) ? 'retain' : 'remove',\n protect: PROTECTED.includes(input?.stage),\n home: 'aws',\n providers: { aws: { region } },\n };\n },\n\n async run() {\n const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');\n // Written by \\`gkm build\\`. Imported rather than discovered,\n // so SST's toolchain never evaluates the application's own modules.\n const { backends, constructs } = await import('./.gkm/manifest/aws.js');\n\n${hasDatabase ? \" const vpc = new sst.aws.Vpc('Vpc', { nat: 'ec2' });\\n\\n\" : ''} const app = new App({\n name: $app.name,\n stage: $app.stage,\n domain: '',\n region,\n hostedZoneId: '',\n });\n\n const provisioned = fromManifest(\n new Stack(app, '${canonicalId(options.name)}'),\n constructs,\n {\n${inputs.join('\\n')}\n },\n backends,\n );\n\n // Each surface's URL, by its id: SST prints these and writes them to\n // .sst/outputs.json, where \\`gkm deploy\\` reads them to health-check\n // what it released.\n return Object.fromEntries(\n Object.entries(constructs)\n .filter(([, c]) => c.kind === 'rest-api' || c.kind === 'site')\n .map(([id]) => [id, provisioned[id]!.provides().url]),\n );\n },\n});\n`,\n\t\t},\n\t];\n}\n\n/**\n * An SST scaffold asked for without a region. `init` always resolves one —\n * asked, `--region`, or eu-west-1 under `--yes` — so this is a caller's bug.\n */\nexport class SstNeedsRegion extends Error {\n\tconstructor() {\n\t\tsuper('An SST deploy needs a region: pass --region, e.g. eu-west-1.');\n\t\tthis.name = 'SstNeedsRegion';\n\t}\n}\n","import { dirname } from 'node:path';\nimport {\n\tcacheFor,\n\tdatabaseFor,\n\temailFor,\n\tstorageFor,\n\tusersMigration,\n\tworkspaceConstructsGlobs,\n} from '../constructs.js';\nimport {\n\tBIOME_SCHEMA,\n\tDEPENDENCY_VERSIONS,\n\tEXPO_VERSIONS,\n\tPNPM_VERSION,\n\tTOOLCHAIN_VERSIONS,\n} from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport { deployPackage, generateDeployFiles } from './deploy.js';\nimport { stagesBlock } from './stages.js';\n\n/**\n * What the root `constructs/` folder imports, and the peers each construct\n * needs, for the services this workspace was scaffolded with.\n */\nfunction rootConstructDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\tconst v = GEEKMIDAS_VERSIONS;\n\treturn {\n\t\t'@geekmidas/constructs': v['@geekmidas/constructs'],\n\t\t'@geekmidas/logger': v['@geekmidas/logger'],\n\t\t...(options.loggerType === 'pino'\n\t\t\t? { pino: DEPENDENCY_VERSIONS.pino }\n\t\t\t: {}),\n\t\t// `RestApi` needs Telescope's types; `BetterAuth` needs the auth\n\t\t// package and Better Auth itself.\n\t\t'@geekmidas/telescope': v['@geekmidas/telescope'],\n\t\t'@geekmidas/auth': v['@geekmidas/auth'],\n\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t// `KyselyDatabase`.\n\t\t'@geekmidas/db': v['@geekmidas/db'],\n\t\tkysely: DEPENDENCY_VERSIONS.kysely,\n\t\tpg: DEPENDENCY_VERSIONS.pg,\n\t\t...(options.constructs.uploads\n\t\t\t? { '@geekmidas/storage': v['@geekmidas/storage'] }\n\t\t\t: {}),\n\t\t...(options.constructs.mail\n\t\t\t? { '@geekmidas/emailkit': v['@geekmidas/emailkit'] }\n\t\t\t: {}),\n\t\t...(options.constructs.cache\n\t\t\t? { '@geekmidas/cache': v['@geekmidas/cache'] }\n\t\t\t: {}),\n\t\t// A mobile app signs in through Better Auth's Expo plugin, which the\n\t\t// auth server loads when one depends on it.\n\t\t...(options.frontendFramework === 'expo'\n\t\t\t? { '@better-auth/expo': DEPENDENCY_VERSIONS['better-auth'] }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * What each API's generated client imports, installed where the client is.\n *\n * The client is written to the root's `.gkm/client/`, so it resolves\n * `@geekmidas/client` and React Query from the root `node_modules` — as the\n * root `constructs/` folder does its imports — not from whichever site imports\n * it.\n *\n * React is pinned here too, because React Query's hooks resolve it from the\n * root, and a frontend running a different React than the one its client's\n * hooks resolve loads two — a broken hook call. So the root's React is the\n * workspace's: every frontend that imports a client runs this one. It starts\n * as the scaffolded frontend's; a frontend added later — a web app beside an\n * Expo app — is kept on the same version, not given its own.\n */\nfunction rootClientDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\treturn {\n\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\treact:\n\t\t\toptions.frontendFramework === 'expo'\n\t\t\t\t? EXPO_VERSIONS.react\n\t\t\t\t: DEPENDENCY_VERSIONS.react,\n\t};\n}\n\n/**\n * What `test/factories/` imports at the root: the factory and faker, and\n * Kysely's types where the root does not already install it for the\n * constructs.\n */\nfunction rootFactoryDependencies(\n\toptions: TemplateOptions,\n): Record<string, string> {\n\treturn {\n\t\t'@geekmidas/testkit': GEEKMIDAS_VERSIONS['@geekmidas/testkit'],\n\t\t'@faker-js/faker': DEPENDENCY_VERSIONS['@faker-js/faker'],\n\t\t...(options.template === 'fullstack'\n\t\t\t? {}\n\t\t\t: { kysely: DEPENDENCY_VERSIONS.kysely }),\n\t};\n}\n\n/**\n * Generate monorepo root files (pnpm-workspace.yaml, root package.json, etc.)\n */\nexport function generateMonorepoFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\tconst isFullstack = options.template === 'fullstack';\n\tconst deploy = deployPackage(options);\n\tconst isSst = options.deployTarget === 'sst';\n\n\t// Root package.json for monorepo\n\tconst rootPackageJson = {\n\t\tname: options.name,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tpackageManager: PNPM_VERSION,\n\t\tscripts: {\n\t\t\tdev: isFullstack ? 'gkm dev' : 'turbo dev',\n\t\t\tbuild: isFullstack ? 'gkm build' : 'turbo build',\n\t\t\ttest: isFullstack ? 'gkm test' : 'turbo test',\n\t\t\t'test:once': isFullstack ? 'gkm test --run' : 'turbo test:once',\n\t\t\ttypecheck: 'turbo typecheck',\n\t\t\tlint: 'biome lint .',\n\t\t\tfmt: 'biome format . --write',\n\t\t\t'fmt:check': 'biome format .',\n\t\t\t...deploy.scripts,\n\t\t},\n\t\tdependencies: {\n\t\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t\t\t// The root `constructs/` folder resolves its imports from the root\n\t\t\t// `node_modules`, not from any app's — so what the constructs load,\n\t\t\t// and the peers each of them needs, are installed here.\n\t\t\t...(isFullstack ? rootConstructDependencies(options) : {}),\n\t\t\t...(isFullstack ? rootClientDependencies(options) : {}),\n\t\t\t...deploy.dependencies,\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t\t\t// The test factories live at the root — a factory belongs to a\n\t\t\t// database, not to an app — and resolve their imports from the root\n\t\t\t// `node_modules`, as the constructs do.\n\t\t\t...(options.constructs.database ? rootFactoryDependencies(options) : {}),\n\t\t\t...deploy.devDependencies,\n\t\t},\n\t};\n\n\t// pnpm-workspace.yaml - detect folder structure from apiPath\n\tconst apiPathParts = options.apiPath.split('/');\n\tconst appsFolder = apiPathParts[0] || 'apps';\n\n\tconst pnpmWorkspace = `packages:\n - '${appsFolder}/*'\n - 'packages/*'\n`;\n\n\t// Root biome.json\n\tconst biomeConfig = {\n\t\t$schema: BIOME_SCHEMA,\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\t// Biome 2 moved import sorting into the assist, and `files.ignore` into\n\t\t// negated `includes`: the 1.x keys make it refuse the whole config.\n\t\tassist: { actions: { source: { organizeImports: 'on' } } },\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Tailwind v4's `@theme` and `@apply`, which the UI package's CSS uses.\n\t\tcss: { parser: { tailwindDirectives: true } },\n\t\tfiles: {\n\t\t\tincludes: [\n\t\t\t\t'**',\n\t\t\t\t'!**/node_modules',\n\t\t\t\t'!**/dist',\n\t\t\t\t'!**/.gkm',\n\t\t\t\t'!**/coverage',\n\t\t\t\t...(isSst ? ['!**/.sst', '!sst-env.d.ts'] : []),\n\t\t\t],\n\t\t},\n\t};\n\n\t// Root turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\t// Turbo hashes a package's own files, and an app's constructs and\n\t\t\t\t// the config naming them live above it, at the root. Without these,\n\t\t\t\t// editing a construct replays a stale cached build. Root task config\n\t\t\t\t// applies to every package, so a new app is covered with nothing\n\t\t\t\t// generated. `$TURBO_ROOT$` needs turbo 2.4+.\n\t\t\t\tinputs: [\n\t\t\t\t\t'$TURBO_DEFAULT$',\n\t\t\t\t\t'$TURBO_ROOT$/constructs/**/*.ts',\n\t\t\t\t\t'$TURBO_ROOT$/gkm.config.ts',\n\t\t\t\t],\n\t\t\t\t// A backend's build is under `.gkm/`; a Next.js site's under `.next/`.\n\t\t\t\toutputs: ['dist/**', '.gkm/**', '.next/**', '!.next/cache/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\t// Root .gitignore\n\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Written by gkm from the constructs; your own docker-compose.yml is not\ndocker-compose.constructs.yml\n\n# Environment\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Turbo\n.turbo/\n${isSst ? '\\n# SST\\n.sst/\\n' : ''}`;\n\n\t// Root tsconfig.json - base config for all packages\n\t// Using turbo typecheck to run tsc --noEmit in each app/package\n\tconst tsConfig = {\n\t\tcompilerOptions: {\n\t\t\t// How an app reaches the workspace's constructs without climbing out\n\t\t\t// of its own directory with `../../` — and the manifest `gkm build`\n\t\t\t// writes at the root, for whatever reads what was built.\n\t\t\tpaths: {\n\t\t\t\t...(isFullstack\n\t\t\t\t\t? { [`@${options.name}/constructs/*`]: ['./constructs/*'] }\n\t\t\t\t\t: {}),\n\t\t\t\t[`@${options.name}/manifest`]: [\n\t\t\t\t\t`./.gkm/manifest/${isSst ? 'aws' : 'server'}.ts`,\n\t\t\t\t],\n\t\t\t\t// Each API's typed client, generated beside the manifest.\n\t\t\t\t[`@${options.name}/client/*`]: ['./.gkm/client/*'],\n\t\t\t},\n\t\t\t...(isFullstack\n\t\t\t\t? {\n\t\t\t\t\t\t// The constructs import each other with `.ts` extensions.\n\t\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t\tnoEmit: true,\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\ttarget: 'ES2022',\n\t\t\tmodule: 'NodeNext',\n\t\t\tmoduleResolution: 'NodeNext',\n\t\t\tlib: ['ES2022'],\n\t\t\tstrict: true,\n\t\t\tesModuleInterop: true,\n\t\t\tskipLibCheck: true,\n\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\tresolveJsonModule: true,\n\t\t},\n\t\t// SST typechecks its own config against its own platform types, which\n\t\t// exist only after \\`sst install\\` and are not this project's to check.\n\t\texclude: [\n\t\t\t'node_modules',\n\t\t\t'dist',\n\t\t\t...(isSst ? ['sst.config.ts', '.sst'] : []),\n\t\t],\n\t};\n\n\t// Vitest config for workspace\n\tconst vitestConfig = `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n // The test stage, reconciled and every database construct's migrations\n // applied, before any project's tests start — declared here, once, so no\n // project filter can skip it and nothing runs it twice.\n globalSetup: ['@geekmidas/cli/vitest'],\n // Each app and package is its own project, so its own config — its path\n // aliases — applies to its own tests.\n projects: ['apps/*', 'packages/*'],\n // The shared packages ship without tests of their own.\n passWithNoTests: true,\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json', 'html'],\n exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts'],\n },\n },\n});\n`;\n\n\t// VSCode settings for consistent development experience\n\tconst vscodeSettings = {\n\t\t'search.exclude': {\n\t\t\t'**/.sst': true,\n\t\t\t'**/.gkm': true,\n\t\t\t'**/.turbo': true,\n\t\t},\n\t\t'editor.formatOnSave': true,\n\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t'editor.codeActionsOnSave': {\n\t\t\t'source.fixAll.biome': 'always',\n\t\t\t'source.organizeImports.biome': 'always',\n\t\t\t'source.organizeImports': 'always',\n\t\t},\n\t\t'[typescriptreact]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[typescript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[javascript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[json]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'cSpell.words': [\n\t\t\t'betterauth',\n\t\t\t'dokploy',\n\t\t\t'envkit',\n\t\t\t'geekmidas',\n\t\t\t'healthcheck',\n\t\t\t'kysely',\n\t\t\t'testkit',\n\t\t\t'timestamptz',\n\t\t\t'turborepo',\n\t\t\toptions.name,\n\t\t],\n\t};\n\n\t// VSCode extensions recommendations\n\tconst vscodeExtensions = {\n\t\trecommendations: [\n\t\t\t'biomejs.biome',\n\t\t\t'streetsidesoftware.code-spell-checker',\n\t\t\t'dbaeumer.vscode-eslint',\n\t\t\t'ms-azuretools.vscode-docker',\n\t\t],\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(rootPackageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'pnpm-workspace.yaml',\n\t\t\tcontent: pnpmWorkspace,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfig,\n\t\t},\n\t\t{\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/settings.json',\n\t\t\tcontent: `${JSON.stringify(vscodeSettings, null, '\\t')}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/extensions.json',\n\t\t\tcontent: `${JSON.stringify(vscodeExtensions, null, '\\t')}\\n`,\n\t\t},\n\t\t...generateDeployFiles(options),\n\t];\n\n\t// Add workspace config for fullstack template\n\tif (isFullstack) {\n\t\tfiles.push({\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: generateWorkspaceConfig(options),\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * `gkm.config.ts` for the fullstack workspace.\n *\n * What is *not* here is the point. There is no `apps` block: the apps are the\n * constructs that said they have a process — a `RestApi`, a `BetterAuth`, a\n * `StaticSite` — and naming them again here would be the same sentence written\n * twice with only one copy checked.\n *\n * There is no `services` block either unless something non-default was picked.\n * Every key defaults from the deploy target: on a server target a cache is a\n * table in the database that is already there, storage is MinIO, mail is SES.\n */\nfunction generateWorkspaceConfig(options: TemplateOptions): string {\n\tconst config = `import { defineWorkspace } from '@geekmidas/cli/config';\n\nexport default defineWorkspace({\n // The scope every physical name is built from: \\`Database\\` becomes\n // \\`production-${options.name}-database\\` on Dokploy and on AWS alike.\n name: '${options.name}',\n${stagesBlock(options.stages)}\n${deployBlock(options)}\n // Every kind, in every app. A declared database is why a Postgres exists, a\n // declared bucket is why MinIO does, a declared topic is why a broker does —\n // none of it listed here. It is also where the apps come from: a\n // \\`StaticSite\\` is an app, and so is every \\`RestApi\\`. And it finds each\n // app's endpoints, crons and subscribers: an endpoint belongs to the surface\n // it was built from, not to the directory it sits in.\n constructs: [\n${workspaceConstructsGlobs(options.routesStructure, dirname(options.apiPath))\n\t.map((glob) => ` '${glob}',`)\n\t.join('\\n')}\n ],\n\n secrets: {\n enabled: true,${secretsStore(options)}\n },\n});\n`;\n\n\treturn config;\n}\n\n/**\n * Where it deploys, when that is not the default Dokploy: what a bare\n * `gkm build` builds for, and which backends a cache or a broker resolves to.\n */\nfunction deployBlock(options: TemplateOptions): string {\n\tif (options.deployTarget !== 'sst') return '';\n\treturn `\n // \\`gkm deploy\\` runs \\`sst deploy\\` on the manifest \\`gkm build\\` writes to\n // \\`.gkm/manifest/aws.ts\\`. Each construct becomes a managed AWS resource.\n deploy: { default: 'sst' },\n`;\n}\n\n/**\n * Where a deployed stage's secrets live. On AWS that is SSM in the stage's own\n * account, which the deploy job reaches with the role it already assumed; a\n * server target keeps the encrypted local file, the default.\n */\nfunction secretsStore(options: TemplateOptions): string {\n\tif (options.deployTarget !== 'sst' || !options.region) return '';\n\treturn `\n // Deployed stages keep their secrets in SSM, in the account each stage\n // deploys to: \\`gkm secrets:set <KEY> '…' --stage <stage>\\` writes there.\n // Past 8 KB a stage needs { provider: 'secrets-manager', region } instead.\n store: { provider: 'ssm', region: '${options.region}' },`;\n}\n\n/**\n * The workspace's constructs, at its root rather than inside an app.\n *\n * They outlive the app that used them first: a site depending on the API is a\n * fact about the workspace, and a construct reaching across into a sibling\n * app's `src/` to state it is the shape this layout removes. Apps import them\n * through the `@<name>/constructs/*` path the root tsconfig maps.\n *\n * Every one of these is also an answer config used to give: the database is\n * why a Postgres exists, the surface and the site are the apps, and the edges\n * between them are the CORS origins and the build order.\n */\nexport function generateRootConstructs(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') return [];\n\n\tconst { frontendFramework } = options;\n\tconst { cache, uploads, mail } = options.constructs;\n\tconst db = databaseFor();\n\tconst files: GeneratedFile[] = [];\n\n\tfiles.push({\n\t\tpath: 'constructs/logger.ts',\n\t\tcontent: `import { createLogger } from '@geekmidas/logger/${options.loggerType}';\n\n/**\n * The logger every endpoint runs with.\n *\n * Named once, here, because the surface carries it. It used to be\n * \\`logger: './src/config/logger#logger'\\` in config — a module path the build\n * printed into each generated handler, checked by nothing and wrong the moment\n * the file moved.\n */\nexport const logger = createLogger();\n`,\n\t});\n\n\tfiles.push({\n\t\tpath: 'constructs/database.ts',\n\t\tcontent: `import { KyselyDatabase } from '@geekmidas/constructs/database/kysely';\nimport { CamelCasePlugin, type Generated } from 'kysely';\n\n/**\n * Your database schema. Add tables here.\n *\n * camelCase, because of the plugin below: the columns are snake_case in\n * Postgres (\\`created_at\\`), and Kysely maps between the two.\n */\nexport interface Database {\n users: {\n id: Generated<string>;\n name: string;\n email: string;\n createdAt: Generated<Date>;\n };\n}\n\n/**\n * The database, declared once.\n *\n * The container, the database inside it, its roles and schema, and\n * \\`${db.urlKey}\\` all derive from this line — which is why nothing lists\n * \\`postgres\\` anywhere.\n */\nexport const database = new KyselyDatabase<Database, '${db.id}'>('${db.id}', {\n // Yours to keep, change or remove. Every connection this construct opens —\n // every endpoint, the tests — uses it.\n plugins: [new CamelCasePlugin()],\n});\n\n/**\n * The auth server's own schema in that same Postgres, with its own role.\n *\n * A schema tenant rather than a second database: one container, and a role\n * whose \\`search_path\\` is pinned, so Better Auth's tables cannot collide with\n * the application's. It takes its own options: no plugin, because Better\n * Auth names its own columns.\n */\nexport const authDb = database.schema<Record<string, never>, 'AuthDb'>('AuthDb');\n`,\n\t});\n\n\t// Its migrations beside it, in the folder its name gives.\n\tfiles.push(usersMigration());\n\n\tfiles.push({\n\t\tpath: 'constructs/auth.ts',\n\t\tcontent: `${frontendFramework === 'expo' ? \"import { expo } from '@better-auth/expo';\\n\" : ''}import { BetterAuth } from '@geekmidas/constructs/auth';\nimport { authDb } from './database.ts';\n\n/**\n * The auth server.\n *\n * There is no \\`src/index.ts\\` to go with this, and that is the point: the\n * routes are a wildcard, so no glob finds them and the build generates the\n * entry from this declaration instead. CORS, the trusted origins and the\n * cookie domain come from whatever declared an edge to it — nobody writes an\n * origin down.\n */\nexport const auth = new BetterAuth('Auth', {\n path: 'apps/auth',\n database: authDb,\n basePath: '/api/auth',${\n\t\tfrontendFramework === 'expo'\n\t\t\t? `\n // The mobile app signs in through Better Auth's Expo plugin: it sends its\n // scheme as the origin, and this is what reads it. The construct refuses to\n // start without it once a MobileApp depends on this server.\n options: { plugins: [expo()] },`\n\t\t\t: ''\n\t}\n});\n`,\n\t});\n\n\tfiles.push({\n\t\tpath: 'constructs/api.ts',\n\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { auth } from './auth.ts';\nimport { logger } from './logger.ts';\n\n/**\n * The application's HTTP surface — one RestApi, one container.\n *\n * \\`path\\` is where its app lives. Its handlers are found by the workspace's\n * \\`constructs\\` glob, and belong to it because they were built from it.\n */\nexport const api = new RestApi('Api', {\n path: '${options.apiPath}',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one.\n logger,\n}).auth(auth);\n`,\n\t});\n\n\tconst variant =\n\t\tfrontendFramework === 'tanstack-start'\n\t\t\t? \"{ path: 'apps/web', variant: 'tanstack' }\"\n\t\t\t: frontendFramework === 'expo'\n\t\t\t\t? undefined\n\t\t\t\t: \"{ path: 'apps/web', variant: 'next' }\";\n\n\tif (frontendFramework === 'expo') {\n\t\tfiles.push({\n\t\t\tpath: 'constructs/app.ts',\n\t\t\tcontent: `import { MobileApp } from '@geekmidas/constructs/mobile-app';\nimport { api } from './api.ts';\nimport { auth } from './auth.ts';\n\n/**\n * The mobile app — a construct like a site, which is what makes it an app.\n *\n * \\`.dependsOn()\\` is the single fact behind what a mobile app otherwise has\n * written down by hand: its API and auth URLs, its URL scheme, the\n * scheme in the auth server's trusted origins, Better Auth's Expo plugin, and\n * sign-in links a phone can open.\n */\nexport const app = new MobileApp('App', { path: 'apps/app' }).dependsOn([\n api,\n auth,\n]);\n`,\n\t\t});\n\t}\n\n\tif (variant !== undefined) {\n\t\tfiles.push({\n\t\t\tpath: 'constructs/site.ts',\n\t\t\tcontent: `import { StaticSite } from '@geekmidas/constructs/site';\nimport { api } from './api.ts';\nimport { auth } from './auth.ts';\n\n/**\n * The frontend — a construct like any other, which is what makes it an app.\n *\n * \\`path\\` is where it lives. \\`.dependsOn()\\` is the single fact\n * behind four things that are hand-maintained otherwise: this site's\n * build-time API URL, the API's CORS origins, the auth server's trusted\n * origins, and which generated client lands here.\n */\nexport const web = new StaticSite('Web', ${variant}).dependsOn([api, auth]);\n`,\n\t\t});\n\t}\n\n\tif (uploads) {\n\t\tconst bucket = storageFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/storage.ts',\n\t\t\tcontent: `import { ObjectStorage } from '@geekmidas/constructs/object-storage';\n\n/** A bucket — MinIO locally, S3 deployed, one declaration for both. */\nexport const uploads = new ObjectStorage('${bucket.id}');\n`,\n\t\t});\n\t}\n\n\tif (mail) {\n\t\tconst mail = emailFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/email.ts',\n\t\t\tcontent: `import { Email } from '@geekmidas/constructs/email';\n\n/** Outbound mail — Mailpit locally, SES deployed. */\nexport const email = new Email('${mail.id}', { templates: {} });\n`,\n\t\t});\n\t}\n\n\tif (cache) {\n\t\tconst kv = cacheFor();\n\t\tfiles.push({\n\t\t\tpath: 'constructs/cache.ts',\n\t\t\tcontent: `import { Cache } from '@geekmidas/constructs/cache';\n\n/**\n * A cache. Which backend serves it follows the deploy target — a table in the\n * database on a server, Upstash on AWS — so nothing here says where it lives.\n */\nexport const cache = new Cache('${kv.id}');\n`,\n\t\t});\n\t}\n\n\treturn files;\n}\n","import { DEPENDENCY_VERSIONS, PNPM_VERSION } from '../dependencies.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate package.json with dependencies based on template and options\n */\nexport function generatePackageJson(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { name, telescope, monorepo } = options;\n\tconst { database, cache, uploads, mail } = options.constructs;\n\n\t// Start with template dependencies\n\tconst dependencies = { ...template.dependencies };\n\tconst devDependencies = { ...template.devDependencies };\n\tconst scripts = { ...template.scripts };\n\n\t// The logger the scaffold imports is `@geekmidas/logger/<loggerType>`, and\n\t// only the pino one needs pino installed beside it.\n\tif (options.loggerType === 'pino') {\n\t\tdependencies.pino = DEPENDENCY_VERSIONS.pino;\n\t}\n\n\t// Add optional dependencies based on user choices\n\tif (telescope) {\n\t\tdependencies['@geekmidas/telescope'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/telescope'];\n\t}\n\n\t// Only a project that declares constructs needs them. The workspace path\n\t// still reaches its infrastructure through hand-written services.\n\tconst declares = !monorepo;\n\n\t// Every construct resolves its env key through the manifest, so declaring\n\t// one at all is what needs this — not any particular kind.\n\tif (declares && (database || uploads || cache || mail)) {\n\t\tdependencies['@geekmidas/manifest'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/manifest'];\n\t}\n\n\t// A construct hands back a client from the package that owns it, and each of\n\t// those is an optional peer — an app that declares no bucket resolves no S3\n\t// SDK. Installed here because the app declared one.\n\tif (declares && uploads) {\n\t\tdependencies['@geekmidas/storage'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/storage'];\n\t}\n\n\tif (declares && cache) {\n\t\tdependencies['@geekmidas/cache'] = GEEKMIDAS_VERSIONS['@geekmidas/cache'];\n\t}\n\n\tif (declares && mail) {\n\t\tdependencies['@geekmidas/emailkit'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/emailkit'];\n\t}\n\n\tif (database) {\n\t\tdependencies['@geekmidas/db'] = GEEKMIDAS_VERSIONS['@geekmidas/db'];\n\t\tdependencies.kysely = DEPENDENCY_VERSIONS.kysely;\n\t\tdependencies.pg = DEPENDENCY_VERSIONS.pg;\n\t\tdevDependencies['@types/pg'] = DEPENDENCY_VERSIONS['@types/pg'];\n\t\tdevDependencies['@geekmidas/testkit'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/testkit'];\n\t\tdevDependencies['@faker-js/faker'] = DEPENDENCY_VERSIONS['@faker-js/faker'];\n\t}\n\n\t// For monorepo apps, remove biome/turbo/esbuild (they're at root) and lint/fmt scripts\n\t// zod is at root level for monorepos\n\tif (monorepo) {\n\t\tdelete devDependencies['@biomejs/biome'];\n\t\tdelete devDependencies.turbo;\n\t\tdelete devDependencies.esbuild;\n\t\tdelete dependencies.zod;\n\t\tdelete scripts.lint;\n\t\tdelete scripts.fmt;\n\t\tdelete scripts['fmt:check'];\n\n\t\t// Add models package as dependency\n\t\tdependencies[`@${name}/models`] = 'workspace:*';\n\t}\n\n\t// Sort dependencies alphabetically\n\tconst sortObject = (obj: Record<string, string>) =>\n\t\tObject.fromEntries(\n\t\t\tObject.entries(obj).sort(([a], [b]) => a.localeCompare(b)),\n\t\t);\n\n\t// For monorepo, derive package name from apiPath (e.g., apps/api -> @name/api)\n\tlet packageName = name;\n\tif (monorepo && options.apiPath) {\n\t\tconst pathParts = options.apiPath.split('/');\n\t\tconst appName = pathParts[pathParts.length - 1] || 'api';\n\t\tpackageName = `@${name}/${appName}`;\n\t}\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\t// A workspace's root carries this; a standalone app is its own root.\n\t\t...(!monorepo && options.packageManager === 'pnpm'\n\t\t\t? { packageManager: PNPM_VERSION }\n\t\t\t: {}),\n\t\tscripts,\n\t\tdependencies: sortObject(dependencies),\n\t\tdevDependencies: sortObject(devDependencies),\n\t};\n\n\treturn [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t];\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate source files from template\n */\nexport function generateSourceFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\treturn template.files(options);\n}\n","import { kebabCase, serviceKey } from '@geekmidas/manifest';\nimport { databaseFor } from '../constructs.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate test infrastructure files when database is enabled: the\n * transaction-isolated test config and an example spec, in the app. The\n * factory is the project's — see {@link generateTestFactoryFiles}.\n */\nexport function generateTestFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.constructs.database) {\n\t\treturn [];\n\t}\n\n\t// The keys the declared database publishes. Migrations connect as the owner\n\t// role — the one that may create, alter, and drop; a handler is never given\n\t// it, which is the security property the role split exists for.\n\tconst db = databaseFor();\n\n\t// Single-app projects have no `~/*` alias, so what a test file imports\n\t// depends on where it will sit.\n\tconst declares = !options.monorepo;\n\tconst schema = declares\n\t\t? '../src/constructs/database.ts'\n\t\t: `@${options.name}/constructs/database.ts`;\n\n\t// Both layouts declare the same database, so both publish the same keys. A\n\t// monorepo used to read a per-app secret here instead, and rendered the\n\t// owner key as the runtime one — so its migrations ran as the role that may\n\t// create nothing, and failed on the first table.\n\tconst runtimeUrl = db.urlKey;\n\tconst ownerUrl = db.ownerUrlKey;\n\n\treturn [\n\t\t// test/config.ts - Wraps vitest `it` with transaction auto-rollback\n\t\t{\n\t\t\tpath: 'test/config.ts',\n\t\t\tcontent: `import { it as itVitest } from 'vitest';\nimport { wrapVitestKyselyTransaction } from '@geekmidas/testkit/kysely';\nimport { type Database, database } from '${schema}';\n\nexport const it = wrapVitestKyselyTransaction<Database>(itVitest, {\n // The construct itself, so the tests connect the way the app does — with\n // the plugins it was given, \\`CamelCasePlugin\\` included.\n connection: database,\n});\n`,\n\t\t},\n\n\t\t// test/example.spec.ts - Example test showing usage\n\t\t{\n\t\t\tpath: 'test/example.spec.ts',\n\t\t\tcontent: `import { describe, expect } from 'vitest';\nimport { it } from './config.ts';\n\ndescribe('example', () => {\n it('should have a working test setup', async ({ trx }) => {\n // trx is a Kysely transaction; everything in it is rolled back after the\n // test\n expect(trx).toBeDefined();\n });\n});\n`,\n\t\t},\n\t];\n}\n\n/**\n * The database's test factory, at the project root:\n * `test/factories/<construct>.ts`.\n *\n * A factory belongs to a database, not to an app, so there is one per database\n * for the whole project. `gkm test` finds it by that name and hands every\n * feature test \\`factories.get('database')\\`, built on the test's transaction.\n */\nexport function generateTestFactoryFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.constructs.database) {\n\t\treturn [];\n\t}\n\n\tconst db = databaseFor();\n\t// From the project root. A fullstack monorepo declares its constructs at\n\t// the root and maps them through the root tsconfig; an API monorepo keeps\n\t// them in the app, and a single app under `src/`.\n\tconst schema =\n\t\toptions.monorepo && options.template === 'fullstack'\n\t\t\t? `@${options.name}/constructs/database.ts`\n\t\t\t: options.monorepo\n\t\t\t\t? `../../${options.apiPath}/src/constructs/database.ts`\n\t\t\t\t: '../../src/constructs/database.ts';\n\n\treturn [\n\t\t{\n\t\t\tpath: `test/factories/${kebabCase(db.id)}.ts`,\n\t\t\tcontent: `import type { Kysely } from 'kysely';\nimport { KyselyFactory } from '@geekmidas/testkit/kysely';\nimport type { Database } from '${schema}';\n\nconst usersBuilder = KyselyFactory.createBuilder<Database, 'users'>(\n 'users',\n ({ faker }) => ({\n id: faker.string.uuid(),\n name: faker.person.fullName(),\n email: faker.internet.email(),\n createdAt: new Date(),\n }),\n);\n\nconst builders = { users: usersBuilder };\nconst seeds = {};\n\n/**\n * This database's factory. \\`gkm test\\` builds it on each feature test's\n * transaction and hands it over as \\`factories.get('${serviceKey(db.id)}')\\`.\n */\nexport function createFactory(db: Kysely<Database>) {\n return new KyselyFactory<Database, typeof builders, typeof seeds>(\n builders,\n seeds,\n db,\n );\n}\n\nexport type Factory = ReturnType<typeof createFactory>;\n`,\n\t\t},\n\t];\n}\n","import { DEPENDENCY_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile } from '../templates/index.js';\n\n/**\n * shadcn/ui components, written into the web app that uses them.\n *\n * shadcn is copy-in by design: the components are the app's own source, to\n * edit and add to with `npx shadcn@latest add`. A shared workspace package of\n * them was one more package to build and version for code only the web app\n * imported.\n */\n\n/** What the components below import. */\nexport const SHADCN_DEPENDENCIES = {\n\t'@radix-ui/react-dialog': DEPENDENCY_VERSIONS['@radix-ui/react-dialog'],\n\t'@radix-ui/react-label': DEPENDENCY_VERSIONS['@radix-ui/react-label'],\n\t'@radix-ui/react-separator': DEPENDENCY_VERSIONS['@radix-ui/react-separator'],\n\t'@radix-ui/react-slot': DEPENDENCY_VERSIONS['@radix-ui/react-slot'],\n\t'@radix-ui/react-tabs': DEPENDENCY_VERSIONS['@radix-ui/react-tabs'],\n\t'@radix-ui/react-tooltip': DEPENDENCY_VERSIONS['@radix-ui/react-tooltip'],\n\t'class-variance-authority': DEPENDENCY_VERSIONS['class-variance-authority'],\n\tclsx: DEPENDENCY_VERSIONS['clsx'],\n\t'lucide-react': DEPENDENCY_VERSIONS['lucide-react'],\n\t'tailwind-merge': DEPENDENCY_VERSIONS['tailwind-merge'],\n} as const;\n\n/**\n * Tailwind v4 with the shadcn theme tokens — the stylesheet the app imports\n * once, at its root.\n */\nexport const SHADCN_GLOBALS_CSS = `@import \"tailwindcss\";\n\n@theme {\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 0 0% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 0 0% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 0 0% 3.9%;\n --primary: 160 84% 39%;\n --primary-foreground: 0 0% 98%;\n --secondary: 0 0% 96.1%;\n --secondary-foreground: 0 0% 9%;\n --muted: 0 0% 96.1%;\n --muted-foreground: 0 0% 45.1%;\n --accent: 0 0% 96.1%;\n --accent-foreground: 0 0% 9%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 89.8%;\n --input: 0 0% 89.8%;\n --ring: 160 84% 39%;\n --radius: 0.5rem;\n }\n\n .dark {\n --background: 0 0% 9%;\n --foreground: 0 0% 98%;\n --card: 0 0% 11%;\n --card-foreground: 0 0% 98%;\n --popover: 0 0% 11%;\n --popover-foreground: 0 0% 98%;\n --primary: 160 84% 52%;\n --primary-foreground: 0 0% 9%;\n --secondary: 0 0% 15%;\n --secondary-foreground: 0 0% 98%;\n --muted: 0 0% 15%;\n --muted-foreground: 0 0% 64%;\n --accent: 0 0% 15%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 50.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 18%;\n --input: 0 0% 18%;\n --ring: 160 84% 52%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n`;\n\n/**\n * The components, `cn`, and the `components.json` that tells the shadcn CLI\n * where they live.\n *\n * @param appDir the web app, relative to the workspace root (`apps/web`)\n * @param css the stylesheet holding {@link SHADCN_GLOBALS_CSS}, relative to\n * the app\n * @param options.rsc whether the app renders React Server Components, so\n * `shadcn add` marks what it writes `'use client'`. The radix-based\n * components here carry the directive either way; outside RSC it is inert.\n */\nexport function shadcnFiles(\n\tappDir: string,\n\tcss: string,\n\toptions: { rsc: boolean },\n): GeneratedFile[] {\n\tconst componentsJson = {\n\t\t$schema: 'https://ui.shadcn.com/schema.json',\n\t\tstyle: 'new-york',\n\t\trsc: options.rsc,\n\t\ttsx: true,\n\t\ttailwind: {\n\t\t\tconfig: '',\n\t\t\tcss,\n\t\t\tbaseColor: 'neutral',\n\t\t\tcssVariables: true,\n\t\t\tprefix: '',\n\t\t},\n\t\taliases: {\n\t\t\tcomponents: '~/components',\n\t\t\tutils: '~/lib/utils',\n\t\t\tui: '~/components/ui',\n\t\t\tlib: '~/lib',\n\t\t\thooks: '~/hooks',\n\t\t},\n\t\ticonLibrary: 'lucide',\n\t};\n\tconst utilsTs = `import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`;\n\n\tconst buttonTsx = `import { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n default:\n 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button';\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n`;\n\n\tconst inputTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = 'Input';\n\nexport { Input };\n`;\n\n\tconst cardTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-xl border bg-card text-card-foreground shadow',\n className,\n )}\n {...props}\n />\n));\nCard.displayName = 'Card';\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-1.5 p-6', className)}\n {...props}\n />\n));\nCardHeader.displayName = 'CardHeader';\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-semibold leading-none tracking-tight', className)}\n {...props}\n />\n));\nCardTitle.displayName = 'CardTitle';\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n));\nCardDescription.displayName = 'CardDescription';\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />\n));\nCardContent.displayName = 'CardContent';\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center p-6 pt-0', className)}\n {...props}\n />\n));\nCardFooter.displayName = 'CardFooter';\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };\n`;\n\n\tconst labelTsx = `'use client';\n\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(labelVariants(), className)}\n {...props}\n />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n`;\n\n\tconst badgeTsx = `import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst badgeVariants = cva(\n 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',\n {\n variants: {\n variant: {\n default:\n 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',\n secondary:\n 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',\n destructive:\n 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',\n outline: 'text-foreground',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\nfunction Badge({ className, variant, ...props }: BadgeProps) {\n return (\n <div className={cn(badgeVariants({ variant }), className)} {...props} />\n );\n}\n\nexport { Badge, badgeVariants };\n`;\n\n\tconst separatorTsx = `'use client';\n\nimport * as SeparatorPrimitive from '@radix-ui/react-separator';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Separator = React.forwardRef<\n React.ElementRef<typeof SeparatorPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(\n (\n { className, orientation = 'horizontal', decorative = true, ...props },\n ref,\n ) => (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative={decorative}\n orientation={orientation}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className,\n )}\n {...props}\n />\n ),\n);\nSeparator.displayName = SeparatorPrimitive.Root.displayName;\n\nexport { Separator };\n`;\n\n\tconst tabsTsx = `'use client';\n\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Tabs = TabsPrimitive.Root;\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n 'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n className,\n )}\n {...props}\n />\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n`;\n\n\tconst tooltipTsx = `'use client';\n\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n`;\n\n\tconst dialogTsx = `'use client';\n\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { X } from 'lucide-react';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Dialog = DialogPrimitive.Root;\n\nconst DialogTrigger = DialogPrimitive.Trigger;\n\nconst DialogPortal = DialogPrimitive.Portal;\n\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n className,\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',\n className,\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n 'flex flex-col space-y-1.5 text-center sm:text-left',\n className,\n )}\n {...props}\n />\n);\nDialogHeader.displayName = 'DialogHeader';\n\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n className,\n )}\n {...props}\n />\n);\nDialogFooter.displayName = 'DialogFooter';\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-lg font-semibold leading-none tracking-tight',\n className,\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogTrigger,\n DialogClose,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n};\n`;\n\n\tconst components: Record<string, string> = {\n\t\tbutton: buttonTsx,\n\t\tinput: inputTsx,\n\t\tcard: cardTsx,\n\t\tlabel: labelTsx,\n\t\tbadge: badgeTsx,\n\t\tseparator: separatorTsx,\n\t\ttabs: tabsTsx,\n\t\ttooltip: tooltipTsx,\n\t\tdialog: dialogTsx,\n\t};\n\n\treturn [\n\t\t{\n\t\t\tpath: `${appDir}/components.json`,\n\t\t\tcontent: `${JSON.stringify(componentsJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: `${appDir}/src/lib/utils.ts`, content: utilsTs },\n\t\t...Object.entries(components).map(([name, content]) => ({\n\t\t\tpath: `${appDir}/src/components/ui/${name}.tsx`,\n\t\t\tcontent,\n\t\t})),\n\t];\n}\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport {\n\tSHADCN_DEPENDENCIES,\n\tSHADCN_GLOBALS_CSS,\n\tshadcnFiles,\n} from './shadcn.js';\n\n/**\n * Generate Next.js web app files for fullstack template\n */\nexport function generateWebAppFiles(options: TemplateOptions): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\t// package.json for web app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- next dev --turbopack',\n\t\t\tbuild: 'gkm exec -- next build',\n\t\t\tstart: 'next start',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t...SHADCN_DEPENDENCIES,\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\tnext: DEPENDENCY_VERSIONS['next'],\n\t\t\treact: DEPENDENCY_VERSIONS['react'],\n\t\t\t'react-dom': DEPENDENCY_VERSIONS['react-dom'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/postcss': DEPENDENCY_VERSIONS['@tailwindcss/postcss'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/react': DEPENDENCY_VERSIONS['@types/react'],\n\t\t\t'@types/react-dom': DEPENDENCY_VERSIONS['@types/react-dom'],\n\t\t\ttailwindcss: DEPENDENCY_VERSIONS['tailwindcss'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t},\n\t};\n\n\t// next.config.ts\n\tconst nextConfig = `import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n output: 'standalone',\n reactStrictMode: true,\n transpilePackages: ['${modelsPackage}'],\n};\n\nexport default nextConfig;\n`;\n\n\t// postcss.config.mjs for Tailwind v4\n\tconst postcssConfig = `export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n};\n`;\n\n\t// tsconfig.json for Next.js\n\t// Note: Next.js handles compilation, so noEmit: true\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\tplugins: [\n\t\t\t\t{\n\t\t\t\t\tname: 'next',\n\t\t\t\t},\n\t\t\t],\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t\t[`${modelsPackage}`]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],\n\t\texclude: ['node_modules'],\n\t\t// No project `references`: the `paths` above already point at the\n\t\t// sources, and a reference to a project that is not `composite` makes\n\t\t// `tsc --noEmit` — the app's `typecheck` — an error.\n\t};\n\n\t// Query client singleton for browser, fresh instance for server\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n if (typeof window === 'undefined') {\n // Server: always make a new query client\n return makeQueryClient();\n }\n // Browser: reuse existing query client\n if (!browserQueryClient) browserQueryClient = makeQueryClient();\n return browserQueryClient;\n}\n`;\n\n\t// Client config - NEXT_PUBLIC_* vars (available in browser)\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - only NEXT_PUBLIC_* vars (available in browser)\n// These values are inlined at build time by Next.js\nconst envParser = new EnvironmentParser({\n NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,\n NEXT_PUBLIC_AUTH_URL: process.env.NEXT_PUBLIC_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n .create((get) => ({\n apiUrl: get('NEXT_PUBLIC_API_URL').string(),\n authUrl: get('NEXT_PUBLIC_AUTH_URL').string(),\n }))\n .parse();\n`;\n\n\t// Server config - server-only vars (not available in browser)\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser)\n// Access these only in Server Components, Route Handlers, or Server Actions\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n .create((get) => ({\n // Add server-only secrets here\n // Example: stripeSecretKey: get('STRIPE_SECRET_KEY').string(),\n }))\n .parse();\n`;\n\n\t// Auth client for better-auth\n\tconst authClientTs = `import { createAuthClient } from 'better-auth/react';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n baseURL: clientConfig.authUrl,\n plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\t// Providers using shared QueryClient\n\tconst providersTsx = `'use client';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n const queryClient = getQueryClient();\n\n return (\n <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n );\n}\n`;\n\n\t// API client setup - imports directly from the API package export\n\tconst apiIndexTs = `import { createApi } from '@${options.name}/client/api';\nimport { getQueryClient } from '~/lib/query-client.ts';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const api = createApi({\n baseURL: clientConfig.apiUrl,\n queryClient: getQueryClient(),\n});\n`;\n\n\t// App layout\n\tconst layoutTsx = `import type { Metadata } from 'next';\nimport { Providers } from './providers.tsx';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n title: '${options.name}',\n description: 'Created with gkm init',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"en\">\n <body>\n <Providers>{children}</Providers>\n </body>\n </html>\n );\n}\n`;\n\n\t// Home page with API example using the app's own shadcn components\n\tconst pageTsx = `import { api } from '~/api/index.ts';\nimport { Button } from '~/components/ui/button.tsx';\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '~/components/ui/card.tsx';\n\nexport default async function Home() {\n // Type-safe API call using the generated client\n const health = await api('GET /health').catch(() => null);\n\n return (\n <main className=\"min-h-screen bg-background p-8\">\n <div className=\"mx-auto max-w-4xl space-y-8\">\n <div className=\"space-y-2\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Welcome to ${options.name}</h1>\n <p className=\"text-muted-foreground\">Your fullstack application is ready.</p>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>API Status</CardTitle>\n <CardDescription>Connection to your backend API</CardDescription>\n </CardHeader>\n <CardContent>\n {health ? (\n <pre className=\"rounded-lg bg-muted p-4 text-sm\">\n {JSON.stringify(health, null, 2)}\n </pre>\n ) : (\n <p className=\"text-destructive\">Unable to connect to API</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Next Steps</CardTitle>\n <CardDescription>Get started with your project</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <ul className=\"list-inside list-disc space-y-2 text-muted-foreground\">\n <li>Run <code className=\"rounded bg-muted px-1\">gkm openapi</code> to generate typed API client</li>\n <li>Edit <code className=\"rounded bg-muted px-1\">apps/web/src/app/page.tsx</code> to customize this page</li>\n <li>Add API routes in <code className=\"rounded bg-muted px-1\">apps/api/src/endpoints/</code></li>\n <li>Add UI components with <code className=\"rounded bg-muted px-1\">npx shadcn@latest add</code> in apps/web</li>\n </ul>\n <div className=\"flex gap-4\">\n <Button>Get Started</Button>\n <Button variant=\"outline\">Documentation</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n </main>\n );\n}\n`;\n\n\t// .gitignore for Next.js\n\tconst gitignore = `.next/\nnode_modules/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/next.config.ts',\n\t\t\tcontent: nextConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/postcss.config.mjs',\n\t\t\tcontent: postcssConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/globals.css',\n\t\t\tcontent: SHADCN_GLOBALS_CSS,\n\t\t},\n\t\t...shadcnFiles('apps/web', 'src/app/globals.css', { rsc: true }),\n\t\t{\n\t\t\tpath: 'apps/web/src/app/layout.tsx',\n\t\t\tcontent: layoutTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/providers.tsx',\n\t\t\tcontent: providersTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/page.tsx',\n\t\t\tcontent: pageTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/client.ts',\n\t\t\tcontent: clientConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/server.ts',\n\t\t\tcontent: serverConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/query-client.ts',\n\t\t\tcontent: queryClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/auth-client.ts',\n\t\t\tcontent: authClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/api/index.ts',\n\t\t\tcontent: apiIndexTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport {\n\tSHADCN_DEPENDENCIES,\n\tSHADCN_GLOBALS_CSS,\n\tshadcnFiles,\n} from './shadcn.js';\n\n/**\n * Generate TanStack Start web app files for the fullstack template.\n *\n * Mirrors the Next.js scaffold (apps/web) but on Vite + TanStack Start +\n * TanStack Router with the `VITE_` env-var convention.\n */\nexport function generateTanStackWebFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- vite dev',\n\t\t\tbuild: 'gkm exec -- vite build',\n\t\t\tstart: 'node .output/server/index.mjs',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t...SHADCN_DEPENDENCIES,\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': DEPENDENCY_VERSIONS['@tanstack/react-query'],\n\t\t\t'@tanstack/react-router': DEPENDENCY_VERSIONS['@tanstack/react-router'],\n\t\t\t'@tanstack/react-start': DEPENDENCY_VERSIONS['@tanstack/react-start'],\n\t\t\t'better-auth': DEPENDENCY_VERSIONS['better-auth'],\n\t\t\treact: DEPENDENCY_VERSIONS['react'],\n\t\t\t'react-dom': DEPENDENCY_VERSIONS['react-dom'],\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/vite': DEPENDENCY_VERSIONS['@tailwindcss/vite'],\n\t\t\t'@tanstack/router-plugin': DEPENDENCY_VERSIONS['@tanstack/router-plugin'],\n\t\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\t\t'@types/react': DEPENDENCY_VERSIONS['@types/react'],\n\t\t\t'@types/react-dom': DEPENDENCY_VERSIONS['@types/react-dom'],\n\t\t\t'@vitejs/plugin-react': TOOLCHAIN_VERSIONS['@vitejs/plugin-react'],\n\t\t\ttailwindcss: DEPENDENCY_VERSIONS['tailwindcss'],\n\t\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\t\tvite: TOOLCHAIN_VERSIONS['vite'],\n\t\t},\n\t};\n\n\tconst viteConfig = `import { Credentials } from '@geekmidas/envkit/credentials';\nimport tailwindcss from '@tailwindcss/vite';\nimport { tanstackStart } from '@tanstack/react-start/plugin/vite';\nimport viteReact from '@vitejs/plugin-react';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n // Vite resolves tsconfig \\`paths\\` itself; no plugin needed.\n resolve: { tsconfigPaths: true },\n server: {\n port: Number(Credentials.PORT ?? 3001),\n },\n // VITE_* vars are inlined automatically; no manual loadEnv needed.\n envPrefix: 'VITE_',\n plugins: [\n tailwindcss(),\n tanstackStart(),\n viteReact(),\n ],\n});\n`;\n\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\ttypes: ['vite/client'],\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t// Every API's client, generated at the workspace root.\n\t\t\t\t[`@${options.name}/client/*`]: ['../../.gkm/client/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['**/*.ts', '**/*.tsx', 'src/routeTree.gen.ts'],\n\t\texclude: ['node_modules', '.output', '.vinxi', 'dist'],\n\t};\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n },\n },\n });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n if (typeof window === 'undefined') {\n return makeQueryClient();\n }\n if (!browserQueryClient) browserQueryClient = makeQueryClient();\n return browserQueryClient;\n}\n`;\n\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - VITE_* vars are inlined at build time.\nconst envParser = new EnvironmentParser({\n VITE_API_URL: import.meta.env.VITE_API_URL,\n VITE_AUTH_URL: import.meta.env.VITE_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n .create((get) => ({\n apiUrl: get('VITE_API_URL').string(),\n authUrl: get('VITE_AUTH_URL').string(),\n }))\n .parse();\n`;\n\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser).\n// Access these only in TanStack Start server functions / server routes.\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n .create((_get) => ({\n // Add server-only secrets here\n // Example: stripeSecretKey: _get('STRIPE_SECRET_KEY').string(),\n }))\n .parse();\n`;\n\n\tconst authClientTs = `import { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n baseURL: clientConfig.authUrl,\n plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\tconst apiIndexTs = `import { createApi } from '@${options.name}/client/api';\nimport { clientConfig } from '~/config/client.ts';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n return createApi({\n baseURL: clientConfig.apiUrl,\n queryClient: getQueryClient(),\n headers: options?.headers,\n onRequest: (config) => ({ ...config, credentials: 'include' }),\n });\n}\n\nexport const api = createAppApi();\n`;\n\n\tconst routerTs = `import { createRouter } from '@tanstack/react-router';\nimport { routeTree } from './routeTree.gen.ts';\n\nexport function getRouter() {\n return createRouter({\n routeTree,\n scrollRestoration: true,\n defaultPreload: 'intent',\n });\n}\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: ReturnType<typeof getRouter>;\n }\n}\n`;\n\n\t// Placeholder routeTree.gen — TanStack's plugin regenerates this on dev.\n\tconst routeTreeGen = `// This file is auto-generated by @tanstack/router-plugin.\n// It will be overwritten on the next \\`vite dev\\` run.\nimport { rootRouteWithContext } from '@tanstack/react-router';\n\nexport const routeTree = rootRouteWithContext()({\n // Routes are populated by the plugin from src/routes/**.tsx\n} as never);\n`;\n\n\tconst rootRouteTsx = `/// <reference types=\"vite/client\" />\nimport '~/styles/globals.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport {\n HeadContent,\n Outlet,\n Scripts,\n createRootRoute,\n} from '@tanstack/react-router';\nimport type { ReactNode } from 'react';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport const Route = createRootRoute({\n head: () => ({\n meta: [\n { charSet: 'utf-8' },\n { name: 'viewport', content: 'width=device-width, initial-scale=1' },\n { title: '${options.name}' },\n ],\n }),\n component: RootComponent,\n});\n\nfunction RootComponent() {\n const queryClient = getQueryClient();\n return (\n <RootDocument>\n <QueryClientProvider client={queryClient}>\n <Outlet />\n </QueryClientProvider>\n </RootDocument>\n );\n}\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n return (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n {children}\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n\n\tconst indexRouteTsx = `import { createFileRoute } from '@tanstack/react-router';\nimport { api } from '~/api/index.ts';\n\nexport const Route = createFileRoute('/')({\n component: HomeComponent,\n});\n\nfunction HomeComponent() {\n const { data: health } = api.useQuery('GET /health', {});\n\n return (\n <main className=\"min-h-screen bg-background p-8\">\n <div className=\"mx-auto max-w-4xl space-y-8\">\n <div className=\"space-y-2\">\n <h1 className=\"text-4xl font-bold tracking-tight\">\n Welcome to ${options.name}\n </h1>\n <p className=\"text-muted-foreground\">\n Your TanStack Start app is ready.\n </p>\n </div>\n\n <section className=\"rounded-lg border p-6\">\n <h2 className=\"text-xl font-semibold\">API Status</h2>\n {health ? (\n <pre className=\"mt-4 rounded bg-muted p-4 text-sm\">\n {JSON.stringify(health, null, 2)}\n </pre>\n ) : (\n <p className=\"mt-2 text-muted-foreground\">Connecting…</p>\n )}\n </section>\n </div>\n </main>\n );\n}\n`;\n\n\tconst globalsCss = `${SHADCN_GLOBALS_CSS}\n@source \"../..\";\n`;\n\n\tconst gitignore = `.output/\n.vinxi/\nnode_modules/\n.env.local\n*.log\nsrc/routeTree.gen.ts\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/vite.config.ts', content: viteConfig },\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/src/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/web/src/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/web/src/config/client.ts', content: clientConfigTs },\n\t\t{ path: 'apps/web/src/config/server.ts', content: serverConfigTs },\n\t\t{ path: 'apps/web/src/api/index.ts', content: apiIndexTs },\n\t\t{ path: 'apps/web/src/router.tsx', content: routerTs },\n\t\t{ path: 'apps/web/src/routeTree.gen.ts', content: routeTreeGen },\n\t\t{ path: 'apps/web/src/routes/__root.tsx', content: rootRouteTsx },\n\t\t{ path: 'apps/web/src/routes/index.tsx', content: indexRouteTsx },\n\t\t{ path: 'apps/web/src/styles/globals.css', content: globalsCss },\n\t\t...shadcnFiles('apps/web', 'src/styles/globals.css', { rsc: false }),\n\t\t{ path: 'apps/web/.gitignore', content: gitignore },\n\t];\n}\n","import {\n\tcacheFor,\n\tdatabaseFiles,\n\tdatabaseFor,\n\temailFor,\n\tstorageFor,\n} from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const apiTemplate: TemplateConfig = {\n\tname: 'api',\n\tdescription: 'Full API with auth, database, services',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@geekmidas/services': GEEKMIDAS_VERSIONS['@geekmidas/services'],\n\t\t'@geekmidas/errors': GEEKMIDAS_VERSIONS['@geekmidas/errors'],\n\t\t'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure, monorepo, name } = options;\n\t\tconst { cache, uploads, mail: sendsMail } = options.constructs;\n\n\t\t// The ids and env keys the scaffolded constructs own. Derived, so the\n\t\t// files below and the runtime that discovers them cannot disagree.\n\t\tconst bucket = storageFor();\n\t\tconst kv = cacheFor();\n\t\tconst db = databaseFor();\n\t\tconst mail = emailFor();\n\n\t\t// Every layout's tsconfig maps `~/*` to `src/*`, so a generated file\n\t\t// imports through it wherever it sits. A single app wrote `./router.ts`\n\t\t// from `src/endpoints/…`, which named a file that is not there.\n\t\tconst src = (path: string) => `~/${path}`;\n\n\t\t// Whether this app declares its infrastructure.\n\t\t//\n\t\t// Single-app projects do: the config gets a `constructs` glob, reconcile\n\t\t// derives their containers, and the handler reaches them by edge. The\n\t\t// fullstack workspace does not yet — its auth app's database role is\n\t\t// created by `docker/postgres/init.sh` and its URL comes from a\n\t\t// per-app secret, neither of which reconcile knows about, so declaring\n\t\t// only the API's half would leave auth pointing at a container that is\n\t\t// no longer the one running.\n\t\t// In a workspace the constructs live at its root — `generateRootConstructs`\n\t\t// writes them — so the app declares none of its own and imports them\n\t\t// through the `@<name>/constructs/*` alias instead. A single-app project\n\t\t// has no root above it, so they stay in `src/constructs/`.\n\t\tconst declares = !monorepo;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Models package import path for monorepo\n\t\tconst modelsImport = monorepo ? `@${name}/models` : null;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based': {\n\t\t\t\t\tconst parts = file.split('/');\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t\t\t}\n\t\t\t\t\treturn `src/${parts[0]}/routes/${parts.slice(1).join('/')}`;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\t/**\n\t\t * Where a file at the app's `src/` root reaches a construct.\n\t\t *\n\t\t * A workspace keeps them at its own root, so the app goes through the\n\t\t * `@<name>/constructs/*` alias rather than climbing out with `../../`.\n\t\t */\n\t\tconst constructsImport = (file: string) =>\n\t\t\tmonorepo ? `@${name}/constructs/${file}.ts` : `./constructs/${file}.ts`;\n\n\t\tconst apiImport = monorepo\n\t\t\t? `@${name}/constructs/api.ts`\n\t\t\t: routesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t//\n\t\t\t// A workspace declares it at its root instead, beside the site and the\n\t\t\t// auth server that depend on it.\n\t\t\t...(declares\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: monorepo\n\t\t\t\t\t? `import { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const healthEndpoint = router\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '~/router.ts';\n\nexport const healthEndpoint = router\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n\t\t\t},\n\n\t\t\t// users endpoints\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/list.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { ListUsersResponseSchema } from '${modelsImport}/user';\nimport { router } from '${src('router.ts')}';\n\nexport const listUsersEndpoint = router\n .get('/users')\n .output(ListUsersResponseSchema)\n${\n\toptions.constructs.database\n\t\t? ` // \\`db\\` is here because the router named the database construct.\n .handle(async ({ db }) => ({\n users: await db.selectFrom('users').select(['id', 'name']).execute(),\n }));\n`\n\t\t: ` .handle(async () => ({\n users: [\n { id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },\n { id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },\n ],\n }));\n`\n}`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '${src('router.ts')}';\n\nconst UserSchema = z.object({\n id: z.string(),\n name: z.string(),\n});\n\nexport const listUsersEndpoint = router\n .get('/users')\n .output(z.object({\n users: z.array(UserSchema),\n }))\n${\n\toptions.constructs.database\n\t\t? ` // \\`db\\` is here because the router named the database construct.\n .handle(async ({ db }) => ({\n users: await db.selectFrom('users').select(['id', 'name']).execute(),\n }));\n`\n\t\t: ` .handle(async () => ({\n users: [\n { id: '1', name: 'Alice' },\n { id: '2', name: 'Bob' },\n ],\n }));\n`\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/get.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { IdParamsSchema } from '${modelsImport}/common';\nimport { UserResponseSchema } from '${modelsImport}/user';\nimport { router } from '${src('router.ts')}';\n\nexport const getUserEndpoint = router\n .get('/users/:id')\n .params(IdParamsSchema)\n .output(UserResponseSchema)\n .handle(async ({ params }) => ({\n id: params.id,\n name: 'Alice',\n email: 'alice@example.com',\n }));\n`\n\t\t\t\t\t: `import { z } from 'zod';\nimport { router } from '${src('router.ts')}';\n\nexport const getUserEndpoint = router\n .get('/users/:id')\n .params(z.object({ id: z.string() }))\n .output(z.object({\n id: z.string(),\n name: z.string(),\n email: z.email(),\n }))\n .handle(async ({ params }) => ({\n id: params.id,\n name: 'Alice',\n email: 'alice@example.com',\n }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The monorepo router: the API names the auth construct (`.auth(auth)` at\n\t\t// the root), so the session comes from it rather than a service that\n\t\t// fetches the auth server by hand.\n\t\tif (options.monorepo) {\n\t\t\t// Add router with session\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/router.ts',\n\t\t\t\tcontent: `import { UnauthorizedError } from '@geekmidas/errors';\nimport { api } from '${constructsImport('api')}';${\n\t\t\t\t\toptions.constructs.database\n\t\t\t\t\t\t? `\nimport { database } from '${constructsImport('database')}';`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\n\n/**\n * The shared endpoint factory — no session required.\n *${\n\t\toptions.constructs.database\n\t\t\t? `\n * Naming the database construct is what puts \\`db\\` in every handler built from\n * this router. Depend on other constructs per endpoint with \\`.dependsOn([…])\\`.`\n\t\t\t: `\n * Depend on constructs per endpoint with \\`.dependsOn([…])\\`.`\n }\n */\nexport const router = api${options.constructs.database ? '.database(database)' : ''};\n\n/**\n * Requires an active session — throws when there is none.\n *\n * \\`auth\\` is the construct named in \\`.auth()\\` on the API, bound to this\n * request: it asks the auth server whose cookie this is. Handlers built from\n * this router get whatever this returns as \\`session\\`.\n */\nexport const sessionRouter = router.session(async ({ auth }) => {\n const session = await auth.getSession();\n\n if (!session) {\n throw new UnauthorizedError('No active session');\n }\n\n return session;\n});\n`,\n\t\t\t});\n\n\t\t\t// Add protected endpoint example\n\t\t\tfiles.push({\n\t\t\t\tpath: getRoutePath('profile.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { sessionRouter } from '~/router.ts';\n\nexport const profileEndpoint = sessionRouter\n .get('/profile')\n .output(z.object({\n id: z.string(),\n email: z.string(),\n name: z.string(),\n }))\n .handle(async ({ session }) => session.user);\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The non-monorepo router. The monorepo one is written above, with the\n\t\t// session extractor its auth app needs.\n\t\tif (!monorepo) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/router.ts',\n\t\t\t\tcontent: `import { api } from '${constructsImport('api')}';${\n\t\t\t\t\toptions.constructs.database\n\t\t\t\t\t\t? `\nimport { database } from '${constructsImport('database')}';`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\n\n/**\n * The shared endpoint factory.\n *${\n\t\toptions.constructs.database\n\t\t\t? `\n * Naming the database construct is what puts \\`db\\` in every handler built from\n * this router. Depend on other constructs per endpoint with \\`.dependsOn([…])\\`.`\n\t\t\t: `\n * Depend on constructs per endpoint with \\`.dependsOn([…])\\`.`\n }\n */\nexport const router = api${options.constructs.database ? '.database(database)' : ''};\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The database — a construct, not a hand-written service. A workspace\n\t\t// declares it, and keeps its migrations, at its root.\n\t\tif (options.constructs.database && declares) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Object storage — MinIO locally, S3 deployed, one declaration for both.\n\t\tif (uploads && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/storage.ts',\n\t\t\t\tcontent: `import { ObjectStorage } from '@geekmidas/constructs/object-storage';\n\n/**\n * A bucket, declared once.\n *\n * Reach it from an endpoint with \\`.dependsOn([uploads])\\`, which is what makes\n * \\`services.${bucket.service}\\` exist and type — and what tells the deploy\n * target to grant that handler S3 access, and nothing else.\n */\nexport const uploads = new ObjectStorage('${bucket.id}');\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Mail. Mailpit locally, SES/Resend/SMTP deployed — one client either\n\t\t// way, because every backend speaks SMTP.\n\t\tif (sendsMail && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/email.ts',\n\t\t\t\tcontent: `import { Email } from '@geekmidas/constructs/email';\n\n/**\n * Outbound mail, declared once.\n *\n * Add React templates to \\`templates\\` and \\`sendTemplate\\` becomes typed\n * against them. Reach it with \\`.dependsOn([email])\\` for\n * \\`services.${mail.service}\\`. Who delivers it is whichever provider the\n * stage's \\`${mail.urlKey}\\` points at — every one of them speaks SMTP.\n */\nexport const email = new Email('${mail.id}', { templates: {} });\n`,\n\t\t\t});\n\t\t}\n\n\t\t// A cache. Where it lives when deployed follows from the deploy target;\n\t\t// the application code is the same either way.\n\t\tif (cache && declares) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/constructs/cache.ts',\n\t\t\t\tcontent: `import { Cache } from '@geekmidas/constructs/cache';\n\n/**\n * A cache, declared once.\n *\n * Reach it with \\`.dependsOn([cache])\\` for \\`services.${kv.service}\\`. This\n * form says the app caches and leaves *where* to the deployment: Upstash on\n * AWS, a table in the database on a server — the same code caches into\n * either.\n *\n * To say it caches in a particular database instead, declare it from that\n * database — \\`database.cache()\\` — and entries become a table in it, in its\n * schema and reached by its role, whatever the target.\n */\nexport const cache = new Cache('${kv.id}');\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles, databaseFor } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const minimalTemplate: TemplateConfig = {\n\tname: 'minimal',\n\tdescription: 'Basic health endpoint',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\tesbuild: TOOLCHAIN_VERSIONS['esbuild'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure, name } = options;\n\n\t\t// The id and env keys the scaffolded database owns.\n\t\tconst db = databaseFor();\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\tconst apiImport =\n\t\t\troutesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { api } from '${apiImport}';\n\nexport const healthEndpoint = api\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The database — a construct, not a hand-written service.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const serverlessTemplate: TemplateConfig = {\n\tname: 'serverless',\n\tdescription: 'AWS Lambda handlers',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/cloud': GEEKMIDAS_VERSIONS['@geekmidas/cloud'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': DEPENDENCY_VERSIONS['@hono/node-server'],\n\t\thono: DEPENDENCY_VERSIONS.hono,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/aws-lambda': DEPENDENCY_VERSIONS['@types/aws-lambda'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build --provider aws',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\t// Where an endpoint file reaches the surface from — one level deeper when\n\t\t// the routes are nested by domain.\n\t\tconst apiImport =\n\t\t\troutesStructure === 'domain-based'\n\t\t\t\t? '../../constructs/api.js'\n\t\t\t\t: '../constructs/api.js';\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The application's HTTP surface. Endpoints are built from it, so each\n\t\t\t// one carries the logger and environment parser its adaptor needs —\n\t\t\t// nothing has to be named in config and nothing printed into the\n\t\t\t// generated handler.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/api.ts',\n\t\t\t\tcontent: `import { RestApi } from '@geekmidas/constructs/rest-api';\nimport { logger } from '../config/logger.ts';\n\nexport const api = new RestApi('Api', {\n // The project is the app.\n path: '.',\n\n // Typed out rather than omitted: an API that ships open because a field was\n // left off is the one default worth refusing to have.\n defaultAuthorizer: 'none',\n\n // The actual logger, not a path to one. Every endpoint built from this\n // surface runs with it, and so does the generated entry.\n logger,\n});\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { api } from '${apiImport}';\n\nexport const healthEndpoint = api\n .get('/health')\n .output(z.object({\n status: z.string(),\n timestamp: z.string(),\n region: z.string(),\n }))\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n region: process.env.AWS_REGION || 'local',\n }));\n`,\n\t\t\t},\n\n\t\t\t// src/functions/hello.ts\n\t\t\t{\n\t\t\t\tpath: 'src/functions/hello.ts',\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { worker } from '~/constructs/worker.ts';\n\nexport const helloFunction = worker\n .input(z.object({ name: z.string() }))\n .output(z.object({ message: z.string() }))\n .handle(async ({ input }) => ({\n message: \\`Hello, \\${input.name}!\\`,\n }));\n`,\n\t\t\t},\n\t\t\t// The process the functions run in. A function says which one runs it\n\t\t\t// the same way an endpoint says which surface serves it.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/worker.ts',\n\t\t\t\tcontent: `import { Worker } from '@geekmidas/constructs/worker';\nimport { logger } from '../config/logger.ts';\n\nexport const worker = new Worker('Jobs', { logger });\n`,\n\t\t\t},\n\t\t];\n\n\t\t// The database, when this project has one. A `pgboss` events backend\n\t\t// implies one, which is why a worker gets here without asking for it.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\n// Note: For production Lambda, consider using a persistent storage\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 50 }),\n enabled: process.env.STAGE === '${options.stages.local}',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { databaseFiles } from '../constructs.js';\nimport { DEPENDENCY_VERSIONS, TOOLCHAIN_VERSIONS } from '../dependencies.js';\nimport { stageEnv } from '../generators/stages.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\n/**\n * A project that is background work and nothing else.\n *\n * It used to scaffold a `RestApi` with no endpoints on it — an HTTP surface\n * declared by a project whose premise is that nothing calls it over HTTP —\n * because a surface was the only construct that made an app exist and the only\n * way to get a logger into the generated runtime. `Worker` is the construct\n * that was missing: it takes no authorizer, publishes no address, and hands out\n * factories already carrying its logger.\n *\n * It scaffolds a cron when the project has a database, and not otherwise. A\n * server fires its own crons, and the schedule lives in Postgres so that\n * running more than one replica still fires each job once — so a worker names\n * the database it keeps schedules in. Without one there is nowhere to keep\n * them, and an example that could not run is worse than none.\n */\nexport const workerTemplate: TemplateConfig = {\n\tname: 'worker',\n\tdescription: 'Background job processing',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\tzod: DEPENDENCY_VERSIONS.zod,\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': DEPENDENCY_VERSIONS['@biomejs/biome'],\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': DEPENDENCY_VERSIONS['@types/node'],\n\t\ttsx: TOOLCHAIN_VERSIONS['tsx'],\n\t\tturbo: DEPENDENCY_VERSIONS['turbo'],\n\t\ttypescript: TOOLCHAIN_VERSIONS['typescript'],\n\t\tvitest: TOOLCHAIN_VERSIONS['vitest'],\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, name } = options;\n\t\tconst { database } = options.constructs;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// The process this project *is*: one with no port.\n\t\t\t//\n\t\t\t// Everything built from it carries this logger, so a subscriber file\n\t\t\t// opens with what it subscribes to rather than with an import of a\n\t\t\t// logger it has to know the path to.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/worker.ts',\n\t\t\t\tcontent: `import { Worker } from '@geekmidas/constructs/worker';\nimport { logger } from '../config/logger.ts';${database ? \"\\nimport { database } from './database.ts';\" : ''}\n\nexport const worker = new Worker('Jobs', { logger })${database ? '.database(database)' : ''};\n`,\n\t\t\t},\n\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n .create((get) => ({\n nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n stage: ${stageEnv(options.stages)},\n }))\n .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// The topic this worker subscribes to. Declaring it is what puts a\n\t\t\t// broker in the plan — no service names one, and nothing reads a\n\t\t\t// broker URL by hand.\n\t\t\t{\n\t\t\t\tpath: 'src/constructs/topics.ts',\n\t\t\t\tcontent: `import { Topic } from '@geekmidas/constructs/topic';\nimport { z } from 'zod';\n\n/**\n * The \\`users\\` topic: pub/sub fan-out, any number of subscribers.\n *\n * The event map is the contract. It types every \\`.event(users, …)\\` that\n * publishes to it and every subscriber that binds with \\`worker.topic(users)\\`,\n * so an event cannot be published in one shape and read in another.\n */\nexport const users = new Topic('users', {\n events: {\n 'user.created': z.object({ userId: z.string(), email: z.email() }),\n 'user.updated': z.object({\n userId: z.string(),\n changes: z.record(z.string(), z.unknown()),\n }),\n },\n});\n`,\n\t\t\t},\n\n\t\t\t// src/subscribers/user-events.ts\n\t\t\t{\n\t\t\t\tpath: 'src/subscribers/user-events.ts',\n\t\t\t\tcontent: `import { users } from '~/constructs/topics.ts';\nimport { worker } from '~/constructs/worker.ts';\n\n// Bound to the topic, not handed its publisher: a subscriber consumes.\nexport const userEventsSubscriber = worker\n .topic(users)\n .subscribe(['user.created', 'user.updated'])\n .handle(async ({ events, logger }) => {\n // A batch, not a single event. Both transports deliver in batches, so\n // handling them one at a time is a round trip per event for no reason.\n logger.info({ count: events.length }, 'Processing user events');\n\n for (const event of events) {\n switch (event.type) {\n case 'user.created':\n logger.info({ userId: event.payload.userId }, 'New user created');\n break;\n case 'user.updated':\n logger.info({ userId: event.payload.userId }, 'User updated');\n break;\n }\n }\n });\n`,\n\t\t\t},\n\t\t];\n\n\t\t// A cron, now that a server target runs one. The schedule lives in the\n\t\t// database the worker named; on AWS it becomes an EventBridge rule and\n\t\t// none of that is consulted.\n\t\tif (database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/crons/cleanup.ts',\n\t\t\t\tcontent: `import { worker } from '~/constructs/worker.ts';\n\nexport const cleanup = worker\n .cron('rate(1 day)')\n .handle(async ({ logger }) => {\n logger.info('Running cleanup');\n\n // Delete old sessions, clear temp files, whatever falls out of date.\n\n logger.info('Cleanup complete');\n });\n`,\n\t\t\t});\n\t\t}\n\n\t\t// The database, when this project has one. A `pgboss` events backend\n\t\t// implies one, which is why a worker gets here without asking for it.\n\t\tif (options.constructs.database) {\n\t\t\tfiles.push(...databaseFiles());\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import type { StagesConfig } from '../../workspace/types.js';\nimport { apiTemplate } from './api.js';\nimport { minimalTemplate } from './minimal.js';\nimport { serverlessTemplate } from './serverless.js';\nimport { workerTemplate } from './worker.js';\n\n/**\n * OpenAPI output path (fixed, not configurable)\n */\n\n/**\n * Endpoints output path (generated by gkm dev/build)\n */\n\n/**\n * Logger implementation type\n */\nexport type LoggerType = 'pino' | 'console';\n\n/**\n * Routes structure pattern\n */\nexport type RoutesStructure =\n\t| 'centralized-endpoints'\n\t| 'centralized-routes'\n\t| 'domain-based';\n\n/**\n * Package manager type\n */\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\n/**\n * Deploy target type\n */\nexport type DeployTarget = 'dokploy' | 'sst' | 'none';\n\n/**\n * The constructs a scaffold declares.\n *\n * Constructs, not containers: `Database` is a `KyselyDatabase`, `Uploads` an\n * `ObjectStorage`. Which container runs each locally, and which backend serves\n * it deployed, follow from the declaration and the deploy target — nothing\n * here names a Postgres or a Redis.\n */\nexport interface ScaffoldedConstructs {\n\tdatabase: boolean;\n\tcache: boolean;\n\tuploads: boolean;\n\tmail: boolean;\n}\n\n/**\n * Frontend framework for the fullstack template's client app.\n * Limited to the three with first-class scaffolds; the wider\n * `FrontendFramework` type also covers `vite` and `remix` which\n * users can configure manually after init.\n */\nexport type FullstackFrontendFramework = 'nextjs' | 'tanstack-start' | 'expo';\n\n/**\n * Options collected from user prompts\n */\nexport interface TemplateOptions {\n\tname: string;\n\ttemplate: TemplateName;\n\ttelescope: boolean;\n\tloggerType: LoggerType;\n\troutesStructure: RoutesStructure;\n\tmonorepo: boolean;\n\t/** Path for the API app in monorepo (e.g., 'apps/api') */\n\tapiPath: string;\n\t/** Selected package manager */\n\tpackageManager: PackageManager;\n\t/** Deploy target */\n\tdeployTarget: DeployTarget;\n\t/** The AWS region, when `deployTarget` is `sst` */\n\tregion?: string;\n\t/** The project's stages, written to gkm.config.ts and read from it */\n\tstages: StagesConfig;\n\t/** The constructs this scaffold declares */\n\tconstructs: ScaffoldedConstructs;\n\t/** Frontend framework (fullstack template only) */\n\tfrontendFramework?: FullstackFrontendFramework;\n}\n\n/**\n * A file to be generated\n */\nexport interface GeneratedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/**\n * Template configuration\n */\nexport interface TemplateConfig {\n\tname: TemplateName;\n\tdescription: string;\n\tdependencies: Record<string, string>;\n\tdevDependencies: Record<string, string>;\n\tscripts: Record<string, string>;\n\tfiles: (options: TemplateOptions) => GeneratedFile[];\n}\n\nexport type TemplateName =\n\t| 'minimal'\n\t| 'api'\n\t| 'serverless'\n\t| 'worker'\n\t| 'fullstack';\n\n/**\n * All available templates\n */\nexport const templates: Record<\n\tExclude<TemplateName, 'fullstack'>,\n\tTemplateConfig\n> = {\n\tminimal: minimalTemplate,\n\tapi: apiTemplate,\n\tserverless: serverlessTemplate,\n\tworker: workerTemplate,\n};\n\n/**\n * Template choices for prompts (Story 1.11 simplified to api + fullstack)\n */\nexport const templateChoices = [\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Single backend API with endpoints',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n];\n\n/**\n * All template choices (includes advanced options)\n */\nexport const allTemplateChoices = [\n\t{\n\t\ttitle: 'Minimal',\n\t\tvalue: 'minimal' as TemplateName,\n\t\tdescription: 'Basic health endpoint',\n\t},\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Full API with auth, database, services',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n\t{\n\t\ttitle: 'Serverless',\n\t\tvalue: 'serverless' as TemplateName,\n\t\tdescription: 'AWS Lambda handlers',\n\t},\n\t{\n\t\ttitle: 'Worker',\n\t\tvalue: 'worker' as TemplateName,\n\t\tdescription: 'Background job processing',\n\t},\n];\n\n/**\n * Frontend framework choices for the fullstack template prompt.\n */\nexport const frontendFrameworkChoices = [\n\t{\n\t\ttitle: 'Next.js',\n\t\tvalue: 'nextjs' as FullstackFrontendFramework,\n\t\tdescription: 'React server components, app router (default)',\n\t},\n\t{\n\t\ttitle: 'TanStack Start',\n\t\tvalue: 'tanstack-start' as FullstackFrontendFramework,\n\t\tdescription: 'File-based router on Vite + Nitro',\n\t},\n\t{\n\t\ttitle: 'Expo',\n\t\tvalue: 'expo' as FullstackFrontendFramework,\n\t\tdescription: 'React Native mobile app (iOS + Android)',\n\t},\n];\n\n/**\n * Logger type choices for prompts\n */\nexport const loggerTypeChoices = [\n\t{\n\t\ttitle: 'Pino',\n\t\tvalue: 'pino' as LoggerType,\n\t\tdescription: 'Fast JSON logger for production (recommended)',\n\t},\n\t{\n\t\ttitle: 'Console',\n\t\tvalue: 'console' as LoggerType,\n\t\tdescription: 'Simple console logger for development',\n\t},\n];\n\n/**\n * Routes structure choices for prompts\n */\nexport const routesStructureChoices = [\n\t{\n\t\ttitle: 'Centralized (endpoints)',\n\t\tvalue: 'centralized-endpoints' as RoutesStructure,\n\t\tdescription: 'src/endpoints/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Centralized (routes)',\n\t\tvalue: 'centralized-routes' as RoutesStructure,\n\t\tdescription: 'src/routes/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Domain-based',\n\t\tvalue: 'domain-based' as RoutesStructure,\n\t\tdescription: 'src/**/routes/*.ts (e.g., src/users/routes/list.ts)',\n\t},\n];\n\n/**\n * Package manager choices for prompts\n */\nexport const packageManagerChoices = [\n\t{\n\t\ttitle: 'pnpm',\n\t\tvalue: 'pnpm' as PackageManager,\n\t\tdescription: 'Fast, disk space efficient (recommended)',\n\t},\n\t{\n\t\ttitle: 'npm',\n\t\tvalue: 'npm' as PackageManager,\n\t\tdescription: 'Node.js default package manager',\n\t},\n\t{\n\t\ttitle: 'yarn',\n\t\tvalue: 'yarn' as PackageManager,\n\t\tdescription: 'Yarn package manager',\n\t},\n\t{\n\t\ttitle: 'bun',\n\t\tvalue: 'bun' as PackageManager,\n\t\tdescription: 'Fast JavaScript runtime and package manager',\n\t},\n];\n\n/**\n * Deploy target choices for prompts\n */\nexport const deployTargetChoices = [\n\t{\n\t\ttitle: 'Dokploy',\n\t\tvalue: 'dokploy' as DeployTarget,\n\t\tdescription: 'Deploy to Dokploy (Docker-based hosting)',\n\t},\n\t{\n\t\ttitle: 'AWS (SST)',\n\t\tvalue: 'sst' as DeployTarget,\n\t\tdescription: 'Deploy to your AWS account through SST',\n\t},\n\t{\n\t\ttitle: 'Configure later',\n\t\tvalue: 'none' as DeployTarget,\n\t\tdescription: 'Skip deployment setup for now',\n\t},\n];\n\n/**\n * Which constructs to declare.\n *\n * The containers that run them locally and the backends that serve them\n * deployed are derived from these, so the prompt names only what the code\n * will say.\n */\nexport const constructChoices: {\n\ttitle: string;\n\tvalue: keyof ScaffoldedConstructs;\n\tdescription: string;\n}[] = [\n\t{\n\t\ttitle: 'Database',\n\t\tvalue: 'database',\n\t\tdescription: 'KyselyDatabase — Postgres',\n\t},\n\t{\n\t\ttitle: 'Cache',\n\t\tvalue: 'cache',\n\t\tdescription: 'Cache — backed by what the deploy target implies',\n\t},\n\t{\n\t\ttitle: 'Uploads',\n\t\tvalue: 'uploads',\n\t\tdescription: 'ObjectStorage — a bucket',\n\t},\n\t{\n\t\ttitle: 'Mail',\n\t\tvalue: 'mail',\n\t\tdescription: 'Email — outbound mail over SMTP',\n\t},\n];\n\n/**\n * Get a template by name\n */\nexport function getTemplate(name: TemplateName): TemplateConfig | null {\n\tif (name === 'fullstack') {\n\t\t// Fullstack template is handled specially, uses api template as base\n\t\treturn templates.api;\n\t}\n\tconst template = templates[name];\n\tif (!template) {\n\t\tthrow new Error(`Unknown template: ${name}`);\n\t}\n\treturn template;\n}\n\n/**\n * Check if a template is the fullstack monorepo template\n */\nexport function isFullstackTemplate(name: TemplateName): boolean {\n\treturn name === 'fullstack';\n}\n","import { execSync } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport prompts from 'prompts';\nimport { FileSecretsStore } from '../secrets/file.js';\nimport { createStageSecrets } from '../secrets/generator.js';\nimport { getKeyPath, projectKey } from '../secrets/keystore.js';\nimport {\n\tdeployedProblems,\n\tInvalidStages,\n\tstageProblems,\n} from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\nimport { generateAgentFiles } from './generators/agents.js';\nimport { generateAuthAppFiles } from './generators/auth.js';\nimport { generateConfigFiles } from './generators/config.js';\nimport { generateEnvFiles } from './generators/env.js';\nimport { generateGithubFiles } from './generators/github.js';\nimport { generateExpoAppFiles } from './generators/mobile-expo.js';\nimport { generateModelsPackage } from './generators/models.js';\nimport {\n\tgenerateMonorepoFiles,\n\tgenerateRootConstructs,\n} from './generators/monorepo.js';\nimport { generatePackageJson } from './generators/package.js';\nimport { generateSourceFiles } from './generators/source.js';\nimport {\n\tgenerateTestFactoryFiles,\n\tgenerateTestFiles,\n} from './generators/test.js';\nimport { generateWebAppFiles } from './generators/web.js';\nimport { generateTanStackWebFiles } from './generators/web-tanstack.js';\nimport {\n\tconstructChoices,\n\ttype DeployTarget,\n\tdeployTargetChoices,\n\ttype FullstackFrontendFramework,\n\tfrontendFrameworkChoices,\n\tgetTemplate,\n\tisFullstackTemplate,\n\tloggerTypeChoices,\n\ttype PackageManager,\n\tpackageManagerChoices,\n\troutesStructureChoices,\n\ttype TemplateName,\n\ttype TemplateOptions,\n\ttemplateChoices,\n} from './templates/index.js';\nimport {\n\tcheckDirectoryExists,\n\tdetectPackageManager,\n\tgetExecCommand,\n\tgetInstallCommand,\n\tgetRunCommand,\n\tvalidateProjectName,\n} from './utils.js';\n\nexport interface InitOptions {\n\t/** Project name */\n\tname?: string;\n\t/** Template to use */\n\ttemplate?: TemplateName;\n\t/** Skip dependency installation */\n\tskipInstall?: boolean;\n\t/** Use defaults for all prompts */\n\tyes?: boolean;\n\t/** Force monorepo setup (deprecated, use fullstack template) */\n\tmonorepo?: boolean;\n\t/** API app path in monorepo */\n\tapiPath?: string;\n\t/** Package manager to use */\n\tpm?: PackageManager;\n\t/** Where the project deploys: `dokploy`, `sst`, or `none` */\n\tdeploy?: DeployTarget;\n\t/** The AWS region an SST deploy goes to, e.g. `eu-west-1` */\n\tregion?: string;\n\t/** Deployed stage names, comma-separated, e.g. `staging,prod` */\n\tstages?: string;\n\t/** Which deployed stage is production: retained and protected */\n\tprotectedStage?: string;\n\t/** What `gkm dev`, `exec` and `test` run as, e.g. `dev` */\n\tlocalStage?: string;\n}\n\n/** `' staging, prod '` → `['staging', 'prod']`. */\nconst stageList = (value: string): string[] =>\n\tvalue\n\t\t.split(',')\n\t\t.map((name) => name.trim())\n\t\t.filter(Boolean);\n\n/** `eu-west-1`, `us-gov-west-1`, `ap-southeast-2`. */\nconst AWS_REGION = /^[a-z]{2}(-gov)?-[a-z]+-\\d$/;\n\n/**\n * Main init command - scaffolds a new project\n */\nexport async function initCommand(\n\tprojectName?: string,\n\toptions: InitOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst detectedPkgManager = detectPackageManager(cwd);\n\n\tif (\n\t\toptions.deploy &&\n\t\t!deployTargetChoices.some((choice) => choice.value === options.deploy)\n\t) {\n\t\tthrow new UnknownDeployTarget(\n\t\t\toptions.deploy,\n\t\t\tdeployTargetChoices.map((c) => c.value),\n\t\t);\n\t}\n\n\tif (options.region && !AWS_REGION.test(options.region)) {\n\t\tthrow new NotAnAwsRegion(options.region);\n\t}\n\n\t// Flags are checked before anything is asked or written, the same rules\n\t// gkm.config.ts is held to.\n\tif (options.stages || options.localStage || options.protectedStage) {\n\t\tconst deployed = stageList(options.stages ?? '');\n\t\tconst problems = [\n\t\t\t...deployedProblems(deployed),\n\t\t\t...(options.localStage\n\t\t\t\t? stageProblems({ local: options.localStage, deployed })\n\t\t\t\t: []),\n\t\t\t...(options.protectedStage && !deployed.includes(options.protectedStage)\n\t\t\t\t? [`--protected-stage \"${options.protectedStage}\" is not in --stages`]\n\t\t\t\t: []),\n\t\t];\n\t\tif (problems.length) throw new InvalidStages([...new Set(problems)]);\n\t}\n\n\tlet deployedSoFar: string[] = [];\n\n\t// Handle Ctrl+C gracefully\n\tprompts.override({});\n\tconst onCancel = () => {\n\t\tprocess.exit(0);\n\t};\n\n\t// Gather answers via prompts\n\tconst answers = await prompts(\n\t\t[\n\t\t\t{\n\t\t\t\ttype: projectName || options.name ? null : 'text',\n\t\t\t\tname: 'name',\n\t\t\t\tmessage: 'Project name:',\n\t\t\t\tinitial: 'my-app',\n\t\t\t\tvalidate: (value: string) => {\n\t\t\t\t\tconst nameValid = validateProjectName(value);\n\t\t\t\t\tif (nameValid !== true) return nameValid;\n\t\t\t\t\tconst dirValid = checkDirectoryExists(value, cwd);\n\t\t\t\t\tif (dirValid !== true) return dirValid;\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.template || options.yes ? null : 'select',\n\t\t\t\tname: 'template',\n\t\t\t\tmessage: 'Template:',\n\t\t\t\tchoices: templateChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'multiselect',\n\t\t\t\tname: 'constructs',\n\t\t\t\tmessage: 'Constructs to declare (space to select, enter to confirm):',\n\t\t\t\tchoices: constructChoices.map((c) => ({ ...c, selected: true })),\n\t\t\t\thint: '- Space to select. Return to submit',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'packageManager',\n\t\t\t\tmessage: 'Package manager:',\n\t\t\t\tchoices: packageManagerChoices,\n\t\t\t\tinitial: packageManagerChoices.findIndex(\n\t\t\t\t\t(c) => c.value === detectedPkgManager,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes || options.deploy ? null : 'select',\n\t\t\t\tname: 'deployTarget',\n\t\t\t\tmessage: 'Deployment target:',\n\t\t\t\tchoices: deployTargetChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\t!options.yes &&\n\t\t\t\t\t!options.region &&\n\t\t\t\t\t(options.deploy ?? values.deployTarget) === 'sst'\n\t\t\t\t\t\t? 'text'\n\t\t\t\t\t\t: null,\n\t\t\t\tname: 'region',\n\t\t\t\tmessage: 'AWS region (e.g. eu-west-1):',\n\t\t\t\tvalidate: (value: string) =>\n\t\t\t\t\tAWS_REGION.test(value.trim()) || 'An AWS region, like eu-west-1',\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Named by the project, not picked from a list: whatever the team\n\t\t\t\t// already calls its environments.\n\t\t\t\ttype: options.yes || options.stages ? null : 'text',\n\t\t\t\tname: 'deployedStages',\n\t\t\t\tmessage: 'Deployed stages, comma-separated (e.g. staging, prod):',\n\t\t\t\tvalidate: (value: string) => {\n\t\t\t\t\tconst deployed = stageList(value);\n\t\t\t\t\tif (deployed.length === 0) return 'At least one stage';\n\t\t\t\t\treturn deployedProblems(deployed)[0] ?? true;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\toptions.yes || options.protectedStage\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: stageList(options.stages ?? values.deployedStages ?? '').length >\n\t\t\t\t\t\t\t\t1\n\t\t\t\t\t\t\t? 'select'\n\t\t\t\t\t\t\t: null,\n\t\t\t\tname: 'protectedStage',\n\t\t\t\tmessage: 'Which one is production (retained and protected)?',\n\t\t\t\tchoices: (_prev, values) =>\n\t\t\t\t\tstageList(options.stages ?? values.deployedStages ?? '').map(\n\t\t\t\t\t\t(name) => ({ title: name, value: name }),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\t// \\`validate\\` is not handed the earlier answers, and the local stage\n\t\t\t\t// is only valid relative to the deployed ones — so they are read\n\t\t\t\t// here, where \\`type\\` is.\n\t\t\t\ttype: (_prev, values) => {\n\t\t\t\t\tdeployedSoFar = stageList(\n\t\t\t\t\t\toptions.stages ?? values.deployedStages ?? '',\n\t\t\t\t\t);\n\t\t\t\t\treturn options.yes || options.localStage ? null : 'text';\n\t\t\t\t},\n\t\t\t\tname: 'localStage',\n\t\t\t\tmessage: 'Local stage, what gkm dev runs as (e.g. dev):',\n\t\t\t\tvalidate: (value: string) =>\n\t\t\t\t\tstageProblems({ local: value.trim(), deployed: deployedSoFar })[0] ??\n\t\t\t\t\ttrue,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'confirm',\n\t\t\t\tname: 'telescope',\n\t\t\t\tmessage: 'Include Telescope (request, exception and log recording)?',\n\t\t\t\tinitial: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'loggerType',\n\t\t\t\tmessage: 'Logger:',\n\t\t\t\tchoices: loggerTypeChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'routesStructure',\n\t\t\t\tmessage: 'Routes structure:',\n\t\t\t\tchoices: routesStructureChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Only prompt for frontend framework on the fullstack template.\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\t!options.yes &&\n\t\t\t\t\t(options.template === 'fullstack' || values.template === 'fullstack')\n\t\t\t\t\t\t? 'select'\n\t\t\t\t\t\t: null,\n\t\t\t\tname: 'frontendFramework',\n\t\t\t\tmessage: 'Frontend framework:',\n\t\t\t\tchoices: frontendFrameworkChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t],\n\t\t{ onCancel },\n\t);\n\n\t// Build final options\n\tconst name = projectName || options.name || answers.name;\n\tif (!name) {\n\t\tconsole.error('Project name is required');\n\t\tprocess.exit(1);\n\t}\n\n\t// Validate name if provided via argument\n\tif (projectName || options.name) {\n\t\tconst nameToValidate = projectName || options.name!;\n\t\tconst nameValid = validateProjectName(nameToValidate);\n\t\tif (nameValid !== true) {\n\t\t\tconsole.error(nameValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconst dirValid = checkDirectoryExists(nameToValidate, cwd);\n\t\tif (dirValid !== true) {\n\t\t\tconsole.error(dirValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst template: TemplateName = options.template || answers.template || 'api';\n\tconst isFullstack = isFullstackTemplate(template);\n\n\t// For fullstack, force monorepo mode\n\t// For api template, monorepo is optional (via --monorepo flag)\n\tconst monorepo = isFullstack || options.monorepo || false;\n\n\t// Which constructs to declare. Everything that runs them — the containers\n\t// locally, the backends deployed — is derived from these and the target.\n\tconst chosen: string[] = options.yes\n\t\t? constructChoices.map((c) => c.value)\n\t\t: answers.constructs || [];\n\tconst constructs = {\n\t\t// A fullstack workspace always has a database: its auth server's\n\t\t// tenant lives in it.\n\t\tdatabase: isFullstack || chosen.includes('database'),\n\t\tcache: chosen.includes('cache'),\n\t\tuploads: chosen.includes('uploads'),\n\t\tmail: chosen.includes('mail'),\n\t};\n\n\tconst pkgManager: PackageManager = options.pm\n\t\t? options.pm\n\t\t: options.yes\n\t\t\t? 'pnpm'\n\t\t\t: (answers.packageManager ?? detectedPkgManager);\n\n\t// `--yes` picks no host rather than one: a default that scaffolds one\n\t// provider's deploy script commits every unattended project to it.\n\tconst deployTarget: DeployTarget =\n\t\toptions.deploy ?? (options.yes ? 'none' : (answers.deployTarget ?? 'none'));\n\n\tconst frontendFramework: FullstackFrontendFramework | undefined = isFullstack\n\t\t? options.yes\n\t\t\t? 'nextjs'\n\t\t\t: (answers.frontendFramework ?? 'nextjs')\n\t\t: undefined;\n\tconst templateOptions: TemplateOptions = {\n\t\tname,\n\t\ttemplate,\n\t\ttelescope: options.yes ? true : (answers.telescope ?? true),\n\t\tloggerType: options.yes ? 'pino' : (answers.loggerType ?? 'pino'),\n\t\troutesStructure: options.yes\n\t\t\t? 'centralized-endpoints'\n\t\t\t: (answers.routesStructure ?? 'centralized-endpoints'),\n\t\tmonorepo,\n\t\tapiPath: monorepo ? (options.apiPath ?? 'apps/api') : '',\n\t\tpackageManager: pkgManager,\n\t\tdeployTarget,\n\t\tstages: resolveStages(options, answers),\n\t\t...(deployTarget === 'sst'\n\t\t\t? {\n\t\t\t\t\t// Asked when there is someone to ask; \\`--yes\\` takes eu-west-1.\n\t\t\t\t\tregion:\n\t\t\t\t\t\toptions.region ??\n\t\t\t\t\t\t(options.yes ? 'eu-west-1' : answers.region?.trim()),\n\t\t\t\t}\n\t\t\t: {}),\n\t\tconstructs,\n\t\tfrontendFramework,\n\t};\n\n\tconst targetDir = join(cwd, name);\n\tconst baseTemplate = getTemplate(templateOptions.template);\n\n\tconst isMonorepo = templateOptions.monorepo;\n\tconst apiPath = templateOptions.apiPath;\n\n\tconsole.log('\\n🚀 Creating your project...\\n');\n\n\t// Create project directory\n\tawait mkdir(targetDir, { recursive: true });\n\n\t// For monorepo, app files go in the specified apiPath (e.g., apps/api)\n\tconst appDir = isMonorepo ? join(targetDir, apiPath) : targetDir;\n\tif (isMonorepo) {\n\t\tawait mkdir(appDir, { recursive: true });\n\t}\n\n\t// Collect app files (backend/api)\n\t// Note: Docker files go to root for monorepo, so exclude them here\n\tconst appFiles = baseTemplate\n\t\t? [\n\t\t\t\t...generatePackageJson(templateOptions, baseTemplate),\n\t\t\t\t...generateConfigFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateEnvFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateSourceFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateTestFiles(templateOptions, baseTemplate),\n\t\t\t]\n\t\t: [];\n\n\t// Collect root monorepo files (includes packages/models)\n\tconst rootFiles = baseTemplate\n\t\t? [\n\t\t\t\t// At the project root in both layouts: an agent opening the repo\n\t\t\t\t// reads the root, not the app directory it has not found yet.\n\t\t\t\t...generateAgentFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateGithubFiles(templateOptions),\n\t\t\t\t...generateMonorepoFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateRootConstructs(templateOptions),\n\t\t\t\t...generateModelsPackage(templateOptions),\n\t\t\t\t// The project's, like its migrations: a factory belongs to a\n\t\t\t\t// database, and every app's tests are handed it.\n\t\t\t\t...generateTestFactoryFiles(templateOptions),\n\t\t\t]\n\t\t: [];\n\n\t// Collect frontend app files for fullstack template, dispatched by framework\n\tconst webAppFiles = isFullstack\n\t\t? frontendFramework === 'tanstack-start'\n\t\t\t? generateTanStackWebFiles(templateOptions)\n\t\t\t: frontendFramework === 'expo'\n\t\t\t\t? generateExpoAppFiles(templateOptions)\n\t\t\t\t: generateWebAppFiles(templateOptions)\n\t\t: [];\n\n\t// Collect auth app files for fullstack template\n\tconst authAppFiles = isFullstack ? generateAuthAppFiles(templateOptions) : [];\n\n\t// Write root files (for monorepo)\n\tfor (const { path, content } of rootFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write app files (backend)\n\tfor (const { path, content } of appFiles) {\n\t\tconst fullPath = join(appDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write web app files (frontend)\n\tfor (const { path, content } of webAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write auth app files (authentication service)\n\tfor (const { path, content } of authAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Initialize encrypted secrets for the local stage\n\tconsole.log('🔐 Initializing encrypted secrets...\\n');\n\t// No container credentials: the containers are derived from the declared\n\t// constructs, and reconcile provisions their roles and passwords.\n\tconst local = templateOptions.stages.local;\n\tconst devSecrets = createStageSecrets(local, [], { projectName: name });\n\n\t// Add common custom secrets. No `NODE_ENV`: the command decides that, and\n\t// `gkm exec` injects secrets over the environment — so one stored here made\n\t// every `gkm exec -- next build` a development build, which Next refuses\n\t// to prerender.\n\tconst customSecrets: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (isFullstack) {\n\t\t// Auth service secrets (better-auth)\n\t\tcustomSecrets.AUTH_PORT = '3002';\n\t\t// No `AUTH_URL`: it is the `Auth` construct's address, derived where\n\t\t// the app runs — stored, it would win over that and send every\n\t\t// container to localhost.\n\t\tcustomSecrets.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\t\tcustomSecrets.BETTER_AUTH_URL = 'http://localhost:3002';\n\t\tcustomSecrets.BETTER_AUTH_TRUSTED_ORIGINS =\n\t\t\t'http://localhost:3000,http://localhost:3001';\n\t}\n\n\tdevSecrets.custom = customSecrets;\n\n\t// The local stage's store is always the file.\n\t// Keyed by the project's identity, which is what the generated config's\n\t// `name` makes it — not the folder it happens to be created in.\n\tconst keys = { key: projectKey({ name }), legacy: [basename(targetDir)] };\n\tawait new FileSecretsStore(targetDir, keys).write(local, devSecrets);\n\tconst keyPath = getKeyPath(local, keys);\n\tconsole.log(` Secrets: .gkm/secrets/${local}.json (encrypted)`);\n\tconsole.log(` Key: ${keyPath}\\n`);\n\n\t// Install dependencies\n\tif (!options.skipInstall) {\n\t\tconsole.log('\\n📦 Installing dependencies...\\n');\n\t\ttry {\n\t\t\texecSync(getInstallCommand(pkgManager), {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\tconsole.error('Failed to install dependencies');\n\t\t}\n\n\t\t// The generators write JSON-style double quotes; the project's own\n\t\t// biome.json says single. \\`check --write\\` formats, sorts imports and\n\t\t// applies safe fixes. It was \\`format --write --unsafe\\`, which Biome 2\n\t\t// rejects outright — and the error was swallowed, so nothing was ever\n\t\t// formatted.\n\t\ttry {\n\t\t\texecSync(getExecCommand(pkgManager, 'biome check --write .'), {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t`\\n⚠️ Formatting did not finish cleanly. Run ${getRunCommand(pkgManager, 'fmt')} to see why.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Initialize git repository\n\tconsole.log('\\n📦 Initializing git repository...\\n');\n\ttry {\n\t\texecSync('git init', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git branch -M main', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git add .', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git commit -m \"🎉 Project created with @geekmidas/toolbox\"', {\n\t\t\tcwd: targetDir,\n\t\t\tstdio: 'pipe',\n\t\t});\n\t\tconsole.log(' Initialized git repository on branch main');\n\t} catch {\n\t\tconsole.log(\n\t\t\t' Could not initialize git repository (git may not be installed)',\n\t\t);\n\t}\n\n\t// Print success message with next steps\n\tprintNextSteps(name, templateOptions, pkgManager);\n}\n\n/**\n * Print success message with next steps\n */\nfunction printNextSteps(\n\tprojectName: string,\n\toptions: TemplateOptions,\n\tpkgManager: PackageManager,\n): void {\n\tconst devCommand = getRunCommand(pkgManager, 'dev');\n\tconst cdCommand = `cd ${projectName}`;\n\n\tconsole.log(`\\n${'─'.repeat(50)}`);\n\tconsole.log('\\n✅ Project created successfully!\\n');\n\n\tconsole.log('Next steps:\\n');\n\tconsole.log(` ${cdCommand}`);\n\n\t// A project that declares its infrastructure starts nothing by hand:\n\t// `gkm dev` reconciles the containers its constructs imply first.\n\tconsole.log(` ${devCommand}`);\n\n\tif (options.constructs.database) {\n\t\tconsole.log('');\n\t\tconsole.log(\n\t\t\t\" # Apply each database construct's db/<construct>/ migrations:\",\n\t\t);\n\t\tconsole.log(' gkm migrate');\n\t\tif (options.monorepo) {\n\t\t\tconsole.log(\" # Better Auth's tables, as its tenant's first migration:\");\n\t\t\tconsole.log(' gkm migration auth && gkm migrate');\n\t\t}\n\t}\n\tconsole.log('');\n\n\tif (options.monorepo) {\n\t\tconsole.log('📁 Project structure:');\n\t\tconsole.log(` ${projectName}/`);\n\t\tconsole.log(` ├── apps/`);\n\t\tconsole.log(` │ ├── api/ # Backend API`);\n\t\tif (isFullstackTemplate(options.template)) {\n\t\t\tconsole.log(` │ ├── auth/ # Auth service (better-auth)`);\n\t\t\tswitch (options.frontendFramework) {\n\t\t\t\tcase 'tanstack-start':\n\t\t\t\t\tconsole.log(` │ └── web/ # TanStack Start frontend`);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'expo':\n\t\t\t\t\tconsole.log(` │ └── app/ # Expo (React Native) app`);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(` │ └── web/ # Next.js frontend`);\n\t\t\t}\n\t\t}\n\t\tconsole.log(` ├── packages/`);\n\t\tconsole.log(` │ └── models/ # Shared Zod schemas`);\n\t\tconsole.log(` ├── .gkm/secrets/ # Encrypted secrets`);\n\t\tconsole.log(` ├── gkm.config.ts # Workspace config`);\n\t\tconsole.log(` └── turbo.json # Turbo config`);\n\t\tconsole.log('');\n\t}\n\n\tconst { local, deployed } = options.stages;\n\tconsole.log('🔐 Secrets management:');\n\tconsole.log(` gkm secrets:show --stage ${local} # View secrets`);\n\tconsole.log(` gkm secrets:set KEY VALUE --stage ${local} # Add secret`);\n\tfor (const stage of deployed) {\n\t\tconsole.log(\n\t\t\t` gkm secrets:init --stage ${stage} # Create ${stage} secrets`,\n\t\t);\n\t}\n\tconsole.log('');\n\n\tif (options.deployTarget === 'dokploy') {\n\t\tconsole.log('🚀 Deployment:');\n\t\tfor (const stage of deployed) {\n\t\t\tconsole.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)}`);\n\t\t}\n\t\tconsole.log('');\n\t}\n\n\tif (options.deployTarget === 'sst') {\n\t\tconsole.log('🚀 Deployment (AWS, through SST):');\n\t\tfor (const stage of deployed) {\n\t\t\tconsole.log(\n\t\t\t\t` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm deploy: build, sst deploy, health checks`,\n\t\t\t);\n\t\t}\n\t\tconsole.log(` Uses your AWS credentials, in ${options.region}.`);\n\t\tif (options.constructs.mail) {\n\t\t\tconsole.log(' Set MAIL_FROM to a sender verified in SES first.');\n\t\t}\n\t\tconsole.log('');\n\t}\n\n\tconsole.log('📚 Documentation: https://geekmidas.github.io/toolbox/');\n\tconsole.log('');\n}\n\n/**\n * The stages the project declares, from the answers or the flags.\n *\n * `--yes` with no stage flags has nobody to ask and needs an answer, so it\n * takes `local`, and one deployed stage, `production`, that is protected.\n */\nfunction resolveStages(\n\toptions: InitOptions,\n\tanswers: {\n\t\tdeployedStages?: string;\n\t\tprotectedStage?: string;\n\t\tlocalStage?: string;\n\t},\n): StagesConfig {\n\tconst deployed = stageList(\n\t\toptions.stages ??\n\t\t\tanswers.deployedStages ??\n\t\t\t(options.yes ? 'production' : ''),\n\t);\n\tconst kept =\n\t\toptions.protectedStage ??\n\t\tanswers.protectedStage ??\n\t\t(deployed.length === 1 || options.yes ? deployed[0] : undefined);\n\tconst local = (\n\t\toptions.localStage ??\n\t\tanswers.localStage ??\n\t\t(options.yes ? 'local' : '')\n\t).trim();\n\n\tconst stages: StagesConfig = {\n\t\tlocal,\n\t\tdeployed,\n\t\t...(kept ? { protected: [kept] } : {}),\n\t};\n\tconst problems = stageProblems(stages);\n\tif (problems.length) throw new InvalidStages(problems);\n\treturn stages;\n}\n\n/** `--deploy` naming a target init has no scaffold for. */\nexport class UnknownDeployTarget extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(`Unknown deploy target \"${target}\". Use ${known.join(', ')}.`);\n\t\tthis.name = 'UnknownDeployTarget';\n\t}\n}\n\n/** `--region` that is not shaped like one, e.g. `europe` for `eu-west-1`. */\nexport class NotAnAwsRegion extends Error {\n\tconstructor(readonly region: string) {\n\t\tsuper(`\"${region}\" is not an AWS region. Use one like eu-west-1.`);\n\t\tthis.name = 'NotAnAwsRegion';\n\t}\n}\n","import { generateSecurePassword } from '../secrets/generator.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/**\n * Generate fullstack-aware custom secrets for a workspace.\n *\n * Generates:\n * - Common secrets: PORT, LOG_LEVEL, JWT_SECRET (no `NODE_ENV` — the command\n * decides that; see `gkm init`)\n * - Better-auth secrets for apps using the better-auth framework\n *\n * No address of anything a construct declares — a database's or a tenant's\n * URL, a surface's or a site's. Those are derived from the construct, with\n * passwords from the stage, and one stored here would be a value set by hand,\n * which wins over the derived one: a `localhost` URL handed to a container,\n * with a password no role has.\n */\nexport function generateFullstackCustomSecrets(\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): Record<string, string> {\n\t// A Postgres exists because something declared a database, not because\n\t// config carried a flag saying so.\n\tconst hasDb = containers.includes('postgres');\n\tconst customs: Record<string, string> = {\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\tif (!hasDb) {\n\t\treturn customs;\n\t}\n\n\tfor (const appConfig of Object.values(workspace.apps)) {\n\t\tif (appConfig.type === 'web' || appConfig.type === 'mobile') continue;\n\n\t\t// Better-auth framework secrets\n\t\tif (appConfig.framework === 'better-auth') {\n\t\t\tcustoms.AUTH_PORT = String(appConfig.port);\n\t\t\tcustoms.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${generateSecurePassword(16)}`;\n\t\t\tcustoms.BETTER_AUTH_URL = `http://localhost:${appConfig.port}`;\n\t\t}\n\t}\n\n\t// Generate trusted origins for better-auth (all app ports)\n\tif (customs.BETTER_AUTH_SECRET) {\n\t\tconst allPorts = Object.values(workspace.apps).map((a) => a.port);\n\t\tcustoms.BETTER_AUTH_TRUSTED_ORIGINS = allPorts\n\t\t\t.map((p) => `http://localhost:${p}`)\n\t\t\t.join(',');\n\t}\n\n\treturn customs;\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport {\n\tConfigNotFound,\n\tloadWorkspaceConfig,\n\tloadWorkspaceSettings,\n} from '../config';\nimport { constructGlobs } from '../reconcile/workspace';\nimport { generateFullstackCustomSecrets } from '../setup/fullstack-secrets';\nimport { CredentialsInvalid, loadCredentialSchemas } from './credentialSchemas';\nimport { FileSecretsStore } from './file.js';\nimport { createStageSecrets, rotateServicePassword } from './generator';\nimport { maskPassword, withCustomSecret } from './storage';\nimport { type SecretsStore, secretsStoreFor } from './store.js';\nimport type { SecretServiceName } from './types';\n\nconst logger = console;\n\n/**\n * The store the stage named on the command line keeps its secrets in — SSM or\n * Secrets Manager in its account, for a deployed stage kept there. Outside any workspace nothing\n * names a store, so it is the file.\n */\nasync function storeFor(stage: string): Promise<SecretsStore> {\n\ttry {\n\t\treturn await secretsStoreFor(await loadWorkspaceSettings(), stage);\n\t} catch (error) {\n\t\tif (error instanceof ConfigNotFound) {\n\t\t\treturn new FileSecretsStore(process.cwd());\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport interface SecretsInitOptions {\n\tstage: string;\n\tforce?: boolean;\n}\n\nexport interface SecretsSetOptions {\n\tstage: string;\n}\n\nexport interface SecretsShowOptions {\n\tstage: string;\n\treveal?: boolean;\n}\n\nexport interface SecretsRotateOptions {\n\tstage: string;\n\tservice?: SecretServiceName;\n}\n\nexport interface SecretsImportOptions {\n\tstage: string;\n\t/** Merge with existing secrets (default: true) */\n\tmerge?: boolean;\n}\n\n/**\n * Initialize secrets for a stage.\n * Generates secure random passwords for configured services.\n */\nexport async function secretsInitCommand(\n\toptions: SecretsInitOptions,\n): Promise<void> {\n\tconst { stage, force } = options;\n\n\tconst store = await storeFor(stage);\n\n\t// Check if secrets already exist\n\tif (!force && (await store.read(stage))) {\n\t\tlogger.error(\n\t\t\t`Secrets already exist for stage \"${stage}\". Use --force to overwrite.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Detect workspace mode for project name and fullstack secrets\n\tlet projectName: string | undefined;\n\tlet workspaceSecrets: Record<string, string> | undefined;\n\ttry {\n\t\tconst loaded = await loadWorkspaceConfig();\n\t\tprojectName = loaded.workspace.name;\n\t\tconst isMultiApp = Object.keys(loaded.workspace.apps).length > 1;\n\n\t\tif (isMultiApp) {\n\t\t\tworkspaceSecrets = generateFullstackCustomSecrets(loaded.workspace);\n\t\t\tlogger.log(' Detected workspace mode — generating per-app secrets');\n\t\t}\n\t} catch {\n\t\t// Not a workspace — single-app mode, skip custom secrets\n\t}\n\n\t// Generate secrets (with project name so DATABASE_URL matches app-specific URLs)\n\t// No container credentials: the containers are derived from the declared\n\t// constructs, and reconcile provisions their roles and passwords.\n\tconst secrets = createStageSecrets(stage, [], { projectName });\n\n\tif (workspaceSecrets) {\n\t\tsecrets.custom = workspaceSecrets;\n\t}\n\n\tawait store.write(stage, secrets);\n\n\tlogger.log(`\\n✓ Secrets initialized for stage \"${stage}\"`);\n\tlogger.log(` Store: ${store.name}`);\n\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(`\\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\tif (Object.keys(secrets.custom).length > 0) {\n\t\tlogger.log(`\\n Custom secrets: ${Object.keys(secrets.custom).length}`);\n\t}\n\n\tlogger.log(`\\n Use \"gkm secrets:show --stage ${stage}\" to view secrets`);\n\tlogger.log(\n\t\t' Use \"gkm secrets:set <KEY> <VALUE> --stage ' +\n\t\t\tstage +\n\t\t\t'\" to add custom secrets',\n\t);\n}\n\n/**\n * Read all data from stdin.\n */\nasync function readStdin(): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\n\tfor await (const chunk of process.stdin) {\n\t\tchunks.push(chunk);\n\t}\n\n\treturn Buffer.concat(chunks).toString('utf-8').trim();\n}\n\n/**\n * Set a custom secret.\n * If value is not provided, reads from stdin.\n */\nexport async function secretsSetCommand(\n\tkey: string,\n\tvalue: string | undefined,\n\toptions: SecretsSetOptions,\n): Promise<void> {\n\tconst { stage } = options;\n\n\t// Read from stdin if value not provided\n\tlet secretValue = value;\n\tif (!secretValue) {\n\t\tif (process.stdin.isTTY) {\n\t\t\tlogger.error(\n\t\t\t\t'No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>',\n\t\t\t);\n\t\t\tlogger.error(\n\t\t\t\t'Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsecretValue = await readStdin();\n\t\tif (!secretValue) {\n\t\t\tlogger.error('No value received from stdin');\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tawait assertCredentialValue(key, secretValue, stage);\n\n\tawait store.write(stage, withCustomSecret(secrets, key, secretValue));\n\tlogger.log(`\\n✓ Secret \"${key}\" set for stage \"${stage}\" (${store.name})`);\n}\n\nexport interface SecretsUnsetOptions {\n\tstage: string;\n}\n\n/** `gkm secrets:unset` for a key the stage does not hold. */\nexport class SecretNotSet extends Error {\n\tconstructor(\n\t\treadonly key: string,\n\t\treadonly stage: string,\n\t) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' holds no secret '${key}'. ` +\n\t\t\t\t`List what it holds with gkm secrets:show --stage ${stage}.`,\n\t\t);\n\t\tthis.name = 'SecretNotSet';\n\t}\n}\n\n/** `gkm secrets:unset` on a stage that has no secrets at all. */\nexport class StageSecretsNotFound extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`The stage '${stage}' has no secrets, so there is nothing to remove.`,\n\t\t);\n\t\tthis.name = 'StageSecretsNotFound';\n\t}\n}\n\n/**\n * Remove a custom secret from a stage, in the stage's own store — the file,\n * SSM or Secrets Manager. The rest of the stage is written back as it was.\n *\n * @throws {StageSecretsNotFound} when the stage holds no secrets\n * @throws {SecretNotSet} when it holds none by that key\n */\nexport async function secretsUnsetCommand(\n\tkey: string,\n\toptions: SecretsUnsetOptions,\n): Promise<void> {\n\tconst { stage } = options;\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\tif (!secrets) throw new StageSecretsNotFound(stage);\n\tif (!(key in secrets.custom)) throw new SecretNotSet(key, stage);\n\n\tconst { [key]: _removed, ...custom } = secrets.custom;\n\tawait store.write(stage, {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom,\n\t});\n\tlogger.log(\n\t\t`\\n✓ Secret \"${key}\" removed from stage \"${stage}\" (${store.name})`,\n\t);\n}\n\n/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them before they are stored — what the app would otherwise\n * refuse as it starts. Only a `<ID>_CREDENTIALS` key in a workspace is\n * looked at, so setting anything else loads no construct.\n *\n * @throws {CredentialsInvalid} listing each issue; nothing is saved\n */\nasync function assertCredentialValue(\n\tkey: string,\n\tvalue: string,\n\tstage: string,\n): Promise<void> {\n\tif (!key.endsWith('_CREDENTIALS')) return;\n\n\tlet workspace: Awaited<ReturnType<typeof loadWorkspaceSettings>>;\n\ttry {\n\t\tworkspace = await loadWorkspaceSettings();\n\t} catch (error) {\n\t\tif (error instanceof ConfigNotFound) return;\n\t\tthrow error;\n\t}\n\n\tconst schemas = await loadCredentialSchemas({\n\t\troot: workspace.root,\n\t\tpatterns: constructGlobs(workspace),\n\t});\n\tconst check = await schemas.check(key, value);\n\tif (!check.ok) {\n\t\tthrow new CredentialsInvalid(stage, [{ key, issues: check.issues }], 'set');\n\t}\n}\n\n/**\n * Show secrets for a stage.\n */\nexport async function secretsShowCommand(\n\toptions: SecretsShowOptions,\n): Promise<void> {\n\tconst { stage, reveal } = options;\n\n\tconst secrets = await (await storeFor(stage)).read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tlogger.log(`\\nSecrets for stage \"${stage}\":`);\n\tlogger.log(` Created: ${secrets.createdAt}`);\n\tlogger.log(` Updated: ${secrets.updatedAt}`);\n\n\t// Show service credentials\n\tlogger.log('\\nService Credentials:');\n\tfor (const [service, creds] of Object.entries(secrets.services)) {\n\t\tif (creds) {\n\t\t\tlogger.log(`\\n ${service}:`);\n\t\t\tlogger.log(` host: ${creds.host}`);\n\t\t\tlogger.log(` port: ${creds.port}`);\n\t\t\tlogger.log(` username: ${creds.username}`);\n\t\t\tlogger.log(\n\t\t\t\t` password: ${reveal ? creds.password : maskPassword(creds.password)}`,\n\t\t\t);\n\t\t\tif (creds.database) {\n\t\t\t\tlogger.log(` database: ${creds.database}`);\n\t\t\t}\n\t\t\tif (creds.bucket) {\n\t\t\t\tlogger.log(` bucket: ${creds.bucket}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Show URLs\n\tlogger.log('\\nConnection URLs:');\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(\n\t\t\t` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(\n\t\t\t` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\t// Show custom secrets\n\tconst customKeys = Object.keys(secrets.custom);\n\tif (customKeys.length > 0) {\n\t\tlogger.log('\\nCustom Secrets:');\n\t\tfor (const [key, value] of Object.entries(secrets.custom)) {\n\t\t\tlogger.log(` ${key}: ${reveal ? value : maskPassword(value)}`);\n\t\t}\n\t}\n\n\tif (!reveal) {\n\t\tlogger.log('\\nUse --reveal to show actual values');\n\t}\n}\n\n/**\n * Rotate passwords for services.\n */\nexport async function secretsRotateCommand(\n\toptions: SecretsRotateOptions,\n): Promise<void> {\n\tconst { stage, service } = options;\n\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tif (service) {\n\t\t// Rotate specific service\n\t\tif (!secrets.services[service]) {\n\t\t\tlogger.error(`Service \"${service}\" not configured in stage \"${stage}\"`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst updated = rotateServicePassword(secrets, service);\n\t\tawait store.write(stage, updated);\n\t\tlogger.log(`\\n✓ Password rotated for ${service} in stage \"${stage}\"`);\n\t} else {\n\t\t// Rotate all services\n\t\tlet updated = secrets;\n\t\tconst services = Object.keys(secrets.services) as SecretServiceName[];\n\n\t\tfor (const svc of services) {\n\t\t\tupdated = rotateServicePassword(updated, svc);\n\t\t}\n\n\t\tawait store.write(stage, updated);\n\t\tlogger.log(\n\t\t\t`\\n✓ Passwords rotated for all services in stage \"${stage}\": ${services.join(', ')}`,\n\t\t);\n\t}\n\n\tlogger.log(`\\nUse \"gkm secrets:show --stage ${stage}\" to view new values`);\n}\n\n/**\n * Import secrets from a JSON file.\n */\nexport async function secretsImportCommand(\n\tfile: string,\n\toptions: SecretsImportOptions,\n): Promise<void> {\n\tconst { stage, merge = true } = options;\n\n\t// Check if file exists\n\tif (!existsSync(file)) {\n\t\tlogger.error(`File not found: ${file}`);\n\t\tprocess.exit(1);\n\t}\n\n\t// Read and parse JSON file\n\tlet importedSecrets: Record<string, string>;\n\ttry {\n\t\tconst content = await readFile(file, 'utf-8');\n\t\timportedSecrets = JSON.parse(content);\n\n\t\t// Validate it's a flat object with string values\n\t\tif (typeof importedSecrets !== 'object' || importedSecrets === null) {\n\t\t\tthrow new Error('JSON must be an object');\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(importedSecrets)) {\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Value for \"${key}\" must be a string, got ${typeof value}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Failed to parse JSON file: ${error instanceof Error ? error.message : 'Invalid JSON'}`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Check if secrets exist for stage\n\tconst store = await storeFor(stage);\n\tconst secrets = await store.read(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Merge or replace custom secrets\n\tconst updatedCustom = merge\n\t\t? { ...secrets.custom, ...importedSecrets }\n\t\t: importedSecrets;\n\n\tconst updated = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: updatedCustom,\n\t};\n\n\tawait store.write(stage, updated);\n\n\tconst importedCount = Object.keys(importedSecrets).length;\n\tconst totalCount = Object.keys(updatedCustom).length;\n\n\tlogger.log(`\\n✓ Imported ${importedCount} secrets for stage \"${stage}\"`);\n\n\tif (merge && totalCount > importedCount) {\n\t\tlogger.log(` Total custom secrets: ${totalCount}`);\n\t}\n\n\tlogger.log('\\n Imported keys:');\n\tfor (const key of Object.keys(importedSecrets)) {\n\t\tlogger.log(` - ${key}`);\n\t}\n}\n\n/**\n * Mask password in a URL for display.\n */\nexport function maskUrl(url: string): string {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tif (parsed.password) {\n\t\t\tparsed.password = maskPassword(parsed.password);\n\t\t}\n\t\treturn parsed.toString();\n\t} catch {\n\t\treturn url;\n\t}\n}\n","import { loadWorkspaceConfig } from '../config.js';\nimport { describeServices } from '../reconcile/containers.js';\nimport {\n\tderivedContainers,\n\treconcileWorkspace,\n} from '../reconcile/workspace.js';\nimport {\n\tcreateStageSecrets,\n\tgenerateConnectionUrls,\n\tgenerateServiceCredentials,\n} from '../secrets/generator.js';\nimport { secretsStoreFor } from '../secrets/store.js';\nimport type { SecretServiceName, StageSecrets } from '../secrets/types.js';\nimport { ensureTrusted } from '../trust/index.js';\nimport type { LoadedConfig, NormalizedWorkspace } from '../workspace/types.js';\nimport { generateFullstackCustomSecrets } from './fullstack-secrets.js';\n\nconst logger = console;\n\nexport interface SetupOptions {\n\tstage?: string;\n\tforce?: boolean;\n\tskipDocker?: boolean;\n\tyes?: boolean;\n}\n\n/**\n * Setup development environment.\n *\n * Orchestrates:\n * 1. Load workspace config\n * 2. Resolve secrets (local → the stage's store → generate fresh)\n * 3. Start Docker services\n */\nexport async function setupCommand(options: SetupOptions = {}): Promise<void> {\n\tlogger.log('\\n🔧 Setting up the local environment...\\n');\n\n\t// 1. Load workspace config\n\tlet loadedConfig: LoadedConfig;\n\ttry {\n\t\tloadedConfig = await loadWorkspaceConfig();\n\t} catch {\n\t\tlogger.error(\n\t\t\t'❌ No gkm.config.ts found. Run this command from a workspace root.',\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tconst stage = options.stage ?? loadedConfig.workspace.stages.local;\n\n\tconst { workspace } = loadedConfig;\n\n\tlogger.log(`📦 Workspace: ${workspace.name}`);\n\tlogger.log(`📱 Apps: ${Object.keys(workspace.apps).join(', ')}`);\n\tlogger.log(`🔑 Stage: ${stage}\\n`);\n\n\t// 2. Resolve secrets\n\tconst secrets = await resolveSecrets(stage, workspace, options);\n\n\tif (!secrets) {\n\t\tlogger.error('❌ Failed to resolve secrets. Exiting.');\n\t\tprocess.exit(1);\n\t}\n\n\t// 3. Reconcile the local target: derive containers, allocate ports, start.\n\tif (!options.skipDocker) {\n\t\tlogger.log('');\n\n\t\tawait reconcileLocal(workspace, stage, options);\n\t}\n\n\t// Print summary\n\tprintSummary(workspace, stage);\n}\n\n/**\n * Converge this machine on what the manifest declares.\n *\n * Says what it did in one line and stays silent when it did nothing, because\n * reconciling on every start is only tolerable if the converged case is both\n * free and quiet.\n */\nasync function reconcileLocal(\n\tworkspace: NormalizedWorkspace,\n\tstage: string,\n\toptions: SetupOptions,\n): Promise<void> {\n\tconst result = await reconcileWorkspace(workspace, { stage });\n\n\tif (result.plan.containers.length === 0) {\n\t\tlogger.log('🐳 No containers declared');\n\t\treturn;\n\t}\n\n\tif (!result.changed) {\n\t\tlogger.log('🐳 Services already up to date');\n\t\treturn;\n\t}\n\n\tlogger.log('🐳 Services');\n\tfor (const line of describeServices(result.services)) {\n\t\tlogger.log(line);\n\t}\n\n\t// Only where something actually answers on https. A project with no edge has\n\t// no authority to trust and should never be asked about one. Every app\n\t// behind the edge answers there — not only a file server, which used to be\n\t// the only one asked about, so a workspace of APIs and sites never was.\n\tconst url = result.plan.resources\n\t\t.filter(\n\t\t\t(r) =>\n\t\t\t\tr.kind === 'rest-api' || r.kind === 'site' || r.kind === 'file-server',\n\t\t)\n\t\t.map((r) => result.env[r.envKey])\n\t\t.find((address) => address?.startsWith('https://'));\n\n\tif (url) {\n\t\tawait ensureTrusted(workspace.root, url, {\n\t\t\t...(options.yes ? { assumeYes: true } : {}),\n\t\t});\n\t}\n}\n\n/**\n * Resolve secrets with priority:\n * 1. Local secrets exist → use them (preserves manual additions)\n * 2. A deployed stage whose store has secrets → pull and use\n * 3. Neither → generate fresh secrets\n *\n * --force skips checks 1 and 2 and always regenerates.\n */\nasync function resolveSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n\toptions: SetupOptions,\n) {\n\t// Force regeneration\n\tif (options.force) {\n\t\tlogger.log('🔐 Generating fresh secrets (--force)...');\n\t\treturn generateFreshSecrets(stage, workspace);\n\t}\n\n\t// The stage's own store — SSM or Secrets Manager in its account, for a\n\t// stage kept there\n\tconst store = await secretsStoreFor(workspace, stage);\n\tconst secrets = await store.read(stage);\n\tif (secrets) {\n\t\tlogger.log('🔐 Using existing secrets');\n\t\t// Reconcile: add any missing workspace-derived keys without overwriting\n\t\tconst reconciled = reconcileSecrets(\n\t\t\tsecrets,\n\t\t\tworkspace,\n\t\t\tawait derivedContainers(workspace, stage),\n\t\t);\n\t\tif (reconciled) {\n\t\t\tawait store.write(stage, reconciled);\n\t\t}\n\t\treturn reconciled ?? secrets;\n\t}\n\n\t// Generate fresh secrets\n\tlogger.log('🔐 Generating fresh development secrets...');\n\treturn generateFreshSecrets(stage, workspace);\n}\n\n/**\n * Reconcile existing secrets with expected workspace-derived keys.\n * Adds missing keys (e.g. BETTER_AUTH_*) without overwriting existing values.\n * Returns the updated secrets if changes were made, or null if no changes needed.\n * @internal Exported for testing\n */\n/**\n * Which containers hold a credential worth generating.\n *\n * Reconcile's container names, mapped to the service a credential is stored\n * under. `redis-http` is the Upstash-protocol proxy in front of Redis and holds\n * no credential of its own — its token is derived — so it maps to nothing, and\n * `caddy` is an edge with nothing to log into.\n */\nfunction credentialedServices(\n\tcontainers: readonly string[],\n): SecretServiceName[] {\n\tconst byContainer: Readonly<Record<string, SecretServiceName>> = {\n\t\tpostgres: 'postgres',\n\t\tredis: 'redis',\n\t\tminio: 'minio',\n\t\tmailpit: 'mailpit',\n\t\tlocalstack: 'localstack',\n\t\t// No `rabbitmq`: the container runs as the local user, and a topic's\n\t\t// \\`rabbitmq://\\` URL is reconcile's. A generated password matched\n\t\t// nothing, and the \\`RABBITMQ_URL\\` built from it could never connect.\n\t};\n\n\treturn [\n\t\t...new Set(\n\t\t\tcontainers\n\t\t\t\t.map((container) => byContainer[container])\n\t\t\t\t.filter((name): name is SecretServiceName => Boolean(name)),\n\t\t),\n\t];\n}\n\nexport function reconcileSecrets(\n\tsecrets: StageSecrets,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): StageSecrets | null {\n\tlet changed = false;\n\tlet result = { ...secrets };\n\n\t// Reconcile service credentials: add missing services\n\tfor (const name of credentialedServices(containers)) {\n\t\tif (!result.services[name]) {\n\t\t\tconst creds = generateServiceCredentials(name);\n\t\t\t// Override defaults with project-derived names\n\t\t\tif (name === 'minio') {\n\t\t\t\tcreds.bucket = workspace.name;\n\t\t\t\tcreds.username = workspace.name;\n\t\t\t}\n\t\t\tresult = {\n\t\t\t\t...result,\n\t\t\t\tservices: { ...result.services, [name]: creds },\n\t\t\t};\n\t\t\tresult.urls = generateConnectionUrls(result.services);\n\t\t\tlogger.log(` 🔄 Adding missing service credentials: ${name}`);\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// Reconcile custom secrets for multi-app workspaces\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (isMultiApp) {\n\t\tconst expected = generateFullstackCustomSecrets(workspace, containers);\n\t\tconst missing: Record<string, string> = {};\n\n\t\tfor (const [key, value] of Object.entries(expected)) {\n\t\t\tif (!(key in result.custom)) {\n\t\t\t\tmissing[key] = value;\n\t\t\t}\n\t\t}\n\n\t\tif (Object.keys(missing).length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t` 🔄 Adding missing secrets: ${Object.keys(missing).join(', ')}`,\n\t\t\t);\n\t\t\tresult = {\n\t\t\t\t...result,\n\t\t\t\tcustom: { ...result.custom, ...missing },\n\t\t\t};\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (!changed) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\t...result,\n\t\tupdatedAt: new Date().toISOString(),\n\t};\n}\n\n/**\n * Build a fresh StageSecrets object for a workspace: service credentials,\n * connection URLs, and custom secrets. Pure — does not write to disk or touch\n * any store. Service passwords are freshly randomized, so the result must be the same\n * one used to start the matching Docker containers.\n * @internal Exported for reuse by `gkm test` auto-setup.\n */\nexport function createFreshWorkspaceSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n\tcontainers: readonly string[] = [],\n): StageSecrets {\n\t// Which services need a credential is which containers exist, and that is\n\t// the manifest's answer. It used to be a boolean per service read from\n\t// config, which generated a Postgres password for a project with no\n\t// database and none for a project that declared one and set no flag.\n\tconst serviceNames = credentialedServices(containers);\n\n\t// Create base secrets with service credentials\n\t// No events backend: whether there are events is a declared `Topic` or\n\t// `Queue`, and reconcile derives their connection strings from those.\n\t// Passing the target's broker here would demand broker credentials from a\n\t// project that declared no queue at all.\n\tconst secrets = createStageSecrets(stage, serviceNames, {\n\t\tprojectName: workspace.name,\n\t});\n\n\t// Generate fullstack-aware custom secrets\n\tconst isMultiApp = Object.keys(workspace.apps).length > 1;\n\tif (isMultiApp) {\n\t\tsecrets.custom = generateFullstackCustomSecrets(workspace, containers);\n\t} else {\n\t\t// No `NODE_ENV`, for the reason `gkm init` gives: `gkm exec` injects\n\t\t// secrets over the environment, so a stored one made every\n\t\t// `gkm exec -- next build` a development build.\n\t\tsecrets.custom = {\n\t\t\tPORT: '3000',\n\t\t\tLOG_LEVEL: 'debug',\n\t\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t\t};\n\t}\n\n\treturn secrets;\n}\n\n/**\n * Ensure a usable secret set exists for a stage, generating a fresh one from the\n * workspace config when none is present. No-op if secrets already exist.\n *\n * Powers `gkm test --auto-setup` / `GKM_AUTO_SETUP`: CI can run without a\n * committed secrets file or a shared encryption key — the stage is regenerated\n * from the committed `gkm.config.ts`, and the file store mints a local key.\n *\n * @returns true if fresh secrets were generated, false if existing ones were kept\n */\nexport async function ensureStageSecrets(\n\tstage: string,\n\tcwd: string = process.cwd(),\n): Promise<boolean> {\n\tconst { workspace } = await loadWorkspaceConfig(cwd);\n\n\tconst store = await secretsStoreFor(workspace, stage);\n\tif (await store.read(stage)) {\n\t\treturn false;\n\t}\n\n\tconst secrets = createFreshWorkspaceSecrets(\n\t\tstage,\n\t\tworkspace,\n\t\tawait derivedContainers(workspace, stage),\n\t);\n\tawait store.write(stage, secrets);\n\treturn true;\n}\n\n/**\n * Generate fresh secrets for the workspace.\n */\nasync function generateFreshSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n) {\n\tconst secrets = createFreshWorkspaceSecrets(\n\t\tstage,\n\t\tworkspace,\n\t\tawait derivedContainers(workspace, stage),\n\t);\n\n\t// Straight to the stage's store, where a deploy from anywhere reads them.\n\tconst store = await secretsStoreFor(workspace, stage);\n\tawait store.write(stage, secrets);\n\tlogger.log(` Secrets written to the \"${stage}\" store (${store.name})`);\n\n\treturn secrets;\n}\n\n/**\n * Print setup summary with next steps.\n */\nfunction printSummary(workspace: NormalizedWorkspace, stage: string): void {\n\tlogger.log(`\\n${'─'.repeat(50)}`);\n\tlogger.log('\\n✅ Development environment ready!\\n');\n\n\tlogger.log('📋 Apps:');\n\tfor (const [name, app] of Object.entries(workspace.apps)) {\n\t\tconst icon =\n\t\t\tapp.type === 'web' ? '🌐' : app.type === 'mobile' ? '📱' : '🔧';\n\t\tlogger.log(` ${icon} ${name} → http://localhost:${app.port}`);\n\t}\n\n\tlogger.log('\\n🚀 Next steps:');\n\tlogger.log(' gkm dev # Start all apps');\n\tlogger.log(` gkm secrets:show --stage ${stage} # View secrets`);\n\tlogger.log('');\n}\n","/**\n * Dropping the test stage's databases when a suite ends.\n *\n * Reconcile never drops — the line it draws is at data. The test stage's data\n * is the exception: every test runs in a transaction rolled back after it, so\n * nothing in these databases is anyone's, and a database kept between runs is\n * one whose migrations already ran — an edited migration is never applied to\n * it again. So each run starts from a database it created, and drops it when\n * the suite ends: the Vitest global setup's teardown.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pgClient } from '../reconcile/clients';\nimport type { SqlClient } from '../reconcile/provision';\nimport { quoteIdentifier } from '../reconcile/provision';\nimport { forgetState } from '../reconcile/state';\nimport { TEST_STAGE } from '../workspace/stages';\nimport { TEST_READY_FILE, type TestReady } from './ready';\n\n/**\n * Drop the databases the last setup recorded, and forget the test stage's\n * reconcile, so the next run provisions them from nothing.\n *\n * A no-op when nothing is recorded — no run yet, or one already torn down —\n * so running it twice, or before a setup, is harmless.\n */\nexport async function dropTestDatabases(\n\t/** Where `gkm test` ran — its ready file is under it. */\n\tcwd: string,\n\t/** The workspace root, which holds the reconcile state. */\n\troot: string,\n\tsql: (port: number) => SqlClient = pgClient,\n): Promise<string[]> {\n\tconst readyPath = join(cwd, TEST_READY_FILE);\n\tconst ready = await readReady(readyPath);\n\tconst recorded = ready?.databases;\n\tif (!ready || !recorded) return [];\n\n\tconst client = sql(recorded.port);\n\tfor (const name of recorded.names) {\n\t\t// Recorded from the test stage's plan, so always suffixed — checked\n\t\t// anyway: the container is shared with the local stage, and this is the\n\t\t// one statement in the toolbox that deletes a developer's data.\n\t\tif (!name.endsWith(`_${TEST_STAGE}`)) {\n\t\t\tthrow new NotATestDatabase(name);\n\t\t}\n\t\t// FORCE: a connection left open by the suite — a pool not yet ended —\n\t\t// would otherwise keep the database alive.\n\t\tawait client.query(\n\t\t\tundefined,\n\t\t\t`DROP DATABASE IF EXISTS ${quoteIdentifier(name)} WITH (FORCE)`,\n\t\t);\n\t}\n\n\tawait forgetState(root, TEST_STAGE);\n\tconst { databases: _dropped, ...rest } = ready;\n\tawait writeFile(readyPath, JSON.stringify(rest, null, 2));\n\n\treturn recorded.names;\n}\n\nasync function readReady(path: string): Promise<TestReady | undefined> {\n\ttry {\n\t\treturn JSON.parse(await readFile(path, 'utf-8')) as TestReady;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** A name recorded for the test stage without the test stage's suffix. */\nexport class NotATestDatabase extends Error {\n\tconstructor(readonly database: string) {\n\t\tsuper(\n\t\t\t`Refusing to drop '${database}': only the test stage's databases (named ` +\n\t\t\t\t`'…_${TEST_STAGE}') are dropped after a suite. Delete ` +\n\t\t\t\t`${TEST_READY_FILE} if it was edited by hand.`,\n\t\t);\n\t\tthis.name = 'NotATestDatabase';\n\t}\n}\n","import { spawn } from 'node:child_process';\nimport { writeFile } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nimport { loadWorkspaceConfig } from '../config';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { sniffAppEnvironment } from '../deploy/sniffer';\nimport { primaryPortKey } from '../reconcile/containers';\nimport type { ReconcileResult } from '../reconcile/index.js';\nimport { postgresDatabaseNames } from '../reconcile/provision.js';\nimport { backendsOf, constructGlobs } from '../reconcile/workspace.js';\nimport { TEST_STAGE } from '../workspace/stages';\nimport {\n\tDEFAULT_FACTORIES_DIR,\n\tTEST_MANIFEST_ENV,\n\twriteTestHarness,\n} from './harness';\nimport { TEST_READY_ENV, TEST_READY_FILE, type TestReady } from './ready';\nimport { dropTestDatabases } from './teardown';\n\nexport interface TestOptions {\n\t/** Stage to load secrets from (default: development) */\n\tstage?: string;\n\t/** Run tests once without watch mode */\n\trun?: boolean;\n\t/** Enable watch mode */\n\twatch?: boolean;\n\t/** Generate coverage report */\n\tcoverage?: boolean;\n\t/** Open Vitest UI */\n\tui?: boolean;\n\t/** Pattern to filter tests */\n\tpattern?: string;\n\t/**\n\t * Generate a fresh stage (secrets + encryption key) from the workspace config\n\t * when none exists, instead of requiring committed secrets / a shared key.\n\t * Intended for CI. Also enabled by the GKM_AUTO_SETUP env var.\n\t */\n\tautoSetup?: boolean;\n\t/**\n\t * Write the test manifest and the harness generated from it, then stop —\n\t * no containers started, no suite run. What typechecking a suite needs:\n\t * `#test` is generated, so a typecheck that runs before `gkm test` has\n\t * nothing to resolve it to without this.\n\t */\n\tprepare?: boolean;\n\t/**\n\t * Everything the suite needs, then stop: the stage reconciled, its\n\t * databases migrated, the harness and credentials written. What the Vitest\n\t * global setup (`@geekmidas/cli/vitest`) runs, so a suite started by plain\n\t * `vitest` — or an editor — gets the same stage `gkm test` would give it.\n\t */\n\tsetup?: boolean;\n\t/**\n\t * Drop the test stage's databases the last setup created, then stop — what\n\t * the Vitest global setup's teardown runs when the suite ends.\n\t */\n\tteardown?: boolean;\n}\n\n/**\n * Run tests with secrets, dependency URLs, and .env files loaded.\n * Environment variables are sniffed to inject only what the app needs.\n */\nexport async function testCommand(options: TestOptions = {}): Promise<void> {\n\tconst cwd = process.cwd();\n\t// The project's local stage unless one was named: \\`gkm test\\` reads the\n\t// secrets a developer's own \\`gkm dev\\` does.\n\tconst stage =\n\t\toptions.stage ??\n\t\t(await loadWorkspaceConfig(cwd)\n\t\t\t.then((loaded) => loaded.workspace.stages.local)\n\t\t\t.catch(() => undefined));\n\tif (options.teardown) {\n\t\tawait teardown(cwd);\n\t\treturn;\n\t}\n\n\tif (!stage) {\n\t\tthrow new NoStageToTest();\n\t}\n\n\tconsole.log(`\\n🧪 Running tests with ${stage} environment...\\n`);\n\n\t// 0. Auto-setup (CI): regenerate a fresh stage from the workspace config when\n\t// none exists, so tests run without committed secrets or a shared key.\n\tconst autoSetup = options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP);\n\tif (autoSetup) {\n\t\tconst { ensureStageSecrets } = await import('../setup/index.js');\n\t\tconst generated = await ensureStageSecrets(stage, cwd);\n\t\tif (generated) {\n\t\t\tconsole.log(` 🔐 Generated fresh ${stage} secrets (auto-setup)`);\n\t\t}\n\t}\n\n\t// 1. Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tconsole.log(` 📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// A run killed before its teardown left its databases behind, migrated —\n\t// so an edited migration would not run again. Dropped before reconciling,\n\t// which then creates them afresh.\n\tif (!options.prepare) {\n\t\tawait teardown(cwd);\n\t}\n\n\t// 2. Prepare credentials: loads secrets and reconciles the test stage —\n\t// starts its containers and resolves every declared address\n\tconst result = await prepareEntryCredentials({\n\t\tstage,\n\t\t// Preparing writes files; it has no suite to start containers for.\n\t\tstartDocker: !options.prepare,\n\t\tsecretsFileName: 'test-secrets.json',\n\t\t// The same reconcile `gkm dev` runs, differing only in what the resources\n\t\t// are called: one container and one role pair serve both stages, so the\n\t\t// suffix is the whole of the isolation.\n\t\treconcileStage: 'test',\n\t});\n\n\tlet finalCredentials = { ...result.credentials };\n\n\t// 3. Sniff env vars to filter only what the app needs (workspace only)\n\tif (result.appInfo) {\n\t\tconst sniffed = await sniffAppEnvironment(\n\t\t\tresult.appInfo.app,\n\t\t\tresult.appInfo.appName,\n\t\t\tresult.appInfo.workspaceRoot,\n\t\t\t{ logWarnings: false },\n\t\t);\n\n\t\tif (sniffed.requiredEnvVars.length > 0) {\n\t\t\t// Sniffed *plus* declared. A construct reads its own key inside\n\t\t\t// `@geekmidas/constructs` rather than in application code, so a walk of\n\t\t\t// the app finds no `get('MAIL_URL')` and sniffing alone reports it as\n\t\t\t// unneeded — which is how a suite that resolved 25 declared URLs\n\t\t\t// started with 13 and failed on the first construct to look for one of\n\t\t\t// the other 12.\n\t\t\tconst needed = new Set([\n\t\t\t\t...sniffed.requiredEnvVars,\n\t\t\t\t...result.declaredKeys,\n\t\t\t]);\n\t\t\tconst filtered: Record<string, string> = {};\n\t\t\tfor (const [key, value] of Object.entries(finalCredentials)) {\n\t\t\t\tif (needed.has(key)) {\n\t\t\t\t\tfiltered[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinalCredentials = filtered;\n\t\t\tconsole.log(\n\t\t\t\t` 🔍 Sniffed ${sniffed.requiredEnvVars.length} required env var(s)` +\n\t\t\t\t\t(result.declaredKeys.length > 0\n\t\t\t\t\t\t? `, kept ${result.declaredKeys.length} declared`\n\t\t\t\t\t\t: ''),\n\t\t\t);\n\t\t}\n\t}\n\n\tconsole.log('');\n\n\t// 4. Write final credentials and create preload script\n\tawait writeFile(\n\t\tresult.secretsJsonPath,\n\t\tJSON.stringify(finalCredentials, null, 2),\n\t);\n\n\tconst gkmDir = join(cwd, '.gkm');\n\tconst preloadPath = join(gkmDir, 'test-credentials-preload.ts');\n\tawait createCredentialsPreload(preloadPath, result.secretsJsonPath);\n\n\t// 5. The test manifest: what was discovered and resolved above, kept for the\n\t// suite, so a feature test is built from it rather than declaring it all\n\t// again — and the harness generated from it, `it` and a `Browser` with a\n\t// typed client per surface.\n\tconst workspace = await loadWorkspaceConfig(cwd)\n\t\t.then((loaded) => loaded.workspace)\n\t\t.catch(() => undefined);\n\tconst manifestPath = workspace\n\t\t? await writeTestHarness({\n\t\t\t\troot: workspace.root,\n\t\t\t\ttargets: [\n\t\t\t\t\tworkspace.root,\n\t\t\t\t\t...Object.values(workspace.apps).map((app) =>\n\t\t\t\t\t\tisAbsolute(app.path) ? app.path : join(workspace.root, app.path),\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t\tpatterns: constructGlobs(workspace),\n\t\t\t\tcacheBackend: backendsOf(workspace).cache,\n\t\t\t\teventsBackend: backendsOf(workspace).events,\n\t\t\t\tstage: TEST_STAGE,\n\t\t\t\tenv: finalCredentials,\n\t\t\t\tfactories: join(\n\t\t\t\t\tworkspace.root,\n\t\t\t\t\tworkspace.test.factories ?? DEFAULT_FACTORIES_DIR,\n\t\t\t\t),\n\t\t\t})\n\t\t: undefined;\n\n\tif (options.prepare) {\n\t\tconsole.log(\n\t\t\tmanifestPath\n\t\t\t\t? ` 🧪 Test harness written beside ${manifestPath}`\n\t\t\t\t: ' 🧪 Nothing to prepare: this project declares no constructs',\n\t\t);\n\t\treturn;\n\t}\n\n\t// 6. The databases, migrated and seeded — once, here, for every construct,\n\t// before any project's tests start. Not a Vitest `globalSetup` per\n\t// project: one of those runs only when its project has a matching test,\n\t// and two of them run twice.\n\tif (workspace) {\n\t\tawait migrateTestStage(workspace, result.credentials);\n\t}\n\n\t// What the Vitest global setup loads, and how it knows this run already did\n\t// its work.\n\tconst readyPath = join(cwd, TEST_READY_FILE);\n\tawait writeFile(\n\t\treadyPath,\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tenv: result.secretsJsonPath,\n\t\t\t\t...(manifestPath ? { manifest: manifestPath } : {}),\n\t\t\t\t...testDatabases(result.reconciled),\n\t\t\t} satisfies TestReady,\n\t\t\tnull,\n\t\t\t2,\n\t\t),\n\t);\n\n\tif (options.setup) {\n\t\tconsole.log(` 🧪 Test stage ready: ${TEST_READY_FILE}`);\n\t\treturn;\n\t}\n\n\t// Merge NODE_OPTIONS with existing value (if any)\n\tconst existingNodeOptions = process.env.NODE_OPTIONS ?? '';\n\tconst tsxImport = '--import=tsx';\n\tconst preloadImport = `--import=${preloadPath}`;\n\tconst nodeOptions = [existingNodeOptions, tsxImport, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Build vitest args\n\tconst args: string[] = [];\n\n\tif (options.run) {\n\t\targs.push('run');\n\t} else if (options.watch) {\n\t\targs.push('--watch');\n\t}\n\n\tif (options.coverage) {\n\t\targs.push('--coverage');\n\t}\n\n\tif (options.ui) {\n\t\targs.push('--ui');\n\t}\n\n\tif (options.pattern) {\n\t\targs.push(options.pattern);\n\t}\n\n\t// Run vitest with combined environment and credentials preload\n\tconst vitestProcess = spawn('npx', ['vitest', ...args], {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...finalCredentials,\n\t\t\t...(manifestPath ? { [TEST_MANIFEST_ENV]: manifestPath } : {}),\n\t\t\t[TEST_READY_ENV]: readyPath,\n\t\t\tNODE_ENV: 'test',\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for vitest to complete\n\treturn new Promise((resolve, reject) => {\n\t\tvitestProcess.on('close', (code) => {\n\t\t\tif (code === 0) {\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(new Error(`Tests failed with exit code ${code}`));\n\t\t\t}\n\t\t});\n\n\t\tvitestProcess.on('error', (error) => {\n\t\t\treject(error);\n\t\t});\n\t});\n}\n\n/** Drop what the last setup created — see `dropTestDatabases`. */\nasync function teardown(cwd: string): Promise<void> {\n\tconst root = await loadWorkspaceConfig(cwd)\n\t\t.then((loaded) => loaded.workspace.root)\n\t\t.catch(() => cwd);\n\tconst dropped = await dropTestDatabases(cwd, root);\n\tif (dropped.length > 0) {\n\t\tconsole.log(` 🧹 Dropped ${dropped.join(', ')}`);\n\t}\n}\n\n/**\n * The test stage's Postgres databases, to drop when the suite ends — those\n * the plan provisions, on the port the shared container answers.\n */\nfunction testDatabases(\n\treconciled: ReconcileResult | undefined,\n): Pick<TestReady, 'databases'> {\n\tconst port = reconciled?.ports[primaryPortKey('postgres')];\n\tconst names = reconciled ? postgresDatabaseNames(reconciled.plan) : [];\n\treturn port !== undefined && names.length > 0\n\t\t? { databases: { port, names } }\n\t\t: {};\n}\n\n/**\n * Migrate the test stage just reconciled, then seed it: a test run never\n * starts without the reference data the app needs.\n */\nasync function migrateTestStage(\n\tworkspace: NonNullable<\n\t\tAwaited<ReturnType<typeof loadWorkspaceConfig>>['workspace']\n\t>,\n\tenv: Readonly<Record<string, string>>,\n): Promise<void> {\n\tconst { migrateAndSeed } = await import('../migrate/index.js');\n\tconst { discover } = await import('../reconcile/discover.js');\n\n\tconst sources = {};\n\tconst manifest = await discover({\n\t\tpatterns: constructGlobs(workspace),\n\t\tcwd: workspace.root,\n\t\tsources,\n\t});\n\n\tconst { migrations, seeds } = await migrateAndSeed({\n\t\troot: workspace.root,\n\t\tmanifest,\n\t\tsources,\n\t\tenv,\n\t\tstage: TEST_STAGE,\n\t});\n\n\tfor (const { target, applied } of migrations) {\n\t\tif (applied.length > 0) {\n\t\t\tconsole.log(` 🗄️ ${target.migrations}: applied ${applied.join(', ')}`);\n\t\t}\n\t}\n\tfor (const { target, seeded } of seeds) {\n\t\tif (seeded.length > 0) {\n\t\t\tconsole.log(` 🌱 ${target.seeds}: ran ${seeded.join(', ')}`);\n\t\t}\n\t}\n}\n\n/** `gkm test` outside a project that declares stages, with none named. */\nexport class NoStageToTest extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'No stage to test with: add `stages` to gkm.config.ts, or pass --stage.',\n\t\t);\n\t\tthis.name = 'NoStageToTest';\n\t}\n}\n","/**\n * Just enough semver for `gkm upgrade`: ordering versions, and reading the\n * floor out of a simple range. The same ordering the release pipeline uses to\n * decide what is published (`scripts/release-state.mjs`).\n */\n\nconst VERSION = /(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\ninterface Parsed {\n\tcore: [number, number, number];\n\tids: (string | number)[];\n}\n\nfunction parse(version: string): Parsed | undefined {\n\tconst match = version.match(VERSION);\n\tif (!match) return undefined;\n\tconst [, major, minor, patch, pre] = match;\n\treturn {\n\t\tcore: [Number(major), Number(minor), Number(patch)],\n\t\tids: pre\n\t\t\t? pre.split('.').map((id) => (/^\\d+$/.test(id) ? Number(id) : id))\n\t\t\t: [],\n\t};\n}\n\n/** Negative, zero or positive, as `a` is below, equal to or above `b`. */\nexport function compareVersions(a: string, b: string): number {\n\tconst x = parse(a);\n\tconst y = parse(b);\n\tif (!x || !y) return 0;\n\n\tfor (let i = 0; i < 3; i++) {\n\t\tif (x.core[i] !== y.core[i]) return x.core[i]! - y.core[i]!;\n\t}\n\t// A release outranks any prerelease of the same version.\n\tif (!x.ids.length || !y.ids.length) return y.ids.length - x.ids.length;\n\tfor (let i = 0; i < Math.max(x.ids.length, y.ids.length); i++) {\n\t\tconst p = x.ids[i];\n\t\tconst q = y.ids[i];\n\t\tif (p === undefined) return -1;\n\t\tif (q === undefined) return 1;\n\t\tif (p === q) continue;\n\t\tif (typeof p === 'number' && typeof q === 'number') return p - q;\n\t\tif (typeof p === 'number') return -1;\n\t\tif (typeof q === 'number') return 1;\n\t\treturn p < q ? -1 : 1;\n\t}\n\treturn 0;\n}\n\n/** `alpha` for `10.0.0-alpha.6`; undefined for a release. */\nexport function prereleaseTag(version: string): string | undefined {\n\tconst id = parse(version)?.ids[0];\n\treturn typeof id === 'string' ? id : undefined;\n}\n\n/**\n * A range that is one operator and one version — `~1.2.3`, `^1.2.3`, `>=1.2.3`,\n * `1.2.3` — split into the two. Anything else (`>=8 <10`, `a || b`) is not\n * something to rewrite mechanically.\n */\nexport function simpleRange(\n\trange: string,\n): { operator: string; version: string } | undefined {\n\tconst match = range\n\t\t.trim()\n\t\t.match(/^(\\^|~|>=|)v?(\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?)$/);\n\treturn match ? { operator: match[1]!, version: match[2]! } : undefined;\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { parseDocument } from 'yaml';\nimport {\n\tdetectPackageManager,\n\tfindWorkspacePackages,\n\tfindWorkspaceRoot,\n\tgetInstallCommand,\n\ttype PackageManager,\n} from '../init/utils.js';\nimport { compareVersions, prereleaseTag, simpleRange } from './version.js';\n\nconst logger = console;\n\nconst SCOPE = '@geekmidas/';\nconst DEP_FIELDS = [\n\t'dependencies',\n\t'devDependencies',\n\t'peerDependencies',\n\t'optionalDependencies',\n] as const;\ntype DepField = (typeof DEP_FIELDS)[number];\n\nexport interface UpgradeOptions {\n\tdryRun?: boolean;\n\t/**\n\t * Every `@geekmidas` package, and the third-party packages their peer ranges\n\t * require. Without it only `@geekmidas/cli` moves — upgrade the CLI first,\n\t * then let the new one run `upgrade --all`, since it is the one that knows\n\t * what the new versions need.\n\t */\n\tall?: boolean;\n\t/** The npm dist-tag to follow. Default: the line the project is on. */\n\ttag?: string;\n}\n\n/** One dependency range, and where it is written. */\ninterface Occurrence {\n\tname: string;\n\trange: string;\n\t/** A package.json path, or `catalog` for pnpm-workspace.yaml. */\n\tfile: string;\n\tfield: DepField | 'catalog';\n\t/** For a named pnpm catalog. */\n\tcatalog?: string;\n}\n\ninterface Change extends Occurrence {\n\tnext: string;\n}\n\n/** The abbreviated npm document: dist-tags, and each version's peers. */\ninterface Packument {\n\t'dist-tags': Record<string, string>;\n\tversions: Record<\n\t\tstring,\n\t\t{ peerDependencies?: Record<string, string> } | undefined\n\t>;\n}\n\nasync function packument(name: string): Promise<Packument> {\n\tconst res = await fetch(\n\t\t`https://registry.npmjs.org/${name.replace('/', '%2F')}`,\n\t\t{ headers: { accept: 'application/vnd.npm.install-v1+json' } },\n\t);\n\tif (!res.ok) throw new RegistryUnavailable(name, res.status);\n\treturn (await res.json()) as Packument;\n}\n\n/** Every registry range in the workspace's package.json files. */\nfunction packageOccurrences(paths: string[]): Occurrence[] {\n\tconst found: Occurrence[] = [];\n\tfor (const file of paths) {\n\t\tconst pkg = JSON.parse(readFileSync(file, 'utf-8'));\n\t\tfor (const field of DEP_FIELDS) {\n\t\t\tfor (const [name, range] of Object.entries(pkg[field] ?? {})) {\n\t\t\t\tfound.push({ name, range: range as string, file, field });\n\t\t\t}\n\t\t}\n\t}\n\treturn found;\n}\n\n/** pnpm catalog entries, which is where `catalog:` references resolve. */\nfunction catalogOccurrences(root: string): Occurrence[] {\n\tconst file = join(root, 'pnpm-workspace.yaml');\n\tif (!existsSync(file)) return [];\n\n\tconst doc = parseDocument(readFileSync(file, 'utf-8')).toJS() ?? {};\n\tconst found: Occurrence[] = [];\n\tfor (const [name, range] of Object.entries(doc.catalog ?? {})) {\n\t\tfound.push({ name, range: String(range), file, field: 'catalog' });\n\t}\n\tfor (const [catalog, entries] of Object.entries(doc.catalogs ?? {})) {\n\t\tfor (const [name, range] of Object.entries(entries ?? {})) {\n\t\t\tfound.push({\n\t\t\t\tname,\n\t\t\t\trange: String(range),\n\t\t\t\tfile,\n\t\t\t\tfield: 'catalog',\n\t\t\t\tcatalog,\n\t\t\t});\n\t\t}\n\t}\n\treturn found;\n}\n\n/** Not a registry range: resolved elsewhere, so not ours to move. */\nconst isIndirect = (range: string) =>\n\t/^(workspace|catalog|link|file|npm|git|github|https?):/.test(range);\n\n/**\n * The version every `@geekmidas` package moves to.\n *\n * All of them share one version, so the CLI's line answers for the rest. The\n * tag is the one the project is already on — a project on `10.0.0-alpha.6`\n * follows `alpha` — because `latest` names a different major while a new one\n * is in prerelease, and following it would move the project backwards.\n */\nexport function resolveTarget(\n\tdistTags: Record<string, string>,\n\tinstalled: string[],\n\ttag?: string,\n): { tag: string; version: string } {\n\tconst highest = [...installed].sort(compareVersions).at(-1);\n\tconst chosen = tag ?? (highest && prereleaseTag(highest)) ?? 'latest';\n\tconst version = distTags[chosen];\n\tif (!version) {\n\t\tthrow new NoReleaseOnTag(chosen, Object.keys(distTags));\n\t}\n\treturn { tag: chosen, version };\n}\n\n/** The same operator on the new version — `^`, `~`, `>=` or none, as written. */\nfunction withVersion(range: string, version: string): string {\n\treturn `${simpleRange(range)?.operator ?? ''}${version}`;\n}\n\nexport async function upgradeCommand(\n\toptions: UpgradeOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst pm = detectPackageManager(cwd);\n\tconst root = findWorkspaceRoot(cwd, pm);\n\n\tlogger.log('\\n📦 Scanning workspace for @geekmidas packages...\\n');\n\tlogger.log(` Package manager: ${pm}`);\n\n\tconst packageJsons = findWorkspacePackages(cwd, pm);\n\tconst occurrences = [\n\t\t...packageOccurrences(packageJsons),\n\t\t...catalogOccurrences(root),\n\t];\n\tlogger.log(` Found ${packageJsons.length} package(s) in workspace\\n`);\n\n\tconst ours = occurrences.filter(\n\t\t(o) => o.name.startsWith(SCOPE) && !isIndirect(o.range),\n\t);\n\tif (ours.length === 0) {\n\t\tlogger.log(' No @geekmidas packages found.\\n');\n\t\treturn;\n\t}\n\n\tconst installed = ours\n\t\t.map((o) => simpleRange(o.range)?.version)\n\t\t.filter((v): v is string => Boolean(v));\n\n\tconst cli = await packument(`${SCOPE}cli`);\n\tconst target = resolveTarget(cli['dist-tags'], installed, options.tag);\n\tlogger.log(` Target: ${target.version} (npm \"${target.tag}\")\\n`);\n\n\t// Never backwards: a project ahead of the tag it follows keeps its version.\n\tconst highest = installed.sort(compareVersions).at(-1)!;\n\tif (compareVersions(target.version, highest) < 0) {\n\t\tthrow new WouldDowngrade(highest, target.tag, target.version);\n\t}\n\n\tconst moving = options.all\n\t\t? ours\n\t\t: ours.filter((o) => o.name === `${SCOPE}cli`);\n\n\tconst changes: Change[] = [];\n\tfor (const o of moving) {\n\t\t// A range like `>=8 <10` says something on purpose; it is reported for a\n\t\t// person to widen rather than flattened to one version.\n\t\tif (!simpleRange(o.range)) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ ${o.name} ${o.range} is not a simple range; left as is (target ${target.version}).`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst next = withVersion(o.range, target.version);\n\t\tif (next !== o.range) changes.push({ ...o, next });\n\t}\n\n\tif (options.all) {\n\t\tchanges.push(...(await peerChanges(occurrences, ours, target.version)));\n\t}\n\n\tif (changes.length === 0) {\n\t\tlogger.log(' Everything is already on the target version.\\n');\n\t\treturn;\n\t}\n\n\tprintChanges(changes, root);\n\n\tif (!options.all && ours.some((o) => o.name !== `${SCOPE}cli`)) {\n\t\tlogger.log(\n\t\t\t'\\n Only @geekmidas/cli moves without --all. Afterwards, run `gkm upgrade --all` with the new CLI.',\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: no changes made.\\n');\n\t\treturn;\n\t}\n\n\tapplyChanges(changes);\n\tinstall(pm, root);\n\tlogger.log('\\n ✅ Upgrade complete. Run your tests to verify.\\n');\n}\n\n/**\n * Third-party packages the project already lists, raised to the floor of the\n * peer range the target `@geekmidas` versions declare.\n *\n * Only raised, never lowered, and only where both the peer range and the\n * project's range are one operator and one version; anything else is reported\n * for a person to decide.\n */\nasync function peerChanges(\n\toccurrences: Occurrence[],\n\tours: Occurrence[],\n\tversion: string,\n): Promise<Change[]> {\n\tconst floors = new Map<string, string>();\n\tconst names = [...new Set(ours.map((o) => o.name))];\n\tconst docs = await Promise.all(names.map(packument));\n\n\tfor (const doc of docs) {\n\t\tconst peers = doc.versions[version]?.peerDependencies ?? {};\n\t\tfor (const [peer, range] of Object.entries(peers)) {\n\t\t\tif (peer.startsWith(SCOPE)) continue;\n\t\t\tconst floor = simpleRange(range)?.version;\n\t\t\tif (!floor) continue;\n\t\t\tconst known = floors.get(peer);\n\t\t\tif (!known || compareVersions(floor, known) > 0) floors.set(peer, floor);\n\t\t}\n\t}\n\n\tconst changes: Change[] = [];\n\tfor (const o of occurrences) {\n\t\tconst floor = floors.get(o.name);\n\t\tif (!floor || isIndirect(o.range) || o.field === 'peerDependencies') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = simpleRange(o.range);\n\t\tif (!current) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ ${o.name} ${o.range} is not a simple range; @geekmidas needs at least ${floor}.`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tif (compareVersions(current.version, floor) < 0) {\n\t\t\tchanges.push({ ...o, next: withVersion(o.range, floor) });\n\t\t}\n\t}\n\treturn changes;\n}\n\nfunction printChanges(changes: Change[], root: string): void {\n\tlogger.log(' Changes:\\n');\n\tfor (const c of changes) {\n\t\tconst where =\n\t\t\tc.field === 'catalog'\n\t\t\t\t? `pnpm-workspace.yaml (${c.catalog ? `catalogs.${c.catalog}` : 'catalog'})`\n\t\t\t\t: `${relative(root, c.file) || 'package.json'} (${c.field})`;\n\t\tlogger.log(` ${c.name.padEnd(34)} ${c.range} → ${c.next} ${where}`);\n\t}\n}\n\nfunction applyChanges(changes: Change[]): void {\n\tconst byFile = new Map<string, Change[]>();\n\tfor (const c of changes) {\n\t\tbyFile.set(c.file, [...(byFile.get(c.file) ?? []), c]);\n\t}\n\n\tfor (const [file, fileChanges] of byFile) {\n\t\tconst text = readFileSync(file, 'utf-8');\n\t\tif (file.endsWith('.yaml')) {\n\t\t\t// Through the document, so comments and layout survive.\n\t\t\tconst doc = parseDocument(text);\n\t\t\tfor (const c of fileChanges) {\n\t\t\t\tconst path = c.catalog\n\t\t\t\t\t? ['catalogs', c.catalog, c.name]\n\t\t\t\t\t: ['catalog', c.name];\n\t\t\t\tdoc.setIn(path, c.next);\n\t\t\t}\n\t\t\twriteFileSync(file, doc.toString());\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst pkg = JSON.parse(text);\n\t\tfor (const c of fileChanges) pkg[c.field][c.name] = c.next;\n\t\tconst indent = text.match(/^[ \\t]+(?=\")/m)?.[0] ?? ' ';\n\t\twriteFileSync(file, `${JSON.stringify(pkg, null, indent)}\\n`);\n\t}\n}\n\nfunction install(pm: PackageManager, cwd: string): void {\n\tconst command = getInstallCommand(pm);\n\tlogger.log(`\\n Running: ${command}\\n`);\n\ttry {\n\t\texecSync(command, { cwd, stdio: 'inherit', timeout: 300_000 });\n\t} catch {\n\t\tthrow new InstallFailed(command);\n\t}\n}\n\n/** npm did not answer for a package, so there is no version to compare. */\nexport class RegistryUnavailable extends Error {\n\tconstructor(\n\t\t// Not `name`: that is Error's own, and holds the class name.\n\t\treadonly packageName: string,\n\t\treadonly status: number,\n\t) {\n\t\tsuper(\n\t\t\t`npm answered ${status} for ${packageName}. Check the name and your network.`,\n\t\t);\n\t\tthis.name = 'RegistryUnavailable';\n\t}\n}\n\n/** A dist-tag npm does not have, e.g. `--tag beta` before any beta. */\nexport class NoReleaseOnTag extends Error {\n\tconstructor(\n\t\treadonly tag: string,\n\t\treadonly tags: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`npm has no \"${tag}\" release of @geekmidas/cli. Tags: ${tags.join(', ')}.`,\n\t\t);\n\t\tthis.name = 'NoReleaseOnTag';\n\t}\n}\n\n/** The line asked for is behind what is installed; upgrade never goes back. */\nexport class WouldDowngrade extends Error {\n\tconstructor(\n\t\treadonly installed: string,\n\t\treadonly tag: string,\n\t\treadonly target: string,\n\t) {\n\t\tsuper(\n\t\t\t`The project is already on ${installed}, ahead of npm's \"${tag}\" (${target}). Pass --tag to follow another line.`,\n\t\t);\n\t\tthis.name = 'WouldDowngrade';\n\t}\n}\n\n/** The install after rewriting versions failed; its own output says why. */\nexport class InstallFailed extends Error {\n\tconstructor(readonly command: string) {\n\t\tsuper(`\\`${command}\\` failed. Check the output above for details.`);\n\t\tthis.name = 'InstallFailed';\n\t}\n}\n","#!/usr/bin/env -S npx tsx\n\nimport { resolve } from 'node:path';\nimport { Command, Option } from 'commander';\nimport pkg from '../package.json';\nimport { loginCommand, logoutCommand, whoamiCommand } from './auth';\nimport {\n\tbuildCommand,\n\tisMainProvider,\n\tUnknownBuildProvider,\n\tUnknownCacheBackend,\n} from './build/index';\nimport { type ComposeOptions, composeCommand } from './compose/index';\nimport { enableDebug, formatError } from './debug';\nimport { deployInitCommand, deployListCommand } from './deploy/init';\nimport {\n\tstateDiffCommand,\n\tstatePullCommand,\n\tstatePushCommand,\n\tstateShowCommand,\n\tstateUnlockCommand,\n} from './deploy/state-commands';\nimport { devCommand, execCommand } from './dev/index';\nimport { type DockerOptions, dockerCommand } from './docker/index';\nimport { type InitOptions, initCommand } from './init/index';\nimport { openapiCommand } from './openapi';\nimport {\n\tsecretsImportCommand,\n\tsecretsInitCommand,\n\tsecretsRotateCommand,\n\tsecretsSetCommand,\n\tsecretsShowCommand,\n\tsecretsUnsetCommand,\n} from './secrets';\nimport type { SecretServiceName } from './secrets/types';\nimport { type SetupOptions, setupCommand } from './setup/index';\nimport { type TestOptions, testCommand } from './test/index';\nimport { trustCommand } from './trust/index';\nimport { isCacheBackend } from './types';\nimport { type UpgradeOptions, upgradeCommand } from './upgrade/index';\n\nconst program = new Command();\n\nprogram\n\t.name('gkm')\n\t.description('GeekMidas backend framework CLI')\n\t.version(pkg.version)\n\t.option('--cwd <path>', 'Change working directory')\n\t.option('--debug', 'Enable debug mode (verbose errors with stack traces)')\n\t.hook('preAction', () => {\n\t\tconst opts = program.opts();\n\t\tif (opts.debug) enableDebug();\n\t});\n\nprogram\n\t.command('init')\n\t.description('Scaffold a new project')\n\t.argument('[name]', 'Project name')\n\t.option(\n\t\t'--template <template>',\n\t\t'Project template (minimal, api, serverless, worker)',\n\t)\n\t.option('--skip-install', 'Skip dependency installation', false)\n\t.option('-y, --yes', 'Skip prompts, use defaults', false)\n\t.option('--monorepo', 'Setup as monorepo with packages/models', false)\n\t.option('--api-path <path>', 'API app path in monorepo (default: apps/api)')\n\t.option('--pm <manager>', 'Package manager (pnpm, npm, yarn, bun)')\n\t.option('--deploy <target>', 'Where it deploys (dokploy, sst, none)')\n\t.option('--region <region>', 'AWS region for an SST deploy (e.g. eu-west-1)')\n\t.option(\n\t\t'--stages <names>',\n\t\t'Deployed stages, comma-separated (e.g. staging,prod)',\n\t)\n\t.option('--protected-stage <name>', 'Which deployed stage is production')\n\t.option('--local-stage <name>', 'What gkm dev runs as (e.g. dev)')\n\t.action(async (name: string | undefined, options: InitOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait initCommand(name, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('trust')\n\t.description(\n\t\t\"Trust the local edge's certificate authority, so a browser accepts https\",\n\t)\n\t.option('--dry-run', 'Print the commands instead of running them')\n\t.action(async (options: { dryRun?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait trustCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('setup')\n\t.description(\n\t\t'Reconcile declared constructs — containers, databases, buckets, secrets',\n\t)\n\t.option('--stage <stage>', 'Stage name (default: stages.local)')\n\t.option('--force', 'Regenerate secrets even if they exist')\n\t.option('--skip-docker', 'Skip starting Docker services')\n\t.option('-y, --yes', 'Skip prompts')\n\t.action(async (options: SetupOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait setupCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('build')\n\t.description('Build handlers and the manifest from declared constructs')\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Build for aws or server (default: where gkm.config.ts deploys)',\n\t)\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation generation for server builds',\n\t)\n\t.option('--production', 'Build for production (no dev tools, bundled output)')\n\t.option('--skip-bundle', 'Skip bundling step in production build')\n\t.option('--stage <stage>', 'Inject encrypted secrets for deployment stage')\n\t.option(\n\t\t'--mark-optional',\n\t\t'Suffix optional env vars with ? in manifest envVars field (e.g. PORT?)',\n\t)\n\t// Written by the Dockerfiles `gkm compose` generates, whose stack runs its\n\t// own Redis: not a choice a project makes, so not in the help.\n\t.addOption(\n\t\tnew Option(\n\t\t\t'--cache <backend>',\n\t\t\t'Register the drivers for this cache backend rather than the target default',\n\t\t).hideHelp(),\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider?: string;\n\t\t\tcache?: string;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tproduction?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tstage?: string;\n\t\t\tmarkOptional?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\toptions.provider !== undefined &&\n\t\t\t\t\t!isMainProvider(options.provider)\n\t\t\t\t) {\n\t\t\t\t\tthrow new UnknownBuildProvider(options.provider);\n\t\t\t\t}\n\t\t\t\tif (options.cache !== undefined && !isCacheBackend(options.cache)) {\n\t\t\t\t\tthrow new UnknownCacheBackend(options.cache);\n\t\t\t\t}\n\n\t\t\t\tawait buildCommand({\n\t\t\t\t\t...(options.provider ? { provider: options.provider } : {}),\n\t\t\t\t\t...(options.cache ? { cache: options.cache } : {}),\n\t\t\t\t\tenableOpenApi: options.enableOpenapi || false,\n\t\t\t\t\tproduction: options.production || false,\n\t\t\t\t\tskipBundle: options.skipBundle || false,\n\t\t\t\t\tstage: options.stage,\n\t\t\t\t\tmarkOptional: options.markOptional || false,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('dev')\n\t.description(\n\t\t'Reconcile constructs and start the dev server with automatic reload',\n\t)\n\t.option('-p, --port <port>', 'Port to run the development server on')\n\t.option('--entry <file>', 'Entry file to run (bypasses gkm config)')\n\t.option('--watch', 'Watch for file changes (default: true with --entry)')\n\t.option('--no-watch', 'Disable file watching')\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation for development server',\n\t\ttrue,\n\t)\n\t.option('--migrate', 'Apply pending migrations before the apps start')\n\t.option('--seed', 'Migrate, then run the seeds, before the apps start')\n\t.option(\n\t\t'--fake',\n\t\t'Call each external API’s fake (test/fakes/<id>.ts) instead of the provider',\n\t)\n\t.option(\n\t\t'--no-subscribers',\n\t\t'Run no topic subscribers: nothing is subscribed, polled or pushed to',\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tport?: string;\n\t\t\tentry?: string;\n\t\t\twatch?: boolean;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tmigrate?: boolean;\n\t\t\tseed?: boolean;\n\t\t\tfake?: boolean;\n\t\t\tsubscribers?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait devCommand({\n\t\t\t\t\t// Unset without `--port`, so an app in a workspace gets the port the\n\t\t\t\t\t// workspace gave it. Defaulting to 3000 here meant every app asked\n\t\t\t\t\t// for 3000, and the first to start took it from the others.\n\t\t\t\t\tport: options.port ? Number.parseInt(options.port, 10) : undefined,\n\t\t\t\t\tportExplicit: !!options.port,\n\t\t\t\t\tenableOpenApi: options.enableOpenapi ?? true,\n\t\t\t\t\tentry: options.entry,\n\t\t\t\t\twatch: options.watch,\n\t\t\t\t\tmigrate: options.migrate,\n\t\t\t\t\tseed: options.seed,\n\t\t\t\t\tfake: options.fake,\n\t\t\t\t\tsubscribers: options.subscribers,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('exec')\n\t.description('Run a command with secrets injected into Credentials')\n\t.argument('<command...>', 'Command to run (use -- before command)')\n\t.action(async (commandArgs: string[]) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait execCommand(commandArgs);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('test')\n\t.description('Run tests with secrets loaded from environment')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'Stage to load secrets from (default: stages.local)',\n\t)\n\t.option('--run', 'Run tests once without watch mode')\n\t.option('--watch', 'Enable watch mode')\n\t.option('--coverage', 'Generate coverage report')\n\t.option('--ui', 'Open Vitest UI')\n\t.option(\n\t\t'--auto-setup',\n\t\t'Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)',\n\t)\n\t.option(\n\t\t'--prepare',\n\t\t'Write the test manifest and #test harness, then stop — for a typecheck that runs before the suite',\n\t)\n\t.option(\n\t\t'--setup',\n\t\t'Reconcile, migrate and seed the test stage and write the harness, then stop — what @geekmidas/cli/vitest runs',\n\t)\n\t.option(\n\t\t'--teardown',\n\t\t\"Drop the test stage's databases the last setup created, then stop — what @geekmidas/cli/vitest runs when the suite ends\",\n\t)\n\t.argument('[pattern]', 'Pattern to filter tests')\n\t.action(async (pattern: string | undefined, options: TestOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait testCommand({ ...options, pattern });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('migrate')\n\t.description(\n\t\t\"Apply each database construct's migrations from db/<construct>/migrations/, as its owner\",\n\t)\n\t.argument('[construct]', 'Only this construct, by name')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'The local stage (default) or test — a deploy migrates its own stage',\n\t)\n\t.action(\n\t\tasync (construct: string | undefined, options: { stage?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { migrateCommand } = await import('./migrate/index.js');\n\t\t\t\tawait migrateCommand({\n\t\t\t\t\t...options,\n\t\t\t\t\t...(construct ? { construct } : {}),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('seed')\n\t.description(\n\t\t\"Migrate, then run each database construct's seeds from db/<construct>/seeds/, as its owner\",\n\t)\n\t.argument('[construct]', 'Only this construct, by name')\n\t.option(\n\t\t'--stage <stage>',\n\t\t'The local stage (default) or test — a deploy seeds its own stage',\n\t)\n\t.action(\n\t\tasync (construct: string | undefined, options: { stage?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { seedCommand } = await import('./migrate/index.js');\n\t\t\t\tawait seedCommand({\n\t\t\t\t\t...options,\n\t\t\t\t\t...(construct ? { construct } : {}),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('migration')\n\t.description(\n\t\t\"Write a construct's next migration: an empty one for a database, the schema change for an auth server\",\n\t)\n\t.argument('<construct>', 'The construct, by name')\n\t.argument('[name]', 'What the migration is called')\n\t.action(async (construct: string, name: string | undefined) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { migrationCommand } = await import('./migrate/index.js');\n\t\t\tawait migrationCommand({ construct, ...(name ? { name } : {}) });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('cron')\n\t.description('Manage cron jobs')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Cron management - coming soon\\n');\n\t});\n\nprogram\n\t.command('function')\n\t.description('Manage serverless functions')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Serverless function management - coming soon\\n');\n\t});\n\nprogram\n\t.command('api')\n\t.description('Manage REST API endpoints')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('REST API management - coming soon\\n');\n\t});\n\nprogram\n\t.command('openapi')\n\t.description('Generate OpenAPI specification from endpoints')\n\t.option(\n\t\t'--app <name>',\n\t\t'Workspace mode: generate for a single named backend app',\n\t)\n\t.action(async (options: { app?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait openapiCommand({ app: options.app });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('docker')\n\t.description('Generate Docker deployment files')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.action(async (options: DockerOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait dockerCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('compose')\n\t.description(\n\t\t\"Run the workspace's APIs and sites for a stage as one Docker Compose stack behind Caddy\",\n\t)\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Stage to run — always named, so a stack is never a deployed stage by accident',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'Run the images CI pushed at this tag (sites: <tag>-<stage>); nothing is built',\n\t)\n\t.option('--build', 'Build images from this checkout, tagged with the commit')\n\t.option('--pull', 'Pull images (at --tag, or latest) rather than build them')\n\t.option(\n\t\t'--push',\n\t\t'With --build: push every image to deploy.registry and start nothing (for CI)',\n\t)\n\t.option(\n\t\t'--digests-file <path>',\n\t\t'With --push: write each image as <ref>@sha256:… (JSON). With --tag: run the images at those digests',\n\t)\n\t.option('--dry-run', 'Write the files and print the plan; start nothing')\n\t.option('--down', \"Stop the stage's stack (its volumes are kept)\")\n\t.option(\n\t\t'--allow-dev-services <list>',\n\t\t\"Deployed stage: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade\",\n\t)\n\t.action(async (options: ComposeOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait composeCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('prepack')\n\t.description('Generate Docker files for production deployment')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.action(\n\t\tasync (options: {\n\t\t\tbuild?: boolean;\n\t\t\tpush?: boolean;\n\t\t\ttag?: string;\n\t\t\tregistry?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait dockerCommand({\n\t\t\t\t\tbuild: options.build,\n\t\t\t\t\tpush: options.push,\n\t\t\t\t\ttag: options.tag,\n\t\t\t\t\tregistry: options.registry,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Secrets management commands\nprogram\n\t.command('secrets:init')\n\t.description('Initialize secrets for a deployment stage')\n\t.requiredOption('--stage <stage>', 'Stage name (e.g., production, staging)')\n\t.option('--force', 'Overwrite existing secrets')\n\t.action(async (options: { stage: string; force?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsInitCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:set')\n\t.description('Set a custom secret for a stage')\n\t.argument('<key>', 'Secret key (e.g., API_KEY)')\n\t.argument('[value]', 'Secret value (reads from stdin if omitted)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(\n\t\tasync (\n\t\t\tkey: string,\n\t\t\tvalue: string | undefined,\n\t\t\toptions: { stage: string },\n\t\t) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tawait secretsSetCommand(key, value, options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('secrets:unset')\n\t.description('Remove a custom secret from a stage')\n\t.argument('<key>', 'Secret key (e.g., API_KEY)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(async (key: string, options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsUnsetCommand(key, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:add')\n\t.description(\n\t\t\"Build the keys a stage must be given — buckets, mail, file servers, third parties' credentials — across every app\",\n\t)\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--missing', 'Only the keys the stage has not set')\n\t.option('--json', 'Print the keys as JSON and ask nothing')\n\t.action(\n\t\tasync (options: { stage: string; missing?: boolean; json?: boolean }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { secretsAddCommand } = await import('./secrets/add');\n\t\t\t\tawait secretsAddCommand(options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('encryption:rotate')\n\t.description(\n\t\t\"Add a new current key to an Encryption construct's keyring on a server stage\",\n\t)\n\t.argument('<construct>', 'The Encryption construct (e.g. Pii)')\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.action(async (construct: string, options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { encryptionRotateCommand } = await import('./encryption/index.js');\n\t\t\tawait encryptionRotateCommand(construct, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('encryption:retire')\n\t.description(\n\t\t\"Remove an old key from an Encryption construct's keyring, once nothing is under it\",\n\t)\n\t.argument('<construct>', 'The Encryption construct (e.g. Pii)')\n\t.argument('<key>', 'The key to retire (e.g. k1)')\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.action(\n\t\tasync (construct: string, key: string, options: { stage: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { encryptionRetireCommand } = await import(\n\t\t\t\t\t'./encryption/index.js'\n\t\t\t\t);\n\t\t\t\tawait encryptionRetireCommand(construct, key, options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('secrets:show')\n\t.description('Show secrets for a stage')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--reveal', 'Show actual secret values (not masked)')\n\t.action(async (options: { stage: string; reveal?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:rotate')\n\t.description('Rotate service passwords')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option(\n\t\t'--service <service>',\n\t\t'Specific service to rotate (postgres, redis, minio, …)',\n\t)\n\t.action(async (options: { stage: string; service?: SecretServiceName }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsRotateCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:import')\n\t.description('Import secrets from a JSON file')\n\t.argument('<file>', 'JSON file path (e.g., secrets.json)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--no-merge', 'Replace all custom secrets instead of merging')\n\t.action(async (file: string, options: { stage: string; merge?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsImportCommand(file, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:reconcile')\n\t.description('Backfill missing custom secrets from workspace config')\n\t.option('--stage <stage>', 'Stage name (default: stages.local)')\n\t.action(async (options: { stage?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tconst { loadWorkspaceConfig } = await import('./config');\n\t\t\tconst { reconcileMissingSecrets } = await import('./secrets/reconcile');\n\t\t\tconst { secretsStoreFor } = await import('./secrets/store');\n\n\t\t\tconst { workspace } = await loadWorkspaceConfig();\n\t\t\tconst stage = options.stage ?? workspace.stages.local;\n\t\t\tconst store = await secretsStoreFor(workspace, stage);\n\t\t\tconst secrets = await store.read(stage);\n\n\t\t\tif (!secrets) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t\t\t);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tconst { derivedContainers } = await import('./reconcile/workspace');\n\t\t\tconst result = reconcileMissingSecrets(\n\t\t\t\tsecrets,\n\t\t\t\tworkspace,\n\t\t\t\tawait derivedContainers(workspace, stage),\n\t\t\t);\n\n\t\t\tif (!result) {\n\t\t\t\tconsole.log(`\\n✓ Secrets for stage \"${stage}\" are up-to-date`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait store.write(stage, result.secrets);\n\t\t\tconsole.log(\n\t\t\t\t`\\n✓ Reconciled ${result.addedKeys.length} missing secret(s) for stage \"${stage}\":`,\n\t\t\t);\n\t\t\tfor (const key of result.addedKeys) {\n\t\t\t\tconsole.log(` + ${key}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:migrate')\n\t.description(\n\t\t\"Copy a deployed stage's secrets from the configured store to another (file, ssm, secrets-manager)\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.requiredOption('--to <provider>', 'file, ssm or secrets-manager')\n\t.option(\n\t\t'--region <region>',\n\t\t\"The target's AWS region (default: the configured store's)\",\n\t)\n\t.option('--profile <profile>', \"AWS profile for the stage's account\")\n\t.option('--force', 'Replace a stage the target already holds')\n\t.action(\n\t\tasync (options: {\n\t\t\tstage: string;\n\t\t\tto: string;\n\t\t\tregion?: string;\n\t\t\tprofile?: string;\n\t\t\tforce?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tconst { secretsMigrateCommand } = await import('./secrets/migrate');\n\t\t\t\tawait secretsMigrateCommand(options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy command — the terminal around `deploy()`: it prompts, prints and\n// sets the exit code; the deploy itself does none of the three.\nprogram\n\t.command('deploy')\n\t.description('Deploy a stage through its target')\n\t.option(\n\t\t'--target <name>',\n\t\t'Deploy target: dokploy, compose, sst, or one named in deploy.targets (default: deploy.default)',\n\t)\n\t.option('--provider <provider>', '[DEPRECATED] Use --target instead')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'Image tag (default: stage-timestamp; compose: the commit). Compose pulls a given tag',\n\t)\n\t.option('--skip-push', 'Skip pushing image to registry')\n\t.option('--skip-build', 'Skip build step (use existing build)')\n\t.option(\n\t\t'--json',\n\t\t'Write events as JSON lines instead of progress; never prompts',\n\t)\n\t.option(\n\t\t'--dry-run',\n\t\t'Show what would be created or reused; change, build and push nothing',\n\t)\n\t.option(\n\t\t'--atomic',\n\t\t'If the release fails, roll back every app it released, not only the failed ones',\n\t)\n\t.option(\n\t\t'--allow-dev-services <list>',\n\t\t\"Server targets: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade\",\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\ttarget?: string;\n\t\t\tprovider?: string;\n\t\t\tstage: string;\n\t\t\ttag?: string;\n\t\t\tjson?: boolean;\n\t\t\tdryRun?: boolean;\n\t\t\tatomic?: boolean;\n\t\t\tallowDevServices?: string;\n\t\t}) => {\n\t\t\tconst { deployCli } = await import('./deploy/cli');\n\t\t\tconst globalOptions = program.opts();\n\t\t\t// Passed down, not `process.chdir`ed into: the deploy is told which\n\t\t\t// project it is deploying.\n\t\t\tconst code = await deployCli({\n\t\t\t\tcwd: resolve(globalOptions.cwd ?? process.cwd()),\n\t\t\t\t...(options.target ? { target: options.target } : {}),\n\t\t\t\t...(options.provider ? { provider: options.provider } : {}),\n\t\t\t\tstage: options.stage,\n\t\t\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t\t\t...(options.json ? { json: true } : {}),\n\t\t\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t\t\t...(options.allowDevServices\n\t\t\t\t\t? { allowDevServices: options.allowDevServices }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t\tif (code !== 0) process.exit(code);\n\t\t},\n\t);\n\n// Rollback — a stage's apps back on the release before the one they run.\nprogram\n\t.command('deploy:rollback')\n\t.description(\n\t\t\"Put a stage's app back on its previous release (Dokploy): one app with --app, every app with --atomic\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage')\n\t.option('--app <app>', 'The app to roll back')\n\t.option('--atomic', 'Roll back every app that has an earlier release')\n\t.action(\n\t\tasync (options: { stage: string; app?: string; atomic?: boolean }) => {\n\t\t\ttry {\n\t\t\t\tconst { rollbackStage } = await import('./target/dokploy/rollback');\n\t\t\t\tconst { terminalCredentials } = await import('./deploy/terminal');\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tawait rollbackStage({\n\t\t\t\t\tcwd: resolve(globalOptions.cwd ?? process.cwd()),\n\t\t\t\t\tstage: options.stage,\n\t\t\t\t\t...(options.app ? { app: options.app } : {}),\n\t\t\t\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t\t\t\tcredentials: terminalCredentials(),\n\t\t\t\t\tlog: (line) => console.log(line),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy init command - Initialize Dokploy project and application\nprogram\n\t.command('deploy:init')\n\t.description('Initialize Dokploy deployment (create project and application)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.requiredOption('--project <name>', 'Project name (creates if not exists)')\n\t.requiredOption('--app <name>', 'Application name')\n\t.option('--project-id <id>', 'Use existing project ID instead of creating')\n\t.option('--registry-id <id>', 'Configure registry for the application')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tproject: string;\n\t\t\tapp: string;\n\t\t\tprojectId?: string;\n\t\t\tregistryId?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait deployInitCommand({\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\tprojectName: options.project,\n\t\t\t\t\tappName: options.app,\n\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\tregistryId: options.registryId,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy list command - List Dokploy resources\nprogram\n\t.command('deploy:github')\n\t.description(\n\t\t\"Let GitHub Actions deploy a stage: OIDC role in the stage's AWS account, and the GitHub environment the deploy workflow uses\",\n\t)\n\t.requiredOption('--stage <stage>', 'A deployed stage from gkm.config.ts')\n\t.option('--profile <profile>', \"AWS profile for the stage's account\")\n\t.option('--repo <owner/name>', 'GitHub repository (default: this one)')\n\t.option(\n\t\t'--policy-arn <arn>',\n\t\t'Policy for the deploy role (default: AdministratorAccess)',\n\t)\n\t.option('--dry-run', 'Show the plan without changing AWS or GitHub')\n\t.action(async (options) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tconst { deployGithubCommand } = await import('./deploy/github.js');\n\t\t\tawait deployGithubCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('deploy:list')\n\t.description('List Dokploy resources (projects, registries)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.option('--projects', 'List projects')\n\t.option('--registries', 'List registries')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tprojects?: boolean;\n\t\t\tregistries?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (options.projects) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (options.registries) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (!options.projects && !options.registries) {\n\t\t\t\t\t// Default to listing both\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Login command\nprogram\n\t.command('login')\n\t.description('Authenticate with a deployment or DNS provider')\n\t// `--provider`, the same word `gkm deploy` and the DNS config already use for\n\t// these same names. It was `--service`, which made `dokploy` a provider in\n\t// one command and a service in the next — and `service` is the most\n\t// overloaded word in this codebase already: the DI interface, the\n\t// `services:` backend block, and a Dokploy resource name.\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Provider to log in to (dokploy, hostinger)',\n\t\t'dokploy',\n\t)\n\t// Kept working rather than removed: it is what shipped, and a flag rename is\n\t// not worth breaking somebody's CI over.\n\t.option('--service <provider>', '[DEPRECATED] Use --provider instead')\n\t.option('--token <token>', 'API token (will prompt if not provided)')\n\t.option('--endpoint <url>', 'Service endpoint URL')\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider: string;\n\t\t\tservice?: string;\n\t\t\ttoken?: string;\n\t\t\tendpoint?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\t// The alias wins when given, because a default is not a choice.\n\t\t\t\tconst provider = options.service ?? options.provider;\n\n\t\t\t\tif (!['dokploy', 'hostinger'].includes(provider)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Unknown provider: ${provider}. Supported: dokploy, hostinger`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\n\t\t\t\tawait loginCommand({\n\t\t\t\t\tprovider: provider as 'dokploy' | 'hostinger',\n\t\t\t\t\ttoken: options.token,\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Logout command\nprogram\n\t.command('logout')\n\t.description('Remove stored credentials')\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Whose credentials to remove (dokploy, all)',\n\t\t'dokploy',\n\t)\n\t.option('--service <provider>', '[DEPRECATED] Use --provider instead')\n\t.action(async (options: { provider: string; service?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait logoutCommand({\n\t\t\t\tprovider: (options.service ?? options.provider) as 'dokploy' | 'all',\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// Whoami command\nprogram\n\t.command('whoami')\n\t.description('Show current authentication status')\n\t.action(async () => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait whoamiCommand();\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// State management commands\nprogram\n\t.command('state:pull')\n\t.description('Pull deployment state from remote to local')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePullCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:push')\n\t.description('Push deployment state from local to remote')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePushCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:show')\n\t.description('Show deployment state for a stage')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option('--json', 'Output as JSON')\n\t.action(async (options: { stage: string; json?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:unlock')\n\t.description('Release a stage deploy lock left behind by a run that crashed')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateUnlockCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:diff')\n\t.description('Compare local and remote deployment state')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateDiffCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('upgrade')\n\t.description(\n\t\t'Upgrade @geekmidas/cli (with --all, every @geekmidas package) along the release line the project is on',\n\t)\n\t.option('--dry-run', 'Show what would be upgraded without making changes')\n\t.option(\n\t\t'--all',\n\t\t'Every @geekmidas package, and the third-party packages their peers require',\n\t)\n\t.option(\n\t\t'--tag <tag>',\n\t\t'npm dist-tag to follow (default: the line you are on)',\n\t)\n\t.action(async (options: UpgradeOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait upgradeCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram.parse();\n"],"x_google_ignoreList":[5],"mappings":"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"}
|