@geekmidas/cli 10.0.0-alpha.63 → 10.0.0-alpha.64

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.
Files changed (193) hide show
  1. package/dist/{HostingerProvider-mJ7YruxH.cjs → HostingerProvider-Bx2lHHvu.cjs} +3 -3
  2. package/dist/{HostingerProvider-mJ7YruxH.cjs.map → HostingerProvider-Bx2lHHvu.cjs.map} +1 -1
  3. package/dist/{HostingerProvider-DBBwpDjn.mjs → HostingerProvider-Cd4aS5Kj.mjs} +2 -2
  4. package/dist/{HostingerProvider-DBBwpDjn.mjs.map → HostingerProvider-Cd4aS5Kj.mjs.map} +1 -1
  5. package/dist/{LegacyStateStore-CP7SZwTP.cjs → LegacyStateStore-C2abV49N.cjs} +2 -2
  6. package/dist/{LegacyStateStore-CP7SZwTP.cjs.map → LegacyStateStore-C2abV49N.cjs.map} +1 -1
  7. package/dist/{LegacyStateStore-Q3GmKOdw.mjs → LegacyStateStore-DIgkGaUP.mjs} +2 -2
  8. package/dist/{LegacyStateStore-Q3GmKOdw.mjs.map → LegacyStateStore-DIgkGaUP.mjs.map} +1 -1
  9. package/dist/{LocalStateStore-BGIXcrvX.mjs → LocalStateStore-Cy1ZBW7U.mjs} +2 -2
  10. package/dist/{LocalStateStore-BGIXcrvX.mjs.map → LocalStateStore-Cy1ZBW7U.mjs.map} +1 -1
  11. package/dist/{LocalStateStore-sS8mvLeq.cjs → LocalStateStore-DiJqKyPy.cjs} +2 -2
  12. package/dist/{LocalStateStore-sS8mvLeq.cjs.map → LocalStateStore-DiJqKyPy.cjs.map} +1 -1
  13. package/dist/{OpenApiTsGenerator-CjHWFRDd.cjs → OpenApiTsGenerator-BWuDRHe9.cjs} +2 -2
  14. package/dist/{OpenApiTsGenerator-CjHWFRDd.cjs.map → OpenApiTsGenerator-BWuDRHe9.cjs.map} +1 -1
  15. package/dist/{OpenApiTsGenerator-CnAwhGxi.mjs → OpenApiTsGenerator-C6v-IeHt.mjs} +2 -2
  16. package/dist/{OpenApiTsGenerator-CnAwhGxi.mjs.map → OpenApiTsGenerator-C6v-IeHt.mjs.map} +1 -1
  17. package/dist/{S3StateStore-D7l_lWJ3.mjs → S3StateStore-D3x6ivBL.mjs} +2 -2
  18. package/dist/{S3StateStore-D7l_lWJ3.mjs.map → S3StateStore-D3x6ivBL.mjs.map} +1 -1
  19. package/dist/{S3StateStore-6jqITH2F.cjs → S3StateStore-Ds0V1Lgm.cjs} +2 -2
  20. package/dist/{S3StateStore-6jqITH2F.cjs.map → S3StateStore-Ds0V1Lgm.cjs.map} +1 -1
  21. package/dist/{SSMStateStore-B__F7IJa.cjs → SSMStateStore-CLipvx47.cjs} +2 -2
  22. package/dist/{SSMStateStore-B__F7IJa.cjs.map → SSMStateStore-CLipvx47.cjs.map} +1 -1
  23. package/dist/{SSMStateStore-CAQDVpoc.mjs → SSMStateStore-DfF174xQ.mjs} +2 -2
  24. package/dist/{SSMStateStore-CAQDVpoc.mjs.map → SSMStateStore-DfF174xQ.mjs.map} +1 -1
  25. package/dist/{bundler-DLfOn0ls.cjs → bundler-C8uJf324.cjs} +3 -3
  26. package/dist/{bundler-DLfOn0ls.cjs.map → bundler-C8uJf324.cjs.map} +1 -1
  27. package/dist/{bundler-DyWI41Iy.mjs → bundler-DYgm9xsd.mjs} +3 -3
  28. package/dist/{bundler-DyWI41Iy.mjs.map → bundler-DYgm9xsd.mjs.map} +1 -1
  29. package/dist/{cli-PkVF28LM.mjs → cli-Bogz-zEj.mjs} +5 -4
  30. package/dist/{cli-PkVF28LM.mjs.map → cli-Bogz-zEj.mjs.map} +1 -1
  31. package/dist/{cli-D-ZM-X2s.cjs → cli-D3jofJ6j.cjs} +7 -6
  32. package/dist/{cli-D-ZM-X2s.cjs.map → cli-D3jofJ6j.cjs.map} +1 -1
  33. package/dist/{config-CemHVcIr.d.cts → config-Be-4_I6H.d.cts} +3 -3
  34. package/dist/{config-C2BUosLm.d.mts.map → config-Be-4_I6H.d.cts.map} +1 -1
  35. package/dist/{config-C2BUosLm.d.mts → config-DqNRiQOp.d.mts} +3 -3
  36. package/dist/{config-CemHVcIr.d.cts.map → config-DqNRiQOp.d.mts.map} +1 -1
  37. package/dist/config.cjs +416 -17
  38. package/dist/config.cjs.map +1 -0
  39. package/dist/config.d.cts +3 -3
  40. package/dist/config.d.mts +3 -3
  41. package/dist/config.mjs +401 -2
  42. package/dist/config.mjs.map +1 -0
  43. package/dist/credentials-B70vmLcm.cjs +125 -0
  44. package/dist/credentials-B70vmLcm.cjs.map +1 -0
  45. package/dist/credentials-s0wMeZBU.mjs +108 -0
  46. package/dist/credentials-s0wMeZBU.mjs.map +1 -0
  47. package/dist/{define-CHBIEc5j.mjs → define-CYs0PEfZ.mjs} +2 -3
  48. package/dist/define-CYs0PEfZ.mjs.map +1 -0
  49. package/dist/{define-Cv_QvDrg.cjs → define-zUsP72ym.cjs} +2 -3
  50. package/dist/define-zUsP72ym.cjs.map +1 -0
  51. package/dist/deploy/public.cjs +32 -26
  52. package/dist/deploy/public.cjs.map +1 -1
  53. package/dist/deploy/public.d.cts +40 -4
  54. package/dist/deploy/public.d.cts.map +1 -1
  55. package/dist/deploy/public.d.mts +40 -4
  56. package/dist/deploy/public.d.mts.map +1 -1
  57. package/dist/deploy/public.mjs +15 -12
  58. package/dist/deploy/public.mjs.map +1 -1
  59. package/dist/{deploy-ABBI0lf1.cjs → deploy-55rJkdKz.cjs} +17 -14
  60. package/dist/{deploy-ABBI0lf1.cjs.map → deploy-55rJkdKz.cjs.map} +1 -1
  61. package/dist/{deploy-CGW-QY9D.mjs → deploy-Dc2LBJaK.mjs} +8 -7
  62. package/dist/{deploy-CGW-QY9D.mjs.map → deploy-Dc2LBJaK.mjs.map} +1 -1
  63. package/dist/{deploy-CG8bfFij.mjs → deploy-ZRXIPp1c.mjs} +11 -8
  64. package/dist/{deploy-CG8bfFij.mjs.map → deploy-ZRXIPp1c.mjs.map} +1 -1
  65. package/dist/{deploy-BiMrP9i7.cjs → deploy-yUcR2OlW.cjs} +12 -11
  66. package/dist/{deploy-BiMrP9i7.cjs.map → deploy-yUcR2OlW.cjs.map} +1 -1
  67. package/dist/derive-B4vDpzgP.mjs +150 -0
  68. package/dist/derive-B4vDpzgP.mjs.map +1 -0
  69. package/dist/derive-DAbo49sm.cjs +161 -0
  70. package/dist/derive-DAbo49sm.cjs.map +1 -0
  71. package/dist/{discover-C_6COHEv.cjs → discover-DHdECueV.cjs} +6 -157
  72. package/dist/discover-DHdECueV.cjs.map +1 -0
  73. package/dist/{discover-BaT6bpnA.mjs → discover-LMrqsWSU.mjs} +8 -117
  74. package/dist/discover-LMrqsWSU.mjs.map +1 -0
  75. package/dist/{dokploy-CwdmlyQL.mjs → dokploy-CepdXuMl.mjs} +3 -3
  76. package/dist/{dokploy-CwdmlyQL.mjs.map → dokploy-CepdXuMl.mjs.map} +1 -1
  77. package/dist/{dokploy-QJxMhxdf.cjs → dokploy-D1d37rvM.cjs} +3 -3
  78. package/dist/{dokploy-QJxMhxdf.cjs.map → dokploy-D1d37rvM.cjs.map} +1 -1
  79. package/dist/{encryption-DXw3jj0c.cjs → encryption-C9X98u2F.cjs} +5 -5
  80. package/dist/{encryption-DXw3jj0c.cjs.map → encryption-C9X98u2F.cjs.map} +1 -1
  81. package/dist/{encryption-CbQG_ayW.mjs → encryption-CKHjMpCr.mjs} +5 -5
  82. package/dist/{encryption-CbQG_ayW.mjs.map → encryption-CKHjMpCr.mjs.map} +1 -1
  83. package/dist/{github-ciwbIwVa.mjs → github-D-byNI7T.mjs} +4 -4
  84. package/dist/{github-ciwbIwVa.mjs.map → github-D-byNI7T.mjs.map} +1 -1
  85. package/dist/{github-BH_mETav.cjs → github-Dd3tMa1u.cjs} +4 -4
  86. package/dist/{github-BH_mETav.cjs.map → github-Dd3tMa1u.cjs.map} +1 -1
  87. package/dist/{index-DrKzpHl-.d.mts → index-CJ2qsSpp.d.mts} +2 -2
  88. package/dist/{index-BtXDZQuF.d.cts.map → index-CJ2qsSpp.d.mts.map} +1 -1
  89. package/dist/{index-BtXDZQuF.d.cts → index-CfE9Y885.d.cts} +2 -2
  90. package/dist/{index-DrKzpHl-.d.mts.map → index-CfE9Y885.d.cts.map} +1 -1
  91. package/dist/index.cjs +100 -235
  92. package/dist/index.cjs.map +1 -1
  93. package/dist/index.mjs +71 -206
  94. package/dist/index.mjs.map +1 -1
  95. package/dist/local-C7wnrcYK.cjs +586 -0
  96. package/dist/local-C7wnrcYK.cjs.map +1 -0
  97. package/dist/local-Cd8ZYQG3.mjs +473 -0
  98. package/dist/local-Cd8ZYQG3.mjs.map +1 -0
  99. package/dist/{migrate-ImBKTBcW.mjs → migrate-B4gngTLe.mjs} +6 -6
  100. package/dist/{migrate-ImBKTBcW.mjs.map → migrate-B4gngTLe.mjs.map} +1 -1
  101. package/dist/{migrate-6oa9y_f2.cjs → migrate-tx9-P9uz.cjs} +6 -6
  102. package/dist/{migrate-6oa9y_f2.cjs.map → migrate-tx9-P9uz.cjs.map} +1 -1
  103. package/dist/openapi.cjs +2 -2
  104. package/dist/openapi.d.cts +1 -1
  105. package/dist/openapi.d.mts +1 -1
  106. package/dist/openapi.mjs +2 -2
  107. package/dist/{ready-Bpdnn2ON.mjs → ready-bQfu9GES.mjs} +3 -3
  108. package/dist/{ready-Bpdnn2ON.mjs.map → ready-bQfu9GES.mjs.map} +1 -1
  109. package/dist/{ready-BiG0rt4h.cjs → ready-brEhh68f.cjs} +3 -3
  110. package/dist/{ready-BiG0rt4h.cjs.map → ready-brEhh68f.cjs.map} +1 -1
  111. package/dist/reconcile/public.cjs +1 -1
  112. package/dist/reconcile/public.d.cts +1 -1
  113. package/dist/reconcile/public.d.mts +1 -1
  114. package/dist/reconcile/public.mjs +1 -1
  115. package/dist/{resolve-xytBTtG4.cjs → resolve-BXsNQjMR.cjs} +9 -6
  116. package/dist/resolve-BXsNQjMR.cjs.map +1 -0
  117. package/dist/{resolve-B1T0hUaR.mjs → resolve-DZ2IJ0qY.mjs} +9 -6
  118. package/dist/resolve-DZ2IJ0qY.mjs.map +1 -0
  119. package/dist/{runtime-CMwtq0AL.cjs → runtime-BGNDrHzh.cjs} +2 -2
  120. package/dist/{runtime-CMwtq0AL.cjs.map → runtime-BGNDrHzh.cjs.map} +1 -1
  121. package/dist/{runtime-Dn_n-29S.d.cts → runtime-CJEYK4Gz.d.mts} +2 -2
  122. package/dist/{runtime-CXPlkZzs.d.mts.map → runtime-CJEYK4Gz.d.mts.map} +1 -1
  123. package/dist/{runtime-CXPlkZzs.d.mts → runtime-Cjq1jlVX.d.cts} +2 -2
  124. package/dist/{runtime-Dn_n-29S.d.cts.map → runtime-Cjq1jlVX.d.cts.map} +1 -1
  125. package/dist/{runtime-DbakJS8u.mjs → runtime-Cmn-FeYO.mjs} +2 -2
  126. package/dist/{runtime-DbakJS8u.mjs.map → runtime-Cmn-FeYO.mjs.map} +1 -1
  127. package/dist/sandbox/discover-worker.cjs +1 -1
  128. package/dist/sandbox/discover-worker.mjs +1 -1
  129. package/dist/sandbox-CL--ZDui.cjs +164 -0
  130. package/dist/sandbox-CL--ZDui.cjs.map +1 -0
  131. package/dist/sandbox-Dm247NGx.mjs +117 -0
  132. package/dist/sandbox-Dm247NGx.mjs.map +1 -0
  133. package/dist/{sniffer-aO_-s5vq.mjs → sniffer-49KPbDgq.mjs} +25 -470
  134. package/dist/sniffer-49KPbDgq.mjs.map +1 -0
  135. package/dist/{sniffer-D_SYc_pO.cjs → sniffer-ByhbEW5A.cjs} +38 -567
  136. package/dist/sniffer-ByhbEW5A.cjs.map +1 -0
  137. package/dist/sst-BdALKEas.cjs +453 -0
  138. package/dist/sst-BdALKEas.cjs.map +1 -0
  139. package/dist/sst-Cper040I.mjs +430 -0
  140. package/dist/sst-Cper040I.mjs.map +1 -0
  141. package/dist/{store-BS8A7NcA.mjs → store-BaaonhkJ.mjs} +2 -2
  142. package/dist/{store-BS8A7NcA.mjs.map → store-BaaonhkJ.mjs.map} +1 -1
  143. package/dist/{store-KvNQwYaB.cjs → store-D_2ByRtW.cjs} +4 -4
  144. package/dist/{store-KvNQwYaB.cjs.map → store-D_2ByRtW.cjs.map} +1 -1
  145. package/dist/target/public.cjs +3 -3
  146. package/dist/target/public.d.cts +3 -3
  147. package/dist/target/public.d.mts +3 -3
  148. package/dist/target/public.mjs +3 -3
  149. package/dist/{terminal-D0f1u0LG.cjs → terminal-Bdv--jhY.cjs} +16 -111
  150. package/dist/terminal-Bdv--jhY.cjs.map +1 -0
  151. package/dist/{terminal-gMxAo9Dj.mjs → terminal-D7Ntz6WE.mjs} +13 -90
  152. package/dist/terminal-D7Ntz6WE.mjs.map +1 -0
  153. package/dist/{types-DIA7Li-J.d.cts → types-B_bEQvb9.d.mts} +42 -7
  154. package/dist/types-B_bEQvb9.d.mts.map +1 -0
  155. package/dist/{types-CfLKGfC_.d.mts → types-DkrDOMxw.d.cts} +43 -6
  156. package/dist/types-DkrDOMxw.d.cts.map +1 -0
  157. package/dist/utils-D2Nk1Nv2.cjs +205 -0
  158. package/dist/utils-D2Nk1Nv2.cjs.map +1 -0
  159. package/dist/utils-D_fxUqvU.mjs +156 -0
  160. package/dist/utils-D_fxUqvU.mjs.map +1 -0
  161. package/dist/vitest.cjs +1 -1
  162. package/dist/vitest.mjs +1 -1
  163. package/dist/workspace/index.cjs +1 -1
  164. package/dist/workspace/index.d.cts +2 -2
  165. package/dist/workspace/index.d.mts +2 -2
  166. package/dist/workspace/index.mjs +1 -1
  167. package/dist/{workspace-Kl4NG9IH.cjs → workspace-BwgWJK7h.cjs} +5 -5
  168. package/dist/workspace-BwgWJK7h.cjs.map +1 -0
  169. package/dist/{workspace-Dh7rr7l4.mjs → workspace-Bwit4q9O.mjs} +5 -5
  170. package/dist/workspace-Bwit4q9O.mjs.map +1 -0
  171. package/package.json +13 -13
  172. package/dist/config-BEJYKd4s.cjs +0 -648
  173. package/dist/config-BEJYKd4s.cjs.map +0 -1
  174. package/dist/config-LKKCVCnC.mjs +0 -547
  175. package/dist/config-LKKCVCnC.mjs.map +0 -1
  176. package/dist/define-CHBIEc5j.mjs.map +0 -1
  177. package/dist/define-Cv_QvDrg.cjs.map +0 -1
  178. package/dist/discover-BaT6bpnA.mjs.map +0 -1
  179. package/dist/discover-C_6COHEv.cjs.map +0 -1
  180. package/dist/home-DOzBaWaL.cjs +0 -33
  181. package/dist/home-DOzBaWaL.cjs.map +0 -1
  182. package/dist/home-GI7pJl1M.mjs +0 -22
  183. package/dist/home-GI7pJl1M.mjs.map +0 -1
  184. package/dist/resolve-B1T0hUaR.mjs.map +0 -1
  185. package/dist/resolve-xytBTtG4.cjs.map +0 -1
  186. package/dist/sniffer-D_SYc_pO.cjs.map +0 -1
  187. package/dist/sniffer-aO_-s5vq.mjs.map +0 -1
  188. package/dist/terminal-D0f1u0LG.cjs.map +0 -1
  189. package/dist/terminal-gMxAo9Dj.mjs.map +0 -1
  190. package/dist/types-CfLKGfC_.d.mts.map +0 -1
  191. package/dist/types-DIA7Li-J.d.cts.map +0 -1
  192. package/dist/workspace-Dh7rr7l4.mjs.map +0 -1
  193. package/dist/workspace-Kl4NG9IH.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-LKKCVCnC.mjs","names":["z.discriminatedUnion","z.object","z.literal","z.record","z.string","z.unknown","z.array"],"sources":["../src/workspace/derive.ts","../src/config.ts"],"sourcesContent":["/**\n * The apps a manifest implies.\n *\n * `gkm.config.ts` used to carry an `apps` block naming every app: its type, its\n * path, its port, its framework, which other apps it depended on. Every one of\n * those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`\n * and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',\n * dependencies: ['api'] }` are the same statement written twice, and only one of\n * them was checked against anything — so the copy in config was free to drift,\n * and a surface config had no entry for simply never deployed.\n *\n * So the list comes from the graph. A `site` is an app, and so is every\n * `rest-api` — one surface, one container, at the `path` it declared.\n *\n * What config still supplies is what no graph can answer: the backends a cache\n * and a mailer resolve to, the deploy endpoint, the stage's domain.\n */\n\nimport {\n\ttype AppSpec,\n\ttype ConstructManifest,\n\tkebabCase,\n} from '@geekmidas/manifest';\nimport type {\n\tAppDomainConfig,\n\tDeployTargetName,\n\tFramework,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from './types.js';\n\n/** Which frontend framework builds each site variant. */\nconst FRAMEWORKS: Record<string, Framework> = {\n\tstatic: 'vite',\n\tnext: 'nextjs',\n\ttanstack: 'tanstack-start',\n};\n\n/**\n * The app key a construct id becomes.\n *\n * The same kebab form every physical name is built from, so `Api` is `api` in\n * the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an\n * environment — one id, three renderings, no second list.\n */\nexport function appKey(id: string): string {\n\treturn kebabCase(id);\n}\n\n/**\n * The app serving a surface: its own, always.\n *\n * Every surface gets a container. There is no arrangement in which one runs\n * inside another — two surfaces in a process share a filesystem, an\n * environment, and every credential either was granted, so an auth server\n * beside an API is one bug in the API away from being read by it.\n */\nexport function hostOf(\n\tmanifest: ConstructManifest,\n\tid: string,\n): string | undefined {\n\tconst declaration = manifest[id];\n\tif (!declaration || declaration.kind !== 'rest-api') return undefined;\n\n\treturn id;\n}\n\n/**\n * Local ports, assigned so that adding a site does not renumber the others.\n *\n * Backends first, then the site holding the base domain, then the rest\n * alphabetically. The ordering is arbitrary but it is *fixed*, which is the\n * property that matters: a port that moves when an unrelated app is added is a\n * port nobody can put in a bookmark. A construct that names its own port keeps\n * it, and is skipped here.\n */\nfunction assignPorts(apps: Record<string, NormalizedAppConfig>): void {\n\tconst rank = (\n\t\tname: string,\n\t\tapp: NormalizedAppConfig,\n\t): [number, number, string] => [\n\t\tapp.type === 'backend' ? 0 : app.type === 'web' ? 1 : 2,\n\t\tapp.root ? 0 : 1,\n\t\tname,\n\t];\n\n\tconst ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {\n\t\tconst [at, ar, an] = rank(aName, a);\n\t\tconst [bt, br, bn] = rank(bName, b);\n\t\treturn at - bt || ar - br || an.localeCompare(bn);\n\t});\n\n\tconst taken = new Set(\n\t\tordered.map(([, app]) => app.port).filter((p): p is number => !!p),\n\t);\n\n\tlet next = 3000;\n\tfor (const [, app] of ordered) {\n\t\tif (app.port) continue;\n\t\twhile (taken.has(next)) next += 1;\n\t\tapp.port = next;\n\t\ttaken.add(next);\n\t}\n}\n\n/**\n * Whichever site holds the base domain.\n *\n * The convention first — a site named `web` — because it is one people already\n * rely on. Then an explicit `root: true`. A project with one site needs neither.\n */\nfunction markRoot(apps: Record<string, NormalizedAppConfig>): void {\n\tconst sites = Object.entries(apps).filter(([, a]) => a.type === 'web');\n\tif (sites.length === 0) return;\n\tif (sites.some(([, a]) => a.root)) return;\n\n\tconst chosen =\n\t\tsites.find(([name]) => name === 'web') ??\n\t\t(sites.length === 1 ? sites[0] : undefined);\n\tif (chosen) chosen[1].root = true;\n}\n\nexport function derivedApps(\n\tmanifest: ConstructManifest,\n\tworkspace: NormalizedWorkspace,\n): Record<string, NormalizedAppConfig> {\n\tconst apps: Record<string, NormalizedAppConfig> = {};\n\tconst defaultTarget: DeployTargetName =\n\t\tworkspace.deploy?.default ?? 'dokploy';\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\t// Three kinds are apps: a site, a mobile app and an HTTP surface. A worker\n\t\t// is not one — it names the process that runs a cron or a subscriber, and\n\t\t// that process is the app's server, which already exists. Everything else\n\t\t// is a resource one of them uses.\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\t// No opt-in to be had. Each says where it lives.\n\t\tconst spec: AppSpec =\n\t\t\tdeclaration.kind === 'site' || declaration.kind === 'mobile-app'\n\t\t\t\t? declaration.app\n\t\t\t\t: {\n\t\t\t\t\t\tpath: declaration.path,\n\t\t\t\t\t\t...(declaration.telescope ? { telescope: true } : {}),\n\t\t\t\t\t};\n\n\t\tconst name = appKey(id);\n\t\t// A config entry of the same name still wins, so a workspace can override\n\t\t// one field without restating the app. Nothing in this repo needs to.\n\t\tconst configured = workspace.apps[name];\n\n\t\tapps[name] = {\n\t\t\t...configured,\n\t\t\ttype:\n\t\t\t\tdeclaration.kind === 'site'\n\t\t\t\t\t? 'web'\n\t\t\t\t\t: declaration.kind === 'mobile-app'\n\t\t\t\t\t\t? 'mobile'\n\t\t\t\t\t\t: 'backend',\n\t\t\tpath: spec.path,\n\t\t\tport: spec.port ?? configured?.port ?? 0,\n\t\t\t// The label it answers on, under a stage's domain and locally alike.\n\t\t\t...((declaration.kind === 'rest-api' || declaration.kind === 'site') &&\n\t\t\tdeclaration.subdomain\n\t\t\t\t? { subdomain: declaration.subdomain }\n\t\t\t\t: {}),\n\t\t\tdependencies: [],\n\t\t\tresolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,\n\t\t\t...(declaration.kind === 'site'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? FRAMEWORKS[declaration.variant],\n\t\t\t\t\t\t...(declaration.root ? { root: true } : {}),\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(declaration.kind === 'mobile-app'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? declaration.variant,\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t// One glob fans out to the six the build reads, because each generator\n\t\t\t// already inspects every export and keeps what it recognises. A\n\t\t\t// per-kind field still wins where one was given.\n\t\t\t...(spec.telescope !== undefined ? { telescope: spec.telescope } : {}),\n\t\t\t...(spec.openapi !== undefined ? { openapi: spec.openapi } : {}),\n\t\t\t...(spec.runtime !== undefined ? { runtime: spec.runtime } : {}),\n\t\t\t...(spec.env !== undefined ? { env: spec.env } : {}),\n\t\t\t...(spec.entry !== undefined ? { entry: spec.entry } : {}),\n\t\t\t...(configured?.domain\n\t\t\t\t? { domain: configured.domain as AppDomainConfig }\n\t\t\t\t: {}),\n\t\t} as NormalizedAppConfig;\n\t}\n\n\t// Build order, from the edges rather than from a hand-kept list. A site that\n\t// depends on a surface depends on the app that serves it — which for a\n\t// mounted auth server is its host, not a container that does not exist.\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\tconst app = apps[appKey(id)];\n\t\tif (!app) continue;\n\n\t\t// A site names its edges `dependencies`; a surface names them `calls`.\n\t\tconst edges =\n\t\t\tdeclaration.kind === 'rest-api'\n\t\t\t\t? (declaration.calls ?? [])\n\t\t\t\t: (declaration.dependencies ?? []);\n\n\t\tconst names = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tif (edge.kind !== 'rest-api') continue;\n\t\t\tconst host = hostOf(manifest, edge.target);\n\t\t\tif (!host) continue;\n\t\t\tconst key = appKey(host);\n\t\t\tif (key !== appKey(id) && apps[key]) names.add(key);\n\t\t}\n\n\t\tapp.dependencies = [...names].sort();\n\t}\n\n\tmarkRoot(apps);\n\tassignPorts(apps);\n\n\t// Apps config declared that the graph knows nothing about — a `type: 'mobile'`\n\t// entry, or a hand-run process. Kept rather than dropped: config is still the\n\t// escape hatch for what nothing declares.\n\tfor (const [name, app] of Object.entries(workspace.apps)) {\n\t\tif (!apps[name]) apps[name] = app;\n\t}\n\n\treturn apps;\n}\n","import { existsSync, realpathSync } from 'node:fs';\nimport { dirname, join, parse, resolve, sep } from 'node:path';\nimport { z } from 'zod';\nimport { output } from './output.js';\nimport { discover } from './reconcile/discover.js';\nimport { activeSandbox, type Sandbox } from './sandbox/sandbox.js';\nimport { runWorker } from './sandbox/worker.js';\nimport type { GkmConfig } from './types.js';\nimport { derivedApps } from './workspace/derive.js';\nimport {\n\tallConstructGlobs,\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\n// What `gkm dev`'s discovery endpoint answers, for the tools that read it.\nexport type {\n\tAppStatus,\n\tDataApiKind,\n\tDiscoveredApp,\n\tDiscoveredDataApi,\n\tDiscoveredWorkspace,\n\tDiscoveryEvent,\n\tDiscoveryResponse,\n} from './dev/discovery.js';\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\nexport type { DevConfig } from './workspace/types.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new ConfigNotFound(cwd);\n}\n\n/**\n * The directory holding the gkm config that `cwd` belongs to — the project a\n * sandbox for it is confined to.\n *\n * @throws {ConfigNotFound} when neither `cwd` nor any parent has one.\n */\nexport function findWorkspaceRoot(cwd: string): string {\n\treturn findConfigPath(cwd).workspaceRoot;\n}\n\n/** No gkm config in a directory or any of its parents. */\nexport class ConfigNotFound extends Error {\n\tconstructor(readonly cwd: string) {\n\t\tsuper(\n\t\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t\t);\n\t\tthis.name = 'ConfigNotFound';\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\nexport interface LoadConfigOptions {\n\t/**\n\t * Load the config — and discover the constructs it names — in this\n\t * sandbox rather than in this process. The config then arrives as data;\n\t * see {@link Sandbox.isolating} for what happens to one holding live\n\t * objects. Defaults to the run's own (`withSandbox`); with neither, the\n\t * config is imported here, as `gkm` always has.\n\t */\n\tsandbox?: Sandbox;\n\t/**\n\t * How long the sandboxed config load may run. Defaults to\n\t * {@link CONFIG_LOAD_TIMEOUT_MS}.\n\t */\n\ttimeoutMs?: number;\n}\n\n/**\n * How long loading a config, or discovering its constructs, may take in a\n * sandbox: room for tsx to compile a large project cold, and not a deploy\n * held open by a config that never finishes importing.\n */\nexport const CONFIG_LOAD_TIMEOUT_MS = 60_000;\n\n/** The config failed to import, or threw while it ran. */\nexport class ConfigLoadFailed extends Error {\n\tconstructor(\n\t\treadonly configPath: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(`Failed to load config: ${detail}`);\n\t\tthis.name = 'ConfigLoadFailed';\n\t}\n}\n\n/**\n * The config holds something that is not data — a custom state store, an\n * inline deploy target, a function — and the sandbox it was loaded in hands\n * the deploy nothing but data.\n */\nexport class ConfigObjectNotSerializable extends Error {\n\tconstructor(\n\t\treadonly configPath: string,\n\t\treadonly paths: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${configPath} holds values that are not plain data at: ` +\n\t\t\t\t`${paths.join(', ')}. It was loaded in an isolating sandbox, which ` +\n\t\t\t\t'hands the deploy the config as JSON, so a live object — a custom ' +\n\t\t\t\t'store, an inline target, a function — cannot reach it. Configure ' +\n\t\t\t\t'these with plain values instead, or deploy this project with a ' +\n\t\t\t\t'sandbox that is not isolating (the default) if the host trusts it.',\n\t\t);\n\t\tthis.name = 'ConfigObjectNotSerializable';\n\t}\n}\n\n/** What the config worker answers. Checked: the worker ran project code. */\nconst ConfigAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('loaded'),\n\t\tconfig: z.record(z.string(), z.unknown()),\n\t}),\n\tz.object({ reason: z.literal('live'), paths: z.array(z.string()) }),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.object({ name: z.string(), message: z.string() }),\n\t}),\n]);\n\n/** Import the config in this process — live objects and all. */\nasync function importConfig(\n\tconfigPath: string,\n): Promise<GkmConfig | WorkspaceConfig> {\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn config.default;\n\t} catch (error) {\n\t\tthrow new ConfigLoadFailed(configPath, (error as Error).message);\n\t}\n}\n\n/**\n * The config, loaded in `sandbox` and handed back as JSON.\n *\n * A config holding live objects cannot come back that way. An isolating\n * sandbox refuses it with {@link ConfigObjectNotSerializable}; any other\n * imports it here as well, as before, since the host already runs this\n * project's code as its own.\n */\nasync function loadConfigInSandbox(\n\tsandbox: Sandbox,\n\tconfigPath: string,\n\tworkspaceRoot: string,\n\ttimeoutMs = CONFIG_LOAD_TIMEOUT_MS,\n): Promise<GkmConfig | WorkspaceConfig> {\n\tconst { value } = await runWorker(sandbox, 'config load', {\n\t\tname: 'config-worker',\n\t\targs: [configPath],\n\t\tcwd: workspaceRoot,\n\t\ttimeoutMs,\n\t\tschema: ConfigAnswer,\n\t});\n\n\tswitch (value.reason) {\n\t\tcase 'loaded':\n\t\t\t// Its shape is `processConfig`'s to check, against the workspace\n\t\t\t// schema, exactly as for a config imported here.\n\t\t\treturn value.config as unknown as GkmConfig | WorkspaceConfig;\n\t\tcase 'failed':\n\t\t\tthrow new ConfigLoadFailed(configPath, value.error.message);\n\t\tcase 'live':\n\t\t\tif (sandbox.isolating) {\n\t\t\t\tthrow new ConfigObjectNotSerializable(configPath, value.paths);\n\t\t\t}\n\t\t\treturn importConfig(configPath);\n\t}\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(\n\tcwd: string,\n\toptions: LoadConfigOptions = {},\n): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\t// The run's own sandbox when none is given: a deploy reloads the config\n\t// deep in the engine (generating Dockerfiles), and that load is the\n\t// project's code as much as the first.\n\tconst sandbox = options.sandbox ?? activeSandbox();\n\tconst config = sandbox\n\t\t? await loadConfigInSandbox(\n\t\t\t\tsandbox,\n\t\t\t\tconfigPath,\n\t\t\t\tworkspaceRoot,\n\t\t\t\toptions.timeoutMs,\n\t\t\t)\n\t\t: await importConfig(configPath);\n\n\treturn { config, workspaceRoot };\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\n/**\n * The workspace a directory belongs to, as its config states it — without\n * discovering its constructs.\n *\n * For callers that need a fact the config holds (where a stage's secrets are\n * stored) and nothing the graph adds. `loadWorkspaceConfig` imports every\n * construct module to derive the apps, which is a cost a secrets read should\n * not pay.\n */\nexport async function loadWorkspaceSettings(\n\tcwd: string = process.cwd(),\n\toptions: LoadConfigOptions = {},\n): Promise<LoadedConfig['workspace']> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd, options);\n\treturn processConfig(config, workspaceRoot).workspace;\n}\n\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n\toptions: LoadConfigOptions = {},\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd, options);\n\treturn withDerivedApps(processConfig(config, workspaceRoot), options.sandbox);\n}\n\n/**\n * The loaded config, with its apps read off the graph.\n *\n * Here rather than at each call site because every command needs the same\n * answer, and the ones that forgot to ask were exactly the bugs: a site that\n * never deployed, a surface that could not be its own process. `gkm dev`,\n * `gkm build`, `gkm docker` and `gkm deploy` now all see the same apps without\n * any of them knowing a derivation happened.\n *\n * Discovery imports the construct modules — declarations only, not endpoints —\n * which is the same import the reconciler and the build already do. A workspace\n * with no `constructs` glob discovers nothing and keeps whatever its config\n * said, so nothing that worked before changes.\n *\n * A construct file that throws is reported and skipped rather than taking the\n * command down: `gkm dev` failing to start because a half-written declaration\n * cannot be imported is a worse failure than starting with the app it does not\n * describe yet.\n */\nasync function withDerivedApps(\n\tloaded: LoadedConfig,\n\tsandbox?: Sandbox,\n): Promise<LoadedConfig> {\n\tconst globs = allConstructGlobs(loaded.workspace);\n\tif (globs.length === 0) {\n\t\tthrow new WorkspaceDeclaresNoConstructs(loaded.workspace.root);\n\t}\n\n\ttry {\n\t\tconst manifest = await discover({\n\t\t\tpatterns: globs,\n\t\t\tcwd: loaded.workspace.root,\n\t\t\t...(sandbox ? { sandbox } : {}),\n\t\t});\n\n\t\treturn {\n\t\t\t...loaded,\n\t\t\tmanifest,\n\t\t\tworkspace: {\n\t\t\t\t...loaded.workspace,\n\t\t\t\tapps: derivedApps(manifest, loaded.workspace),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\toutput.warn(\n\t\t\t`⚠️ Could not read constructs, so apps come from config alone: ${message}`,\n\t\t);\n\t\treturn loaded;\n\t}\n}\n\n/**\n * A workspace with no `constructs` glob.\n *\n * In v10 every address, container and app comes from what the workspace\n * declares — there is no second path that reads a hand-written compose file or\n * an `apps` block's ports. A config that declares nothing has nothing to run.\n */\nexport class WorkspaceDeclaresNoConstructs extends Error {\n\tconstructor(readonly root: string) {\n\t\tsuper(\n\t\t\t`The workspace at ${root} declares no constructs. Every workspace names ` +\n\t\t\t\t\"where its constructs live — `constructs: ['./constructs/**/*.ts', \" +\n\t\t\t\t\"'./apps/*/endpoints/**/*.ts']` in gkm.config.ts — and its apps, \" +\n\t\t\t\t'containers and URLs are derived from them.',\n\t\t);\n\t\tthis.name = 'WorkspaceDeclaresNoConstructs';\n\t}\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * The app a directory is part of: the one whose `path` contains it.\n *\n * An app's path is the one its construct declares — `new RestApi('Api',\n * { path: 'apps/api' })` — read off the workspace the constructs were derived\n * into, never off the filesystem's package names. The deepest match wins, so\n * an app inside another app's folder is its own; the workspace root belongs to\n * no app unless one lives there.\n */\nfunction resolveWorkspaceApp(\n\tloadedConfig: LoadedConfig,\n\tcwd: string,\n): { key: string; app: NormalizedAppConfig } | undefined {\n\tconst here = real(cwd);\n\tlet found: { key: string; app: NormalizedAppConfig; dir: string } | undefined;\n\n\tfor (const [key, app] of Object.entries(loadedConfig.workspace.apps)) {\n\t\tconst dir = real(join(loadedConfig.workspace.root, app.path));\n\t\tconst inside = here === dir || here.startsWith(`${dir}${sep}`);\n\t\tif (inside && (!found || dir.length > found.dir.length)) {\n\t\t\tfound = { key, app, dir };\n\t\t}\n\t}\n\n\treturn found && { key: found.key, app: found.app };\n}\n\n/** A path with its symlinks resolved, where it exists — `/tmp` is `/private/tmp`. */\nfunction real(path: string): string {\n\tconst absolute = resolve(path);\n\treturn existsSync(absolute) ? realpathSync(absolute) : absolute;\n}\n\n/** A directory that no app in the workspace lives in. */\nexport class NotInAnApp extends Error {\n\tconstructor(\n\t\treadonly cwd: string,\n\t\treadonly apps: Readonly<Record<string, string>>,\n\t) {\n\t\tsuper(\n\t\t\t`${cwd} is not inside any app's path. Apps: ` +\n\t\t\t\tObject.entries(apps)\n\t\t\t\t\t.map(([key, path]) => `${key} (${path})`)\n\t\t\t\t\t.join(', ') +\n\t\t\t\t'.',\n\t\t);\n\t\tthis.name = 'NotInAnApp';\n\t}\n}\n\n/** Every app's path, by key — what `NotInAnApp` lists. */\nfunction appPaths(loadedConfig: LoadedConfig): Record<string, string> {\n\treturn Object.fromEntries(\n\t\tObject.entries(loadedConfig.workspace.apps).map(([key, app]) => [\n\t\t\tkey,\n\t\t\tapp.path,\n\t\t]),\n\t);\n}\n\n/**\n * The backend app a directory is part of, with its gkm config — found by the\n * `path` its construct declares.\n *\n * @example\n * ```ts\n * // From apps/api, where a construct declares `path: 'apps/api'`\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * ```\n *\n * @throws {NotInAnApp} when no app's path contains the directory.\n * @throws {NotABackendApp} when the app it is in has no gkm config to run.\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst { appName, app, workspace, workspaceRoot } =\n\t\tawait loadWorkspaceAppInfo(cwd);\n\n\tconst gkmConfig = getAppGkmConfig(workspace, appName);\n\tif (!gkmConfig) throw new NotABackendApp(appName);\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n\n/** The app a directory is in has no gkm config — a site, or an entry app. */\nexport class NotABackendApp extends Error {\n\tconstructor(readonly appName: string) {\n\t\tsuper(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t\tthis.name = 'NotABackendApp';\n\t}\n}\n\nexport interface WorkspaceAppInfo {\n\t/** The app's key in the workspace. */\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n}\n\n/**\n * The app a directory is part of, frontend or backend — found by the `path`\n * its construct declares. Unlike `loadAppConfig`, the app need not have a\n * gkm config, which is what `gkm exec` and `gkm test` from a site need.\n *\n * @throws {NotInAnApp} when no app's path contains the directory.\n */\nexport async function loadWorkspaceAppInfo(\n\tcwd: string = process.cwd(),\n): Promise<WorkspaceAppInfo> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = await withDerivedApps(\n\t\tprocessConfig(config, workspaceRoot),\n\t);\n\n\tconst resolved = resolveWorkspaceApp(loadedConfig, cwd);\n\tif (!resolved) throw new NotInAnApp(cwd, appPaths(loadedConfig));\n\n\treturn {\n\t\tappName: resolved.key,\n\t\tapp: resolved.app,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t};\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"define-CHBIEc5j.mjs","names":[],"sources":["../src/target/builtins.ts","../src/target/define.ts"],"sourcesContent":["/**\n * The target names the CLI knows without being told, and how a name is\n * looked up.\n *\n * Plain data, so the config schema and `providerOf` — which `gkm dev` and\n * `gkm build` call synchronously on every start — can ask what a name means\n * without importing a deploy engine.\n */\n\nimport type { DeployRuntime, DeployTargetEntry } from './types';\n\n/**\n * - `available`: `gkm deploy` deploys through it.\n * - `external`: a valid `deploy.default` that builds and runs locally, but is\n * deployed by its own tool — `gkm deploy` refuses it and says which.\n * - `planned`: reserved, and refused everywhere.\n */\nexport type BuiltinStatus = 'available' | 'external' | 'planned';\n\nexport interface BuiltinTarget {\n\treadonly runtime: DeployRuntime;\n\treadonly status: BuiltinStatus;\n\t/** What to do instead, for a target `gkm deploy` cannot deploy through yet. */\n\treadonly instead?: (stage: string) => string;\n}\n\nexport const BUILTIN_TARGETS = {\n\tdokploy: { runtime: 'server', status: 'available' },\n\tsst: {\n\t\truntime: 'aws',\n\t\tstatus: 'external',\n\t\tinstead: (stage) => `run \\`gkm build && sst deploy --stage ${stage}\\``,\n\t},\n\t// Neither runs containers the project controls, so both take the managed\n\t// defaults when they arrive.\n\tvercel: { runtime: 'aws', status: 'planned' },\n\tcloudflare: { runtime: 'aws', status: 'planned' },\n} as const satisfies Record<string, BuiltinTarget>;\n\nexport type BuiltinTargetName = keyof typeof BUILTIN_TARGETS;\n\n/** The built-in target called `name`, if one is. */\nexport function builtinTarget(name: string): BuiltinTarget | undefined {\n\treturn Object.hasOwn(BUILTIN_TARGETS, name)\n\t\t? BUILTIN_TARGETS[name as BuiltinTargetName]\n\t\t: undefined;\n}\n\n/** Built-in names a config may use. */\nexport function configurableBuiltins(): string[] {\n\treturn Object.entries(BUILTIN_TARGETS)\n\t\t.filter(([, target]) => target.status !== 'planned')\n\t\t.map(([name]) => name);\n}\n\n/** The `deploy.targets` entry called `name`, if the config has one. */\nexport function configuredTarget(\n\tdeploy: { targets?: Record<string, DeployTargetEntry> } | undefined,\n\tname: string,\n): DeployTargetEntry | undefined {\n\tconst targets = deploy?.targets;\n\treturn targets && Object.hasOwn(targets, name) ? targets[name] : undefined;\n}\n\n/** A target name that is neither built in nor in `deploy.targets`. */\nexport class UnknownDeployTarget extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** The names that would have resolved. */\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Unknown deploy target \"${target}\". Use one of ${known.join(', ')}, or name the package that provides it in gkm.config.ts: deploy: { targets: { ${JSON.stringify(target)}: '<package>' } }.`,\n\t\t);\n\t\tthis.name = 'UnknownDeployTarget';\n\t}\n}\n\n/** A built-in target `gkm deploy` cannot deploy through yet. */\nexport class DeployTargetNotYetSupported extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** What to do instead, when there is something. */\n\t\treadonly instead?: string,\n\t) {\n\t\tsuper(\n\t\t\tinstead\n\t\t\t\t? `gkm deploy cannot deploy through \"${target}\" yet: ${instead}.`\n\t\t\t\t: `Deploy target \"${target}\" is not supported yet. Deploy with dokploy, or name a target package in deploy.targets.`,\n\t\t);\n\t\tthis.name = 'DeployTargetNotYetSupported';\n\t}\n}\n","import type { AnyDeployTarget, DeployTarget } from './types';\n\n/**\n * A deploy target, typed from what it is written with: the options from its\n * `options` schema, the run state from what `validate` returns. Nothing\n * happens at runtime — it returns the target as given.\n *\n * ```ts\n * export default defineTarget({\n * name: 'fly',\n * runtime: 'server',\n * capabilities: { rollback: true, migrations: 'target', images: true },\n * options: z.object({ org: z.string() }),\n * async validate(ctx) {\n * return { org: ctx.options.org }; // ctx.options: { org: string }\n * },\n * async release(ctx, run) { … }, // run: { org: string }\n * …\n * });\n * ```\n */\nexport function defineTarget<Options = undefined, Run = void>(\n\ttarget: DeployTarget<Options, Run>,\n): DeployTarget<Options, Run> {\n\treturn target;\n}\n\n/** Whether `value` has the shape of a target. */\nexport function isDeployTarget(value: unknown): value is AnyDeployTarget {\n\tif (!value || typeof value !== 'object') return false;\n\tconst candidate = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof candidate.name === 'string' &&\n\t\t(candidate.runtime === 'server' || candidate.runtime === 'aws') &&\n\t\ttypeof candidate.capabilities === 'object' &&\n\t\tcandidate.capabilities !== null &&\n\t\t['validate', 'plan', 'release', 'result'].every(\n\t\t\t(phase) => typeof candidate[phase] === 'function',\n\t\t)\n\t);\n}\n"],"mappings":";AA0BA,MAAa,kBAAkB;CAC9B,SAAS;EAAE,SAAS;EAAU,QAAQ;CAAY;CAClD,KAAK;EACJ,SAAS;EACT,QAAQ;EACR,UAAU,UAAU,yCAAyC,MAAM;CACpE;CAGA,QAAQ;EAAE,SAAS;EAAO,QAAQ;CAAU;CAC5C,YAAY;EAAE,SAAS;EAAO,QAAQ;CAAU;AACjD;;AAKA,SAAgB,cAAc,MAAyC;CACtE,OAAO,OAAO,OAAO,iBAAiB,IAAI,IACvC,gBAAgB,QAChB,KAAA;AACJ;;AAGA,SAAgB,uBAAiC;CAChD,OAAO,OAAO,QAAQ,eAAe,CAAC,CACpC,QAAQ,GAAG,YAAY,OAAO,WAAW,SAAS,CAAC,CACnD,KAAK,CAAC,UAAU,IAAI;AACvB;;AAGA,SAAgB,iBACf,QACA,MACgC;CAChC,MAAM,UAAU,QAAQ;CACxB,OAAO,WAAW,OAAO,OAAO,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAA;AAClE;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CAEpC;CAEA;CAHV,YACC,QAEA,OACC;EACD,MACC,0BAA0B,OAAO,gBAAgB,MAAM,KAAK,IAAI,EAAE,gFAAgF,KAAK,UAAU,MAAM,EAAE,mBAC1K;EANS,KAAA,SAAA;EAEA,KAAA,QAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,8BAAb,cAAiD,MAAM;CAE5C;CAEA;CAHV,YACC,QAEA,SACC;EACD,MACC,UACG,qCAAqC,OAAO,SAAS,QAAQ,KAC7D,kBAAkB,OAAO,yFAC7B;EARS,KAAA,SAAA;EAEA,KAAA,UAAA;EAOT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;;;;;;ACvEA,SAAgB,aACf,QAC6B;CAC7B,OAAO;AACR;;AAGA,SAAgB,eAAe,OAA0C;CACxE,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,MAAM,YAAY;CAClB,OACC,OAAO,UAAU,SAAS,aACzB,UAAU,YAAY,YAAY,UAAU,YAAY,UACzD,OAAO,UAAU,iBAAiB,YAClC,UAAU,iBAAiB,QAC3B;EAAC;EAAY;EAAQ;EAAW;CAAQ,CAAC,CAAC,OACxC,UAAU,OAAO,UAAU,WAAW,UACxC;AAEF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"define-Cv_QvDrg.cjs","names":[],"sources":["../src/target/builtins.ts","../src/target/define.ts"],"sourcesContent":["/**\n * The target names the CLI knows without being told, and how a name is\n * looked up.\n *\n * Plain data, so the config schema and `providerOf` — which `gkm dev` and\n * `gkm build` call synchronously on every start — can ask what a name means\n * without importing a deploy engine.\n */\n\nimport type { DeployRuntime, DeployTargetEntry } from './types';\n\n/**\n * - `available`: `gkm deploy` deploys through it.\n * - `external`: a valid `deploy.default` that builds and runs locally, but is\n * deployed by its own tool — `gkm deploy` refuses it and says which.\n * - `planned`: reserved, and refused everywhere.\n */\nexport type BuiltinStatus = 'available' | 'external' | 'planned';\n\nexport interface BuiltinTarget {\n\treadonly runtime: DeployRuntime;\n\treadonly status: BuiltinStatus;\n\t/** What to do instead, for a target `gkm deploy` cannot deploy through yet. */\n\treadonly instead?: (stage: string) => string;\n}\n\nexport const BUILTIN_TARGETS = {\n\tdokploy: { runtime: 'server', status: 'available' },\n\tsst: {\n\t\truntime: 'aws',\n\t\tstatus: 'external',\n\t\tinstead: (stage) => `run \\`gkm build && sst deploy --stage ${stage}\\``,\n\t},\n\t// Neither runs containers the project controls, so both take the managed\n\t// defaults when they arrive.\n\tvercel: { runtime: 'aws', status: 'planned' },\n\tcloudflare: { runtime: 'aws', status: 'planned' },\n} as const satisfies Record<string, BuiltinTarget>;\n\nexport type BuiltinTargetName = keyof typeof BUILTIN_TARGETS;\n\n/** The built-in target called `name`, if one is. */\nexport function builtinTarget(name: string): BuiltinTarget | undefined {\n\treturn Object.hasOwn(BUILTIN_TARGETS, name)\n\t\t? BUILTIN_TARGETS[name as BuiltinTargetName]\n\t\t: undefined;\n}\n\n/** Built-in names a config may use. */\nexport function configurableBuiltins(): string[] {\n\treturn Object.entries(BUILTIN_TARGETS)\n\t\t.filter(([, target]) => target.status !== 'planned')\n\t\t.map(([name]) => name);\n}\n\n/** The `deploy.targets` entry called `name`, if the config has one. */\nexport function configuredTarget(\n\tdeploy: { targets?: Record<string, DeployTargetEntry> } | undefined,\n\tname: string,\n): DeployTargetEntry | undefined {\n\tconst targets = deploy?.targets;\n\treturn targets && Object.hasOwn(targets, name) ? targets[name] : undefined;\n}\n\n/** A target name that is neither built in nor in `deploy.targets`. */\nexport class UnknownDeployTarget extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** The names that would have resolved. */\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Unknown deploy target \"${target}\". Use one of ${known.join(', ')}, or name the package that provides it in gkm.config.ts: deploy: { targets: { ${JSON.stringify(target)}: '<package>' } }.`,\n\t\t);\n\t\tthis.name = 'UnknownDeployTarget';\n\t}\n}\n\n/** A built-in target `gkm deploy` cannot deploy through yet. */\nexport class DeployTargetNotYetSupported extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\t/** What to do instead, when there is something. */\n\t\treadonly instead?: string,\n\t) {\n\t\tsuper(\n\t\t\tinstead\n\t\t\t\t? `gkm deploy cannot deploy through \"${target}\" yet: ${instead}.`\n\t\t\t\t: `Deploy target \"${target}\" is not supported yet. Deploy with dokploy, or name a target package in deploy.targets.`,\n\t\t);\n\t\tthis.name = 'DeployTargetNotYetSupported';\n\t}\n}\n","import type { AnyDeployTarget, DeployTarget } from './types';\n\n/**\n * A deploy target, typed from what it is written with: the options from its\n * `options` schema, the run state from what `validate` returns. Nothing\n * happens at runtime — it returns the target as given.\n *\n * ```ts\n * export default defineTarget({\n * name: 'fly',\n * runtime: 'server',\n * capabilities: { rollback: true, migrations: 'target', images: true },\n * options: z.object({ org: z.string() }),\n * async validate(ctx) {\n * return { org: ctx.options.org }; // ctx.options: { org: string }\n * },\n * async release(ctx, run) { … }, // run: { org: string }\n * …\n * });\n * ```\n */\nexport function defineTarget<Options = undefined, Run = void>(\n\ttarget: DeployTarget<Options, Run>,\n): DeployTarget<Options, Run> {\n\treturn target;\n}\n\n/** Whether `value` has the shape of a target. */\nexport function isDeployTarget(value: unknown): value is AnyDeployTarget {\n\tif (!value || typeof value !== 'object') return false;\n\tconst candidate = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof candidate.name === 'string' &&\n\t\t(candidate.runtime === 'server' || candidate.runtime === 'aws') &&\n\t\ttypeof candidate.capabilities === 'object' &&\n\t\tcandidate.capabilities !== null &&\n\t\t['validate', 'plan', 'release', 'result'].every(\n\t\t\t(phase) => typeof candidate[phase] === 'function',\n\t\t)\n\t);\n}\n"],"mappings":";AA0BA,MAAa,kBAAkB;CAC9B,SAAS;EAAE,SAAS;EAAU,QAAQ;CAAY;CAClD,KAAK;EACJ,SAAS;EACT,QAAQ;EACR,UAAU,UAAU,yCAAyC,MAAM;CACpE;CAGA,QAAQ;EAAE,SAAS;EAAO,QAAQ;CAAU;CAC5C,YAAY;EAAE,SAAS;EAAO,QAAQ;CAAU;AACjD;;AAKA,SAAgB,cAAc,MAAyC;CACtE,OAAO,OAAO,OAAO,iBAAiB,IAAI,IACvC,gBAAgB,QAChB,KAAA;AACJ;;AAGA,SAAgB,uBAAiC;CAChD,OAAO,OAAO,QAAQ,eAAe,CAAC,CACpC,QAAQ,GAAG,YAAY,OAAO,WAAW,SAAS,CAAC,CACnD,KAAK,CAAC,UAAU,IAAI;AACvB;;AAGA,SAAgB,iBACf,QACA,MACgC;CAChC,MAAM,UAAU,QAAQ;CACxB,OAAO,WAAW,OAAO,OAAO,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAA;AAClE;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CAEpC;CAEA;CAHV,YACC,QAEA,OACC;EACD,MACC,0BAA0B,OAAO,gBAAgB,MAAM,KAAK,IAAI,EAAE,gFAAgF,KAAK,UAAU,MAAM,EAAE,mBAC1K;EANS,KAAA,SAAA;EAEA,KAAA,QAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,8BAAb,cAAiD,MAAM;CAE5C;CAEA;CAHV,YACC,QAEA,SACC;EACD,MACC,UACG,qCAAqC,OAAO,SAAS,QAAQ,KAC7D,kBAAkB,OAAO,yFAC7B;EARS,KAAA,SAAA;EAEA,KAAA,UAAA;EAOT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;;;;;;ACvEA,SAAgB,aACf,QAC6B;CAC7B,OAAO;AACR;;AAGA,SAAgB,eAAe,OAA0C;CACxE,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,MAAM,YAAY;CAClB,OACC,OAAO,UAAU,SAAS,aACzB,UAAU,YAAY,YAAY,UAAU,YAAY,UACzD,OAAO,UAAU,iBAAiB,YAClC,UAAU,iBAAiB,QAC3B;EAAC;EAAY;EAAQ;EAAW;CAAQ,CAAC,CAAC,OACxC,UAAU,OAAO,UAAU,WAAW,UACxC;AAEF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"discover-BaT6bpnA.mjs","names":["kebabCase","z.discriminatedUnion","z.object","z.literal","z.record","z.string","z.array","z\n\t\t\t.object"],"sources":["../src/output.ts","../src/generators/Generator.ts","../src/sandbox/sandbox.ts","../src/owningTsconfigJsx.ts","../src/sandbox/worker.ts","../src/reconcile/discover.ts"],"sourcesContent":["/**\n * Where the CLI's progress lines go.\n *\n * Commands write their progress through `output` rather than `console`. Run\n * from the terminal that is the same thing. Run inside `deploy()`, each line\n * goes to the run that wrote it instead — as an event its caller can iterate,\n * and to the logger it was handed — so a deploy embedded in another program\n * does not print over that program's own output.\n *\n * Carried by `AsyncLocalStorage` rather than passed down, because the lines\n * come from everywhere a deploy reaches — the Dockerfile generator, the env\n * sniffer, construct discovery — and two deploys running in one process must\n * not hear each other.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { format } from 'node:util';\n\n/** How loud a line is. */\nexport type OutputLevel = 'info' | 'warn' | 'error';\n\n/** Receives each line written while it is the current sink. */\nexport type OutputSink = (level: OutputLevel, message: string) => void;\n\nconst current = new AsyncLocalStorage<OutputSink>();\n\n/** Runs `fn` with every line written through `output` sent to `sink`. */\nexport function withOutput<T>(sink: OutputSink, fn: () => T): T {\n\treturn current.run(sink, fn);\n}\n\nfunction write(\n\tlevel: OutputLevel,\n\tfallback: (...args: unknown[]) => void,\n): (...args: unknown[]) => void {\n\treturn (...args) => {\n\t\tconst sink = current.getStore();\n\t\tif (sink) sink(level, format(...args));\n\t\telse fallback(...args);\n\t};\n}\n\n/**\n * `console`, for the methods the CLI logs through — routed to the current\n * run's sink when there is one.\n */\nexport const output = {\n\tlog: write('info', (...args) => console.log(...args)),\n\tinfo: write('info', (...args) => console.info(...args)),\n\twarn: write('warn', (...args) => console.warn(...args)),\n\terror: write('error', (...args) => console.error(...args)),\n};\n","import { relative } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\nimport fg from 'fast-glob';\nimport kebabCase from 'lodash.kebabcase';\nimport type { BuildContext } from '../build/types';\nimport type { MainProvider, Routes } from '../types';\n\n/**\n * Zod v4 maintains a process-wide registry of schemas registered via\n * `.meta({ id })`. When we cache-bust user module imports (by appending a\n * `?t=timestamp` query), those modules re-execute and try to register the\n * same ids again, which throws `ID X already exists in the registry`.\n *\n * Clearing the registry in the CLI process is safe: the user's running\n * server lives in a subprocess and has its own isolated registry.\n *\n * Exported for tests.\n */\nexport function clearZodGlobalRegistry(): void {\n\tconst registry = (\n\t\tglobalThis as { __zod_globalRegistry?: { clear?: () => void } }\n\t).__zod_globalRegistry;\n\tif (registry && typeof registry.clear === 'function') {\n\t\tregistry.clear();\n\t}\n}\n\nexport interface GeneratorOptions {\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget?: MainProvider;\n\t/**\n\t * What a handler path in the manifest is relative to — the workspace root,\n\t * which is where `sst.config.ts` runs and resolves it from.\n\t */\n\troot?: string;\n\t[key: string]: any;\n}\n\nexport abstract class ConstructGenerator<T extends Construct, R = void> {\n\tabstract isConstruct(value: any): value is T;\n\n\tstatic async build<T extends Construct, R = void>(\n\t\tcontext: BuildContext,\n\t\toutputDir: string,\n\t\tgenerator: ConstructGenerator<T, R>,\n\t\tpatterns?: Routes,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R> {\n\t\tconst constructs = await generator.load(patterns);\n\t\treturn generator.build(context, constructs, outputDir, options);\n\t}\n\n\tabstract build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<T>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R>;\n\n\tasync load(\n\t\tpatterns?: Routes,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t): Promise<GeneratedConstruct<T>[]> {\n\t\tconst logger = console;\n\n\t\tconst globPatterns = Array.isArray(patterns)\n\t\t\t? patterns\n\t\t\t: patterns\n\t\t\t\t? [patterns]\n\t\t\t\t: [];\n\n\t\t// Find all files\n\t\tconst files = fg.stream(globPatterns, {\n\t\t\tcwd,\n\t\t\tabsolute: true,\n\t\t});\n\n\t\t// Cache-busted re-imports re-execute user modules, which would try to\n\t\t// re-register Zod schemas with the same `.meta({ id })`. Clear the\n\t\t// global registry once per load to prevent duplicate-id errors.\n\t\tif (bustCache) {\n\t\t\tclearZodGlobalRegistry();\n\t\t}\n\n\t\t// Load constructs\n\t\tconst constructs: GeneratedConstruct<T>[] = [];\n\n\t\tfor await (const f of files) {\n\t\t\ttry {\n\t\t\t\tconst file = f.toString();\n\t\t\t\t// Append cache-busting query param to force re-import of changed modules\n\t\t\t\tconst importPath = bustCache ? `${file}?t=${Date.now()}` : file;\n\t\t\t\tconst module = await import(importPath);\n\n\t\t\t\t// Check all exports for constructs\n\t\t\t\tfor (const [key, construct] of Object.entries(module)) {\n\t\t\t\t\tif (this.isConstruct(construct)) {\n\t\t\t\t\t\tconstructs.push({\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tname: kebabCase(key),\n\t\t\t\t\t\t\tconstruct,\n\t\t\t\t\t\t\tpath: {\n\t\t\t\t\t\t\t\tabsolute: file,\n\t\t\t\t\t\t\t\trelative: relative(process.cwd(), file),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`Failed to load ${f}: ${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\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn constructs;\n\t}\n}\n\nexport interface GeneratedConstruct<T extends Construct> {\n\tkey: string;\n\tname: string;\n\tconstruct: T;\n\tpath: {\n\t\tabsolute: string;\n\t\trelative: string;\n\t};\n}\n","/**\n * Where a deploy runs the project's own code.\n *\n * A deploy holds credentials — Dokploy's token, a registry login, an AWS key —\n * and loading `gkm.config.ts`, sniffing an app's environment and building it\n * all execute code from the repository being deployed. On a developer's own\n * laptop that is the developer's code. On a CI job for a fork, or a shared\n * build runner, it is not, and that code should not be able to read the\n * credentials used to deploy it, hang the deploy, or reach outside the\n * checkout.\n *\n * So every step that runs project code goes through a `Sandbox`: one call,\n * with an argument array rather than a shell line, the complete environment\n * the step needs rather than the host's, a timeout it cannot outlive, secrets\n * as files rather than variables, and a working directory inside the project.\n * The steps that need credentials — provisioning, pushing, releasing — are\n * the deploy's own code and never run in one.\n *\n * `LocalSandbox` is the default: a child process on this machine with an\n * allowlisted environment. A host that builds repositories it does not trust\n * passes its own — a container per build, a VM — through `deploy()`'s\n * `sandbox`.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { existsSync, realpathSync } from 'node:fs';\nimport { isAbsolute, relative, resolve, sep } from 'node:path';\n\n/** Where a command's output goes. */\nexport type SandboxOutput = 'capture' | 'inherit' | 'stderr' | 'ignore';\n\nexport interface SandboxExecOptions {\n\t/**\n\t * Where the command runs: the project root or a directory below it, as an\n\t * absolute path or relative to the root. Anywhere else is refused with\n\t * {@link SandboxCwdEscape}.\n\t */\n\tcwd: string;\n\t/**\n\t * The command's whole environment. Nothing of the host's is added to it:\n\t * start from {@link Sandbox.env} and add what the step needs.\n\t */\n\tenv: Readonly<Record<string, string>>;\n\t/**\n\t * How long the command may run before it is killed. Required: a step that\n\t * waits forever — a sniffed entry that opens a server, a build stuck on a\n\t * prompt — would otherwise hold the deploy, and its lock, forever.\n\t */\n\ttimeoutMs: number;\n\t/**\n\t * Files the command can read, by name. Mounted in a directory of their own\n\t * — named by `GKM_SECRETS_DIR` in the command's environment — and removed\n\t * when it exits. Never set as variables, which every child inherits, a\n\t * crash report prints and `/proc/<pid>/environ` shows.\n\t */\n\tsecrets?: Readonly<Record<string, string>>;\n\t/**\n\t * `capture` (the default) returns stdout and stderr in the result;\n\t * `inherit` gives the command the host's terminal; `stderr` sends both\n\t * streams to the host's stderr; `ignore` discards them.\n\t */\n\toutput?: SandboxOutput;\n\t/** Kills the command when aborted; `exec` rejects with the signal's reason. */\n\tsignal?: AbortSignal;\n}\n\n/** How a command ended. A non-zero exit is a result, not an error. */\nexport interface SandboxResult {\n\texitCode: number | null;\n\tsignal: string | null;\n\t/** What it wrote to stdout, when its output was captured. */\n\tstdout: string;\n\t/** What it wrote to stderr, when its output was captured. */\n\tstderr: string;\n}\n\n/**\n * Runs a command against the project, and nothing else of the host's.\n *\n * `exec` resolves with the result however the command exited. It rejects\n * with {@link CommandTimedOut} once the timeout passes — after the command is\n * gone — with {@link SandboxCwdEscape} for a directory outside the project,\n * with the signal's reason when aborted, and with the spawn error when the\n * program cannot be started.\n */\nexport interface Sandbox {\n\t/** The project: the directory every command runs at or below. */\n\treadonly root: string;\n\t/**\n\t * Whether the code it runs is kept from the host: its files, its\n\t * processes, its memory.\n\t *\n\t * An isolating sandbox shares nothing but what crosses `exec`, so a config\n\t * reaches the deploy as data — a live object in it (a custom state store,\n\t * an inline target) cannot cross, and is refused with\n\t * `ConfigObjectNotSerializable`. A non-isolating one, like\n\t * {@link LocalSandbox}, runs on the host as the host's user; a project\n\t * whose config holds live objects is then loaded in-process as before,\n\t * because a project trusted to run there is trusted to do that.\n\t */\n\treadonly isolating: boolean;\n\t/**\n\t * The environment a command starts from: what any program needs to run\n\t * here — `PATH`, `HOME`, the locale — and no credential.\n\t */\n\treadonly env: Readonly<Record<string, string>>;\n\texec(\n\t\tcommand: string,\n\t\targs: readonly string[],\n\t\toptions: SandboxExecOptions,\n\t): Promise<SandboxResult>;\n}\n\n/** The variable naming the directory a command's secrets are mounted in. */\nexport const SECRETS_DIR_ENV = 'GKM_SECRETS_DIR';\n\n/** A command was asked to run outside the project. */\nexport class SandboxCwdEscape extends Error {\n\tconstructor(\n\t\treadonly cwd: string,\n\t\treadonly root: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refusing to run in '${cwd}': it is outside the project at '${root}'. ` +\n\t\t\t\t'A sandboxed step only runs inside the project it was given — check ' +\n\t\t\t\t'the app paths in gkm.config.ts for `..` or an absolute path.',\n\t\t);\n\t\tthis.name = 'SandboxCwdEscape';\n\t}\n}\n\n/** A path with its symlinks resolved where it exists — `/tmp` is `/private/tmp`. */\nfunction real(path: string): string {\n\treturn existsSync(path) ? realpathSync(path) : path;\n}\n\n/**\n * `cwd` as an absolute directory inside `root`, or {@link SandboxCwdEscape}.\n *\n * Symlinks are resolved on both sides first, so a link inside the project\n * that points out of it is an escape, and a project reached through a link\n * (`/tmp` on macOS) is still itself. For a sandbox of a host's own to call\n * before it runs anything.\n */\nexport function confineCwd(root: string, cwd: string): string {\n\tconst absolute = resolve(root, cwd);\n\tconst from = relative(real(resolve(root)), real(absolute));\n\tif (from === '..' || from.startsWith(`..${sep}`) || isAbsolute(from)) {\n\t\tthrow new SandboxCwdEscape(cwd, root);\n\t}\n\treturn absolute;\n}\n\n/** A secret's file name: one path segment, so it cannot be written elsewhere. */\nexport class SecretNameInvalid extends Error {\n\tconstructor(readonly secretName: string) {\n\t\tsuper(\n\t\t\t`'${secretName}' cannot be a secret's name: it becomes a file name in ` +\n\t\t\t\t'the secrets directory, so it must be one segment of letters, digits, ' +\n\t\t\t\t\"'.', '-' or '_' and not start with '.'.\",\n\t\t);\n\t\tthis.name = 'SecretNameInvalid';\n\t}\n}\n\nconst SECRET_NAME = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;\n\n/** Every secret name, checked before anything is written. */\nexport function assertSecretNames(\n\tsecrets: Readonly<Record<string, string>> | undefined,\n): void {\n\tfor (const name of Object.keys(secrets ?? {})) {\n\t\tif (!SECRET_NAME.test(name)) throw new SecretNameInvalid(name);\n\t}\n}\n\n/** A run's sandbox, and what its workers already answered. */\ninterface SandboxRun {\n\tsandbox: Sandbox;\n\tanswers: Map<string, Promise<unknown>>;\n}\n\nconst active = new AsyncLocalStorage<SandboxRun>();\n\n/**\n * Run `fn` with `sandbox` as the one its steps use.\n *\n * Per run rather than global, as `withOutput` routes a run's lines: two\n * deploys in one host process each build in their own sandbox. A step deep in\n * the engine — discovering constructs, sniffing an app — asks\n * {@link activeSandbox} rather than every function between `deploy()` and it\n * taking one more parameter.\n */\nexport function withSandbox<T>(sandbox: Sandbox, fn: () => T): T {\n\treturn active.run({ sandbox, answers: new Map() }, fn);\n}\n\n/** The sandbox of the run this is part of, if it was started with one. */\nexport function activeSandbox(): Sandbox | undefined {\n\treturn active.getStore()?.sandbox;\n}\n\n/**\n * `ask()`'s answer, asked once per run.\n *\n * A deploy loads its config and discovers its constructs from several places\n * — the first load, the engine, the Dockerfile generator — and in a sandbox\n * each was a child process of its own, for the same answer: the checkout does\n * not change while it deploys. Within a run in `sandbox`, the first answer\n * for `key` is the one every later ask gets. Outside one, or for another\n * sandbox, `ask()` runs each time.\n */\nexport function oncePerRun<T>(\n\tsandbox: Sandbox,\n\tkey: string,\n\task: () => Promise<T>,\n): Promise<T> {\n\tconst run = active.getStore();\n\tif (!run || run.sandbox !== sandbox) return ask();\n\n\tlet answer = run.answers.get(key) as Promise<T> | undefined;\n\tif (!answer) {\n\t\tanswer = ask();\n\t\trun.answers.set(key, answer);\n\t\t// A failure is not remembered: the next ask tries again.\n\t\tanswer.catch(() => run.answers.delete(key));\n\t}\n\treturn answer;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nconst REGISTER = 'owning-tsconfig-jsx-register.mjs';\n\n/** The CLI's `bin/` was not found above the module looking for it. */\nexport class OwningTsconfigJsxHookMissing extends Error {\n\tconstructor(readonly from: string) {\n\t\tsuper(\n\t\t\t`Could not find bin/${REGISTER} in any directory above '${from}'. ` +\n\t\t\t\t'It ships with @geekmidas/cli beside bin/gkm.mjs; reinstall the ' +\n\t\t\t\t'package if it is missing.',\n\t\t);\n\t\tthis.name = 'OwningTsconfigJsxHookMissing';\n\t}\n}\n\n/**\n * The CLI's `bin/owning-tsconfig-jsx-register.mjs`, as a file URL. Searched\n * upward because this module runs from `src/` in the repo and from a chunk in\n * `dist/` once built, and `bin/` sits beside both.\n */\nfunction registerUrl(): string {\n\tconst from = dirname(fileURLToPath(import.meta.url));\n\tfor (let dir = from; ; dir = dirname(dir)) {\n\t\tconst candidate = join(dir, 'bin', REGISTER);\n\t\tif (existsSync(candidate)) return pathToFileURL(candidate).href;\n\t\tif (dirname(dir) === dir) throw new OwningTsconfigJsxHookMissing(from);\n\t}\n}\n\n/**\n * `NODE_OPTIONS` for a process that runs app code through tsx, with the hook\n * that compiles each `.tsx` with its own tsconfig's JSX settings (see\n * `bin/owning-tsconfig-jsx.mjs`) put in front of every other `--import`, so it\n * is registered before tsx and reads the source on tsx's behalf.\n *\n * `bin/gkm.mjs` already starts the CLI this way, and its children inherit it;\n * this is for those that set `NODE_OPTIONS` themselves, or whose CLI was\n * started with tsx already imported.\n */\nexport function withOwningTsconfigJsx(nodeOptions = ''): string {\n\tif (nodeOptions.includes(REGISTER)) return nodeOptions;\n\treturn [`--import=${registerUrl()}`, nodeOptions].filter(Boolean).join(' ');\n}\n","/**\n * Running one of the CLI's own worker scripts inside a sandbox, and reading\n * back the one JSON value it answers with.\n *\n * The worker imports the project's TypeScript — `gkm.config.ts`, construct\n * modules, an app's entry — so it starts with the CLI's own tsx and the two\n * hooks `gkm` itself runs with (JSX by the owning tsconfig, path aliases by\n * the adjacent one). The host process needs none of them loaded: a program\n * calling `deploy()` without `--import tsx` still loads a TypeScript config.\n */\n\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport type { z } from 'zod';\nimport { withOwningTsconfigJsx } from '../owningTsconfigJsx';\nimport { oncePerRun, type Sandbox } from './sandbox';\nimport { WORKER_RESULT_MARKER } from './workerRuntime';\n\nconst here = dirname(fileURLToPath(import.meta.url));\n\n/**\n * A worker's file: `dist/sandbox/<name>.mjs` once built — whether this module\n * was bundled into `dist/` or sits beside it — or the `.ts` source under tsx.\n */\nexport function workerFile(name: string): string {\n\tconst candidates = [\n\t\tjoin(here, 'sandbox', `${name}.mjs`),\n\t\tjoin(here, `${name}.mjs`),\n\t\tjoin(here, '..', 'sandbox', `${name}.mjs`),\n\t\tjoin(here, `${name}.ts`),\n\t];\n\treturn (\n\t\tcandidates.find((path) => existsSync(path)) ?? join(here, `${name}.ts`)\n\t);\n}\n\n/** tsx, from the CLI's own dependencies — never the project's. */\nexport function tsxUrl(): string {\n\treturn pathToFileURL(createRequire(import.meta.url).resolve('tsx')).href;\n}\n\n/**\n * `node`'s arguments for `script`: the CLI's TypeScript loaders, then any\n * further `imports`, then the script and its `args` — an argument array, so\n * nothing about a path is read by a shell.\n */\nexport function nodeWithTsx(\n\tscript: string,\n\targs: readonly string[],\n\timports: readonly string[] = [],\n): string[] {\n\treturn [\n\t\t...withOwningTsconfigJsx(`--import=${tsxUrl()}`).split(' '),\n\t\t...imports.map((path) => `--import=${pathToFileURL(path).href}`),\n\t\tscript,\n\t\t...args,\n\t];\n}\n\n/** A worker ended without the answer it exists to give. */\nexport class SandboxWorkerFailed extends Error {\n\tconstructor(\n\t\treadonly step: string,\n\t\treadonly exitCode: number | null,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`The sandboxed ${step} ended (exit code ${exitCode}) without an ` +\n\t\t\t\t`answer.${stderr.trim() ? `\\n${stderr.trim()}` : ''}\\nIts output ` +\n\t\t\t\t'above says why; the sandbox must be able to run `node` with the ' +\n\t\t\t\t\"CLI's own files at the paths they have here.\",\n\t\t);\n\t\tthis.name = 'SandboxWorkerFailed';\n\t}\n}\n\nexport interface WorkerRun<T> {\n\t/** What the worker answered, as the schema reads it. */\n\tvalue: T;\n\t/** What it wrote to stderr: warnings a caller may pass on. */\n\tstderr: string;\n}\n\n/**\n * Run worker `name` in `sandbox`, and parse its answer with `schema`.\n *\n * The answer is the last marked line on stdout. Anything else the project's\n * code printed is ignored, and an answer the schema refuses is a failure\n * rather than data — a worker in an isolating sandbox runs code the host does\n * not trust.\n *\n * Within a run (`withSandbox`), the same worker asked the same question is\n * started once; every ask gets its own copy of the answer, and its stderr, as\n * though it had run again.\n */\nexport async function runWorker<S extends z.ZodType>(\n\tsandbox: Sandbox,\n\tstep: string,\n\toptions: WorkerOptions<S>,\n): Promise<WorkerRun<z.infer<S>>> {\n\tconst key = JSON.stringify([\n\t\toptions.name,\n\t\toptions.cwd,\n\t\toptions.args,\n\t\toptions.env ?? {},\n\t]);\n\tconst answer = await oncePerRun(sandbox, key, () =>\n\t\tstartWorker(sandbox, step, options),\n\t);\n\treturn structuredClone(answer);\n}\n\ninterface WorkerOptions<S extends z.ZodType> {\n\tname: string;\n\targs: readonly string[];\n\tcwd: string;\n\ttimeoutMs: number;\n\tenv?: Readonly<Record<string, string>>;\n\tsignal?: AbortSignal;\n\tschema: S;\n}\n\nasync function startWorker<S extends z.ZodType>(\n\tsandbox: Sandbox,\n\tstep: string,\n\toptions: WorkerOptions<S>,\n): Promise<WorkerRun<z.infer<S>>> {\n\tconst result = await sandbox.exec(\n\t\t'node',\n\t\tnodeWithTsx(workerFile(options.name), options.args),\n\t\t{\n\t\t\tcwd: options.cwd,\n\t\t\tenv: { ...sandbox.env, ...options.env },\n\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\toutput: 'capture',\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t},\n\t);\n\n\tconst line = result.stdout\n\t\t.split('\\n')\n\t\t.reverse()\n\t\t.find((l) => l.startsWith(WORKER_RESULT_MARKER));\n\tif (line) {\n\t\ttry {\n\t\t\tconst parsed = options.schema.safeParse(\n\t\t\t\tJSON.parse(line.slice(WORKER_RESULT_MARKER.length)),\n\t\t\t);\n\t\t\tif (parsed.success) return { value: parsed.data, stderr: result.stderr };\n\t\t} catch {\n\t\t\t// Not JSON: as good as no answer.\n\t\t}\n\t}\n\n\tthrow new SandboxWorkerFailed(step, result.exitCode, result.stderr);\n}\n","/**\n * Discovery — one glob, one structural test.\n *\n * A glob per kind is the same specialness the construct model removes, and\n * resources have no kind to be listed under: a declared `ObjectStorage` would\n * never be found by `routes:` or `crons:`. So there is one `constructs` glob,\n * every export of every matching module is inspected, and the per-kind\n * `isConstruct` checks collapse into a single question — does it have an id and\n * can it declare?\n *\n * Structural rather than `instanceof` on purpose. A construct from a different\n * copy of `@geekmidas/constructs` — a linked workspace, two versions in a\n * lockfile — is still a construct, and `instanceof` is exactly the check that\n * says otherwise.\n */\n\nimport { relative } from 'node:path';\nimport {\n\tassertDerivations,\n\ttype ConstructManifest,\n\tcanonicalId,\n\ttype Declaration,\n} from '@geekmidas/manifest';\nimport fg from 'fast-glob';\nimport { z } from 'zod';\nimport { clearZodGlobalRegistry } from '../generators/Generator';\nimport { output } from '../output';\nimport { activeSandbox, type Sandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** `console`, or the deploy run discovering the manifest. */\nconst logger = output;\n\n/** The construct face discovery needs: an id, and the ability to declare. */\ninterface Declarable {\n\tid: string;\n\tdeclare(): Declaration[];\n}\n\n/**\n * Whether a module export is a construct.\n *\n * Deliberately loose about what else it carries — a construct that also has a\n * `service` is still a construct, and requiring one would exclude the kinds that\n * own no address.\n */\nexport function isDeclarable(value: unknown): value is Declarable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Declarable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.declare === 'function'\n\t);\n}\n\nexport interface DiscoverOptions {\n\t/** The glob(s) to search. One pattern, not one per kind. */\n\tpatterns: string | readonly string[];\n\tcwd?: string;\n\t/**\n\t * Re-import changed modules, for the dev watcher.\n\t *\n\t * A single glob makes discovery more central, not less: a new construct file\n\t * has to be picked up on `add`, not only on `change`.\n\t */\n\tbustCache?: boolean;\n\t/**\n\t * Filled in with where each construct was found, when provided.\n\t *\n\t * Discovery is the only thing that knows: it globbed the files and imported\n\t * them. Everything downstream that needs to *write* an import — the build,\n\t * generating a server entry that reads a surface's logger — would otherwise\n\t * have to be told the path in config, which is the string this removes.\n\t *\n\t * An out-parameter rather than a second return value so that every existing\n\t * caller, which wants the manifest and nothing else, is unchanged.\n\t */\n\tsources?: Record<string, ConstructSource>;\n\t/**\n\t * Filled in, when provided, with the ids each owner's runnables declared an\n\t * edge to — keyed by the surface an endpoint was built from, or the worker\n\t * a cron or subscriber was.\n\t *\n\t * A runnable is not a declaration: a surface's endpoints are found by the\n\t * glob, not listed by the surface, so its node says `endpoints: []` until a\n\t * build folds the routes in. Anything deciding what an app's process reaches\n\t * — which keys its container is given — needs those edges before any build,\n\t * and discovery is already importing the files they are in.\n\t */\n\trunnables?: Record<string, string[]>;\n\t/**\n\t * Import the construct modules in this sandbox rather than in this\n\t * process. Defaults to the run's own (`withSandbox`), so a deploy's every\n\t * discovery — the engine's included — happens there; with neither, they\n\t * are imported here, as before.\n\t */\n\tsandbox?: Sandbox;\n}\n\n/** What the discovery worker answers. Checked: the worker ran project code. */\nconst DiscoverAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('discovered'),\n\t\tmanifest: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ id: z.string(), kind: z.string() }).loose(),\n\t\t),\n\t\trunnables: z.record(z.string(), z.array(z.string())),\n\t}),\n\tz.object({ reason: z.literal('live'), paths: z.array(z.string()) }),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z\n\t\t\t.object({\n\t\t\t\tname: z.string(),\n\t\t\t\tmessage: z.string(),\n\t\t\t\tid: z.string().optional(),\n\t\t\t\tsources: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.loose(),\n\t}),\n]);\n\n/**\n * The manifest, discovered in `sandbox` and handed back as JSON — or\n * `undefined` when it holds something JSON cannot carry and the sandbox is\n * not isolating, for the caller to discover here as before.\n */\nasync function discoverInSandbox(\n\tsandbox: Sandbox,\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest | undefined> {\n\tconst cwd = options.cwd ?? sandbox.root;\n\tconst patterns =\n\t\ttypeof options.patterns === 'string'\n\t\t\t? [options.patterns]\n\t\t\t: [...options.patterns];\n\n\tconst { value, stderr } = await runWorker(sandbox, 'construct discovery', {\n\t\tname: 'discover-worker',\n\t\targs: [JSON.stringify({ patterns, cwd })],\n\t\tcwd,\n\t\ttimeoutMs: DISCOVER_TIMEOUT_MS,\n\t\tschema: DiscoverAnswer,\n\t});\n\n\t// Discovery's own warnings — a glob that matched nothing — are the\n\t// run's, as they would be had it discovered in-process: as written, one\n\t// message, less the newline the worker's `console.warn` ended it with.\n\tif (stderr.trim()) logger.warn(stderr.replace(/\\n$/, ''));\n\n\tswitch (value.reason) {\n\t\tcase 'discovered':\n\t\t\tif (options.runnables) {\n\t\t\t\tfor (const [owner, edges] of Object.entries(value.runnables)) {\n\t\t\t\t\toptions.runnables[owner] = edges;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.manifest as unknown as ConstructManifest;\n\t\tcase 'failed':\n\t\t\tif (value.error.name === 'DuplicateConstruct' && value.error.id) {\n\t\t\t\tthrow new DuplicateConstruct(value.error.id, value.error.sources ?? []);\n\t\t\t}\n\t\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t\tcase 'live':\n\t\t\tif (sandbox.isolating) throw new ConstructsNotSerializable(value.paths);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * A caller asked for the construct objects (`sources`) or a watcher's\n * re-import under an isolating sandbox, where only data comes back.\n */\nexport class LiveConstructsUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'Discovery was asked for the construct objects themselves under an ' +\n\t\t\t\t'isolating sandbox, which hands back only data. Run this step ' +\n\t\t\t\t'without one, or ask only for the manifest.',\n\t\t);\n\t\tthis.name = 'LiveConstructsUnavailable';\n\t}\n}\n\n/** How long discovering a project's constructs may take in a sandbox. */\nconst DISCOVER_TIMEOUT_MS = 60_000;\n\n/** Importing a construct module, or declaring one, threw in the sandbox. */\nexport class ConstructDiscoveryFailed extends Error {\n\tconstructor(\n\t\treadonly errorName: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(`Discovering constructs failed (${errorName}): ${detail}`);\n\t\tthis.name = 'ConstructDiscoveryFailed';\n\t}\n}\n\n/**\n * The constructs' declarations hold something that is not data, and the\n * sandbox they were discovered in hands the deploy nothing but data.\n */\nexport class ConstructsNotSerializable extends Error {\n\tconstructor(readonly paths: readonly string[]) {\n\t\tsuper(\n\t\t\t`The construct manifest holds values that are not plain data at: ` +\n\t\t\t\t`${paths.join(', ')}. Under an isolating sandbox the deploy only ` +\n\t\t\t\t'receives what JSON can carry; deploy with a sandbox that is not ' +\n\t\t\t\t'isolating if the host trusts this project.',\n\t\t);\n\t\tthis.name = 'ConstructsNotSerializable';\n\t}\n}\n\n/** Where a construct was declared, and under what name. */\nexport interface ConstructSource {\n\t/** Absolute path to the module that exported it. */\n\tfile: string;\n\t/** The name it was exported as — what an import statement has to say. */\n\texportName: string;\n\t/**\n\t * The exported construct itself.\n\t *\n\t * What a declaration cannot say — whether it serves itself — the object can\n\t * be asked, and discovery already imported it.\n\t */\n\tconstruct: unknown;\n}\n\n/**\n * Build the construct manifest for a project.\n *\n * Runs the manifest's own validation before returning, so an app is wrong here\n * — where the error names a file — rather than at deploy.\n *\n * @throws {DuplicateConstruct} when two exports claim one id.\n */\nexport async function discover(\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest> {\n\tconst sandbox = options.sandbox ?? activeSandbox();\n\tif (sandbox) {\n\t\tif (!options.sources && !options.bustCache) {\n\t\t\tconst sandboxed = await discoverInSandbox(sandbox, options);\n\t\t\tif (sandboxed) return sandboxed;\n\t\t} else if (sandbox.isolating) {\n\t\t\t// The construct objects themselves, or a re-import for the watcher:\n\t\t\t// neither can cross a sandbox that hands back only data.\n\t\t\tthrow new LiveConstructsUnavailable();\n\t\t}\n\t}\n\n\tconst {\n\t\tpatterns,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t\tsources: out,\n\t} = options;\n\n\t// Re-importing user modules re-executes them, and Zod v4 throws on a\n\t// re-registered `.meta({ id })`. Same reason the generators clear it.\n\tif (bustCache) clearZodGlobalRegistry();\n\n\tconst manifest: Record<string, Declaration> = {};\n\t/** Which file declared each id, for the error when two of them do. */\n\tconst sources: Record<string, string> = {};\n\t/**\n\t * Constructs already seen, by identity.\n\t *\n\t * A re-export is the *same object* reached through a second file — ESM\n\t * bindings are live, so `export * from './database.js'` hands back the\n\t * binding rather than a copy. Without this, a barrel file made every\n\t * construct in it appear declared twice, and `constructs/index.ts` is the\n\t * first thing anyone writes in a shared folder.\n\t *\n\t * Identity rather than file is also the more honest rule: what may not\n\t * happen twice is two *different* constructs claiming one id, and that is\n\t * still an error below.\n\t */\n\tconst seen = new WeakSet<object>();\n\n\tconst globs = Array.isArray(patterns) ? [...patterns] : [patterns as string];\n\tconst files = fg.stream(globs, { cwd, absolute: true });\n\n\t/** Matched files, for the diagnostic below. */\n\tlet matched = 0;\n\n\tfor await (const found of files) {\n\t\tmatched++;\n\t\tconst file = found.toString();\n\t\tconst module = await import(bustCache ? `${file}?t=${Date.now()}` : file);\n\n\t\tfor (const [exportName, exported] of Object.entries(module)) {\n\t\t\tif (!isDeclarable(exported)) {\n\t\t\t\tif (options.runnables) recordRunnable(options.runnables, exported);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// The same construct, reached again through a re-export. Skipped\n\t\t\t// rather than re-declared: it has already claimed its id, from the\n\t\t\t// file that defined it.\n\t\t\tif (seen.has(exported as object)) continue;\n\t\t\tseen.add(exported as object);\n\n\t\t\t// A construct that is also something a process runs — a queue and its\n\t\t\t// consumer, built from a worker — reaches what it depends on through\n\t\t\t// that process, exactly as an endpoint or a cron does.\n\t\t\tif (\n\t\t\t\toptions.runnables &&\n\t\t\t\ttypeof (exported as { owner?: unknown }).owner === 'string'\n\t\t\t) {\n\t\t\t\trecordRunnable(options.runnables, exported);\n\t\t\t}\n\n\t\t\tfor (const declaration of exported.declare()) {\n\t\t\t\t// Canonicalise here too: a construct built by hand rather than through\n\t\t\t\t// a constructor is still subject to the same identity rule.\n\t\t\t\tconst id = canonicalId(declaration.id);\n\t\t\t\tconst source = relative(cwd, file);\n\n\t\t\t\tconst claimed = sources[id];\n\t\t\t\tif (claimed !== undefined && claimed !== source) {\n\t\t\t\t\tthrow new DuplicateConstruct(id, [claimed, source]);\n\t\t\t\t}\n\n\t\t\t\tmanifest[id] = { ...declaration, id };\n\t\t\t\tsources[id] = source;\n\t\t\t\tif (out) out[id] = { file, exportName, construct: exported };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Reference integrity before anyone reads it — a schema tenant naming a\n\t// database that was deleted is a manifest error, not a reconcile failure.\n\tassertDerivations(manifest);\n\n\twarnIfNothingFound(globs, matched, Object.keys(manifest).length);\n\n\treturn manifest;\n}\n\n/**\n * Record a runnable's edges under the construct that owns it — the surface an\n * endpoint was built from, or the worker a cron or subscriber was. Anything\n * with no owner, or that is not a runnable at all, is left alone.\n */\nfunction recordRunnable(\n\trunnables: Record<string, string[]>,\n\texported: unknown,\n): void {\n\tif (typeof exported !== 'object' || exported === null) return;\n\n\tconst runnable = exported as {\n\t\tsurface?: { id?: unknown };\n\t\towner?: unknown;\n\t\tconstructs?: unknown;\n\t};\n\tconst owner =\n\t\ttypeof runnable.surface?.id === 'string'\n\t\t\t? runnable.surface.id\n\t\t\t: typeof runnable.owner === 'string'\n\t\t\t\t? runnable.owner\n\t\t\t\t: undefined;\n\tif (!owner || !Array.isArray(runnable.constructs)) return;\n\n\tconst key = canonicalId(owner);\n\tconst edges = runnables[key] ?? [];\n\trunnables[key] = edges;\n\tfor (const id of runnable.constructs) {\n\t\tif (typeof id !== 'string') continue;\n\t\tconst target = canonicalId(id);\n\t\tif (!edges.includes(target)) edges.push(target);\n\t}\n}\n\n/**\n * Say so when a glob was configured and found nothing.\n *\n * The glob is not a filter over declarations already known — it is *how they\n * are found*, by importing what it matches. So a file it misses is a\n * declaration that does not exist, and every symptom of that appears somewhere\n * other than the cause: no container starts, no env key is written, and the\n * application fails on first use against a resource it can see in its own\n * source.\n *\n * Nothing reported it before, because an unmatched file is indistinguishable\n * from a file nobody wrote. These two cases are the ones that are *not*\n * ambiguous — a glob was configured, so something was expected.\n *\n * Silent when no glob is configured at all: that is a project which has not\n * adopted constructs, and has nothing to be missing.\n */\nfunction warnIfNothingFound(\n\tglobs: readonly string[],\n\tmatched: number,\n\tdeclared: number,\n): void {\n\tif (globs.length === 0) return;\n\n\tif (matched === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched no files, so nothing was declared.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Nothing will be provisioned — no containers, no env keys, no ` +\n\t\t\t\t`resources.\\n` +\n\t\t\t\t` A common cause is depth: '*.ts' matches one level, '**/*.ts' ` +\n\t\t\t\t`matches any.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (declared === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched ${matched} file(s) but none declared ` +\n\t\t\t\t`anything.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Discovery keeps exports with an 'id' that can 'declare()'. A ` +\n\t\t\t\t`construct that is\\n` +\n\t\t\t\t` built but never exported is invisible to it.`,\n\t\t);\n\t}\n}\n\n/** Two constructs claiming one id. */\nexport class DuplicateConstruct extends Error {\n\t/** The id claimed twice. */\n\treadonly id: string;\n\t/** The files that claimed it. */\n\treadonly sources: readonly string[];\n\n\tconstructor(id: string, sources: readonly string[]) {\n\t\tsuper('Two constructs declare the same id');\n\t\tthis.name = 'DuplicateConstruct';\n\t\tthis.id = id;\n\t\tthis.sources = sources;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,UAAU,IAAI,kBAA8B;;AAGlD,SAAgB,WAAc,MAAkB,IAAgB;CAC/D,OAAO,QAAQ,IAAI,MAAM,EAAE;AAC5B;AAEA,SAAS,MACR,OACA,UAC+B;CAC/B,QAAQ,GAAG,SAAS;EACnB,MAAM,OAAO,QAAQ,SAAS;EAC9B,IAAI,MAAM,KAAK,OAAO,OAAO,GAAG,IAAI,CAAC;OAChC,SAAS,GAAG,IAAI;CACtB;AACD;;;;;AAMA,MAAa,SAAS;CACrB,KAAK,MAAM,SAAS,GAAG,SAAS,QAAQ,IAAI,GAAG,IAAI,CAAC;CACpD,MAAM,MAAM,SAAS,GAAG,SAAS,QAAQ,KAAK,GAAG,IAAI,CAAC;CACtD,MAAM,MAAM,SAAS,GAAG,SAAS,QAAQ,KAAK,GAAG,IAAI,CAAC;CACtD,OAAO,MAAM,UAAU,GAAG,SAAS,QAAQ,MAAM,GAAG,IAAI,CAAC;AAC1D;;;;;;;;;;;;;;ACjCA,SAAgB,yBAA+B;CAC9C,MAAM,WACL,WACC;CACF,IAAI,YAAY,OAAO,SAAS,UAAU,YACzC,SAAS,MAAM;AAEjB;AAaA,IAAsB,qBAAtB,MAAwE;CAGvE,aAAa,MACZ,SACA,WACA,WACA,UACA,SACa;EACb,MAAM,aAAa,MAAM,UAAU,KAAK,QAAQ;EAChD,OAAO,UAAU,MAAM,SAAS,YAAY,WAAW,OAAO;CAC/D;CASA,MAAM,KACL,UACA,MAAM,QAAQ,IAAI,GAClB,YAAY,OACuB;EACnC,MAAM,SAAS;EAEf,MAAM,eAAe,MAAM,QAAQ,QAAQ,IACxC,WACA,WACC,CAAC,QAAQ,IACT,CAAC;EAGL,MAAM,QAAQ,GAAG,OAAO,cAAc;GACrC;GACA,UAAU;EACX,CAAC;EAKD,IAAI,WACH,uBAAuB;EAIxB,MAAM,aAAsC,CAAC;EAE7C,WAAW,MAAM,KAAK,OACrB,IAAI;GACH,MAAM,OAAO,EAAE,SAAS;GAGxB,MAAM,SAAS,OADI,YAAA,OAAY,GAAG,KAAK,KAAK,KAAK,IAAI,OAAA,OAAM;GAI3D,KAAK,MAAM,CAAC,KAAK,cAAc,OAAO,QAAQ,MAAM,GACnD,IAAI,KAAK,YAAY,SAAS,GAC7B,WAAW,KAAK;IACf;IACA,MAAMA,YAAU,GAAG;IACnB;IACA,MAAM;KACL,UAAU;KACV,UAAU,SAAS,QAAQ,IAAI,GAAG,IAAI;IACvC;GACD,CAAC;EAGJ,SAAS,OAAO;GACf,MAAM,MAAM;GACZ,OAAO,MAAM,kBAAkB,EAAE,IAAI,IAAI,SAAS;GAClD,IAAI,IAAI,OACP,OAAO,MAAM,IAAI,KAAK;GAEvB,MAAM;EACP;EAGD,OAAO;CACR;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA,MAAa,kBAAkB;;AAG/B,IAAa,mBAAb,cAAsC,MAAM;CAEjC;CACA;CAFV,YACC,KACA,MACC;EACD,MACC,uBAAuB,IAAI,mCAAmC,KAAK,qIAGpE;EAPS,KAAA,MAAA;EACA,KAAA,OAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,SAAS,KAAK,MAAsB;CACnC,OAAO,WAAW,IAAI,IAAI,aAAa,IAAI,IAAI;AAChD;;;;;;;;;AAUA,SAAgB,WAAW,MAAc,KAAqB;CAC7D,MAAM,WAAW,QAAQ,MAAM,GAAG;CAClC,MAAM,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC;CACzD,IAAI,SAAS,QAAQ,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,IAAI,GAClE,MAAM,IAAI,iBAAiB,KAAK,IAAI;CAErC,OAAO;AACR;;AAGA,IAAa,oBAAb,cAAuC,MAAM;CACvB;CAArB,YAAY,YAA6B;EACxC,MACC,IAAI,WAAW,oKAGhB;EALoB,KAAA,aAAA;EAMpB,KAAK,OAAO;CACb;AACD;AAEA,MAAM,cAAc;;AAGpB,SAAgB,kBACf,SACO;CACP,KAAK,MAAM,QAAQ,OAAO,KAAK,WAAW,CAAC,CAAC,GAC3C,IAAI,CAAC,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,kBAAkB,IAAI;AAE/D;AAQA,MAAM,SAAS,IAAI,kBAA8B;;;;;;;;;;AAWjD,SAAgB,YAAe,SAAkB,IAAgB;CAChE,OAAO,OAAO,IAAI;EAAE;EAAS,yBAAS,IAAI,IAAI;CAAE,GAAG,EAAE;AACtD;;AAGA,SAAgB,gBAAqC;CACpD,OAAO,OAAO,SAAS,CAAC,EAAE;AAC3B;;;;;;;;;;;AAYA,SAAgB,WACf,SACA,KACA,KACa;CACb,MAAM,MAAM,OAAO,SAAS;CAC5B,IAAI,CAAC,OAAO,IAAI,YAAY,SAAS,OAAO,IAAI;CAEhD,IAAI,SAAS,IAAI,QAAQ,IAAI,GAAG;CAChC,IAAI,CAAC,QAAQ;EACZ,SAAS,IAAI;EACb,IAAI,QAAQ,IAAI,KAAK,MAAM;EAE3B,OAAO,YAAY,IAAI,QAAQ,OAAO,GAAG,CAAC;CAC3C;CACA,OAAO;AACR;;;AChOA,MAAM,WAAW;;AAGjB,IAAa,+BAAb,cAAkD,MAAM;CAClC;CAArB,YAAY,MAAuB;EAClC,MACC,sBAAsB,SAAS,2BAA2B,KAAK,4FAGhE;EALoB,KAAA,OAAA;EAMpB,KAAK,OAAO;CACb;AACD;;;;;;AAOA,SAAS,cAAsB;CAC9B,MAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;CACnD,KAAK,IAAI,MAAM,OAAQ,MAAM,QAAQ,GAAG,GAAG;EAC1C,MAAM,YAAY,KAAK,KAAK,OAAO,QAAQ;EAC3C,IAAI,WAAW,SAAS,GAAG,OAAO,cAAc,SAAS,CAAC,CAAC;EAC3D,IAAI,QAAQ,GAAG,MAAM,KAAK,MAAM,IAAI,6BAA6B,IAAI;CACtE;AACD;;;;;;;;;;;AAYA,SAAgB,sBAAsB,cAAc,IAAY;CAC/D,IAAI,YAAY,SAAS,QAAQ,GAAG,OAAO;CAC3C,OAAO,CAAC,YAAY,YAAY,KAAK,WAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAC3E;;;;;;;;;;;;;ACzBA,MAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;;;;;AAMnD,SAAgB,WAAW,MAAsB;CAOhD,OACC;EANA,KAAK,MAAM,WAAW,GAAG,KAAK,KAAK;EACnC,KAAK,MAAM,GAAG,KAAK,KAAK;EACxB,KAAK,MAAM,MAAM,WAAW,GAAG,KAAK,KAAK;EACzC,KAAK,MAAM,GAAG,KAAK,IAAI;CAGd,CAAC,CAAC,MAAM,SAAS,WAAW,IAAI,CAAC,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI;AAExE;;AAGA,SAAgB,SAAiB;CAChC,OAAO,cAAc,cAAc,YAAY,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;AACrE;;;;;;AAOA,SAAgB,YACf,QACA,MACA,UAA6B,CAAC,GACnB;CACX,OAAO;EACN,GAAG,sBAAsB,YAAY,OAAO,GAAG,CAAC,CAAC,MAAM,GAAG;EAC1D,GAAG,QAAQ,KAAK,SAAS,YAAY,cAAc,IAAI,CAAC,CAAC,MAAM;EAC/D;EACA,GAAG;CACJ;AACD;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CAEpC;CACA;CACA;CAHV,YACC,MACA,UACA,QACC;EACD,MACC,iBAAiB,KAAK,oBAAoB,SAAS,sBACxC,OAAO,KAAK,IAAI,KAAK,OAAO,KAAK,MAAM,GAAG,4HAGtD;EATS,KAAA,OAAA;EACA,KAAA,WAAA;EACA,KAAA,SAAA;EAQT,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;AAqBA,eAAsB,UACrB,SACA,MACA,SACiC;CAOjC,MAAM,SAAS,MAAM,WAAW,SANpB,KAAK,UAAU;EAC1B,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ,OAAO,CAAC;CACjB,CACyC,SACxC,YAAY,SAAS,MAAM,OAAO,CACnC;CACA,OAAO,gBAAgB,MAAM;AAC9B;AAYA,eAAe,YACd,SACA,MACA,SACiC;CACjC,MAAM,SAAS,MAAM,QAAQ,KAC5B,QACA,YAAY,WAAW,QAAQ,IAAI,GAAG,QAAQ,IAAI,GAClD;EACC,KAAK,QAAQ;EACb,KAAK;GAAE,GAAG,QAAQ;GAAK,GAAG,QAAQ;EAAI;EACtC,WAAW,QAAQ;EACnB,QAAQ;EACR,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;CACpD,CACD;CAEA,MAAM,OAAO,OAAO,OAClB,MAAM,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,MAAM,MAAM,EAAE,WAAW,oBAAoB,CAAC;CAChD,IAAI,MACH,IAAI;EACH,MAAM,SAAS,QAAQ,OAAO,UAC7B,KAAK,MAAM,KAAK,MAAM,qBAAqB,MAAM,CAAC,CACnD;EACA,IAAI,OAAO,SAAS,OAAO;GAAE,OAAO,OAAO;GAAM,QAAQ,OAAO;EAAO;CACxE,QAAQ,CAER;CAGD,MAAM,IAAI,oBAAoB,MAAM,OAAO,UAAU,OAAO,MAAM;AACnE;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9HA,MAAM,SAAS;;;;;;;;AAef,SAAgB,aAAa,OAAqC;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,YAAY;CAElB,OACC,OAAO,UAAU,OAAO,YACxB,UAAU,GAAG,SAAS,KACtB,OAAO,UAAU,YAAY;AAE/B;;AA+CA,MAAM,iBAAiBC,mBAAqB,UAAU;CACrDC,OAAS;EACR,QAAQC,QAAU,YAAY;EAC9B,UAAUC,OACTC,OAAS,GACTH,OAAS;GAAE,IAAIG,OAAS;GAAG,MAAMA,OAAS;EAAE,CAAC,CAAC,CAAC,MAAM,CACtD;EACA,WAAWD,OAASC,OAAS,GAAGC,MAAQD,OAAS,CAAC,CAAC;CACpD,CAAC;CACDH,OAAS;EAAE,QAAQC,QAAU,MAAM;EAAG,OAAOG,MAAQD,OAAS,CAAC;CAAE,CAAC;CAClEH,OAAS;EACR,QAAQC,QAAU,QAAQ;EAC1B,OAAOI,OACE;GACP,MAAMF,OAAS;GACf,SAASA,OAAS;GAClB,IAAIA,OAAS,CAAC,CAAC,SAAS;GACxB,SAASC,MAAQD,OAAS,CAAC,CAAC,CAAC,SAAS;EACvC,CAAC,CAAC,CACD,MAAM;CACT,CAAC;AACF,CAAC;;;;;;AAOD,eAAe,kBACd,SACA,SACyC;CACzC,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,WACL,OAAO,QAAQ,aAAa,WACzB,CAAC,QAAQ,QAAQ,IACjB,CAAC,GAAG,QAAQ,QAAQ;CAExB,MAAM,EAAE,OAAO,WAAW,MAAM,UAAU,SAAS,uBAAuB;EACzE,MAAM;EACN,MAAM,CAAC,KAAK,UAAU;GAAE;GAAU;EAAI,CAAC,CAAC;EACxC;EACA,WAAW;EACX,QAAQ;CACT,CAAC;CAKD,IAAI,OAAO,KAAK,GAAG,OAAO,KAAK,OAAO,QAAQ,OAAO,EAAE,CAAC;CAExD,QAAQ,MAAM,QAAd;EACC,KAAK;GACJ,IAAI,QAAQ,WACX,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,MAAM,SAAS,GAC1D,QAAQ,UAAU,SAAS;GAG7B,OAAO,MAAM;EACd,KAAK;GACJ,IAAI,MAAM,MAAM,SAAS,wBAAwB,MAAM,MAAM,IAC5D,MAAM,IAAI,mBAAmB,MAAM,MAAM,IAAI,MAAM,MAAM,WAAW,CAAC,CAAC;GAEvE,MAAM,IAAI,yBAAyB,MAAM,MAAM,MAAM,MAAM,MAAM,OAAO;EACzE,KAAK;GACJ,IAAI,QAAQ,WAAW,MAAM,IAAI,0BAA0B,MAAM,KAAK;GACtE;CACF;AACD;;;;;AAMA,IAAa,4BAAb,cAA+C,MAAM;CACpD,cAAc;EACb,MACC,2KAGD;EACA,KAAK,OAAO;CACb;AACD;;AAGA,MAAM,sBAAsB;;AAG5B,IAAa,2BAAb,cAA8C,MAAM;CAEzC;CACA;CAFV,YACC,WACA,QACC;EACD,MAAM,kCAAkC,UAAU,KAAK,QAAQ;EAHtD,KAAA,YAAA;EACA,KAAA,SAAA;EAGT,KAAK,OAAO;CACb;AACD;;;;;AAMA,IAAa,4BAAb,cAA+C,MAAM;CAC/B;CAArB,YAAY,OAAmC;EAC9C,MACC,mEACI,MAAM,KAAK,IAAI,EAAE,wJAGtB;EANoB,KAAA,QAAA;EAOpB,KAAK,OAAO;CACb;AACD;;;;;;;;;AAyBA,eAAsB,SACrB,SAC6B;CAC7B,MAAM,UAAU,QAAQ,WAAW,cAAc;CACjD,IAAI,SAAS;EACZ,IAAI,CAAC,QAAQ,WAAW,CAAC,QAAQ,WAAW;GAC3C,MAAM,YAAY,MAAM,kBAAkB,SAAS,OAAO;GAC1D,IAAI,WAAW,OAAO;EACvB,OAAO,IAAI,QAAQ,WAGlB,MAAM,IAAI,0BAA0B;CAEtC;CAEA,MAAM,EACL,UACA,MAAM,QAAQ,IAAI,GAClB,YAAY,OACZ,SAAS,QACN;CAIJ,IAAI,WAAW,uBAAuB;CAEtC,MAAM,WAAwC,CAAC;;CAE/C,MAAM,UAAkC,CAAC;;;;;;;;;;;;;;CAczC,MAAM,uBAAO,IAAI,QAAgB;CAEjC,MAAM,QAAQ,MAAM,QAAQ,QAAQ,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,QAAkB;CAC3E,MAAM,QAAQ,GAAG,OAAO,OAAO;EAAE;EAAK,UAAU;CAAK,CAAC;;CAGtD,IAAI,UAAU;CAEd,WAAW,MAAM,SAAS,OAAO;EAChC;EACA,MAAM,OAAO,MAAM,SAAS;EAC5B,MAAM,SAAS,OAAa,YAAA,OAAY,GAAG,KAAK,KAAK,KAAK,IAAI,OAAA,OAAM;EAEpE,KAAK,MAAM,CAAC,YAAY,aAAa,OAAO,QAAQ,MAAM,GAAG;GAC5D,IAAI,CAAC,aAAa,QAAQ,GAAG;IAC5B,IAAI,QAAQ,WAAW,eAAe,QAAQ,WAAW,QAAQ;IACjE;GACD;GAKA,IAAI,KAAK,IAAI,QAAkB,GAAG;GAClC,KAAK,IAAI,QAAkB;GAK3B,IACC,QAAQ,aACR,OAAQ,SAAiC,UAAU,UAEnD,eAAe,QAAQ,WAAW,QAAQ;GAG3C,KAAK,MAAM,eAAe,SAAS,QAAQ,GAAG;IAG7C,MAAM,KAAK,YAAY,YAAY,EAAE;IACrC,MAAM,SAAS,SAAS,KAAK,IAAI;IAEjC,MAAM,UAAU,QAAQ;IACxB,IAAI,YAAY,KAAA,KAAa,YAAY,QACxC,MAAM,IAAI,mBAAmB,IAAI,CAAC,SAAS,MAAM,CAAC;IAGnD,SAAS,MAAM;KAAE,GAAG;KAAa;IAAG;IACpC,QAAQ,MAAM;IACd,IAAI,KAAK,IAAI,MAAM;KAAE;KAAM;KAAY,WAAW;IAAS;GAC5D;EACD;CACD;CAIA,kBAAkB,QAAQ;CAE1B,mBAAmB,OAAO,SAAS,OAAO,KAAK,QAAQ,CAAC,CAAC,MAAM;CAE/D,OAAO;AACR;;;;;;AAOA,SAAS,eACR,WACA,UACO;CACP,IAAI,OAAO,aAAa,YAAY,aAAa,MAAM;CAEvD,MAAM,WAAW;CAKjB,MAAM,QACL,OAAO,SAAS,SAAS,OAAO,WAC7B,SAAS,QAAQ,KACjB,OAAO,SAAS,UAAU,WACzB,SAAS,QACT,KAAA;CACL,IAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,SAAS,UAAU,GAAG;CAEnD,MAAM,MAAM,YAAY,KAAK;CAC7B,MAAM,QAAQ,UAAU,QAAQ,CAAC;CACjC,UAAU,OAAO;CACjB,KAAK,MAAM,MAAM,SAAS,YAAY;EACrC,IAAI,OAAO,OAAO,UAAU;EAC5B,MAAM,SAAS,YAAY,EAAE;EAC7B,IAAI,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM;CAC/C;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAS,mBACR,OACA,SACA,UACO;CACP,IAAI,MAAM,WAAW,GAAG;CAExB,IAAI,YAAY,GAAG;EAClB,OAAO,KACN,sFACiB,MAAM,KAAK,IAAI,EAAE,2JAKnC;EACA;CACD;CAEA,IAAI,aAAa,GAChB,OAAO,KACN,qCAAqC,QAAQ,qDAE5B,MAAM,KAAK,IAAI,EAAE,qIAInC;AAEF;;AAGA,IAAa,qBAAb,cAAwC,MAAM;;CAE7C;;CAEA;CAEA,YAAY,IAAY,SAA4B;EACnD,MAAM,oCAAoC;EAC1C,KAAK,OAAO;EACZ,KAAK,KAAK;EACV,KAAK,UAAU;CAChB;AACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"discover-C_6COHEv.cjs","names":["AsyncLocalStorage","format","fg","kebabCase","relative","existsSync","realpathSync","resolve","relative","sep","isAbsolute","AsyncLocalStorage","dirname","fileURLToPath","join","existsSync","pathToFileURL","dirname","fileURLToPath","join","existsSync","pathToFileURL","createRequire","WORKER_RESULT_MARKER","fg","canonicalId","relative"],"sources":["../src/output.ts","../src/generators/Generator.ts","../src/sandbox/sandbox.ts","../src/owningTsconfigJsx.ts","../src/sandbox/worker.ts","../src/reconcile/discover.ts"],"sourcesContent":["/**\n * Where the CLI's progress lines go.\n *\n * Commands write their progress through `output` rather than `console`. Run\n * from the terminal that is the same thing. Run inside `deploy()`, each line\n * goes to the run that wrote it instead — as an event its caller can iterate,\n * and to the logger it was handed — so a deploy embedded in another program\n * does not print over that program's own output.\n *\n * Carried by `AsyncLocalStorage` rather than passed down, because the lines\n * come from everywhere a deploy reaches — the Dockerfile generator, the env\n * sniffer, construct discovery — and two deploys running in one process must\n * not hear each other.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { format } from 'node:util';\n\n/** How loud a line is. */\nexport type OutputLevel = 'info' | 'warn' | 'error';\n\n/** Receives each line written while it is the current sink. */\nexport type OutputSink = (level: OutputLevel, message: string) => void;\n\nconst current = new AsyncLocalStorage<OutputSink>();\n\n/** Runs `fn` with every line written through `output` sent to `sink`. */\nexport function withOutput<T>(sink: OutputSink, fn: () => T): T {\n\treturn current.run(sink, fn);\n}\n\nfunction write(\n\tlevel: OutputLevel,\n\tfallback: (...args: unknown[]) => void,\n): (...args: unknown[]) => void {\n\treturn (...args) => {\n\t\tconst sink = current.getStore();\n\t\tif (sink) sink(level, format(...args));\n\t\telse fallback(...args);\n\t};\n}\n\n/**\n * `console`, for the methods the CLI logs through — routed to the current\n * run's sink when there is one.\n */\nexport const output = {\n\tlog: write('info', (...args) => console.log(...args)),\n\tinfo: write('info', (...args) => console.info(...args)),\n\twarn: write('warn', (...args) => console.warn(...args)),\n\terror: write('error', (...args) => console.error(...args)),\n};\n","import { relative } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\nimport fg from 'fast-glob';\nimport kebabCase from 'lodash.kebabcase';\nimport type { BuildContext } from '../build/types';\nimport type { MainProvider, Routes } from '../types';\n\n/**\n * Zod v4 maintains a process-wide registry of schemas registered via\n * `.meta({ id })`. When we cache-bust user module imports (by appending a\n * `?t=timestamp` query), those modules re-execute and try to register the\n * same ids again, which throws `ID X already exists in the registry`.\n *\n * Clearing the registry in the CLI process is safe: the user's running\n * server lives in a subprocess and has its own isolated registry.\n *\n * Exported for tests.\n */\nexport function clearZodGlobalRegistry(): void {\n\tconst registry = (\n\t\tglobalThis as { __zod_globalRegistry?: { clear?: () => void } }\n\t).__zod_globalRegistry;\n\tif (registry && typeof registry.clear === 'function') {\n\t\tregistry.clear();\n\t}\n}\n\nexport interface GeneratorOptions {\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget?: MainProvider;\n\t/**\n\t * What a handler path in the manifest is relative to — the workspace root,\n\t * which is where `sst.config.ts` runs and resolves it from.\n\t */\n\troot?: string;\n\t[key: string]: any;\n}\n\nexport abstract class ConstructGenerator<T extends Construct, R = void> {\n\tabstract isConstruct(value: any): value is T;\n\n\tstatic async build<T extends Construct, R = void>(\n\t\tcontext: BuildContext,\n\t\toutputDir: string,\n\t\tgenerator: ConstructGenerator<T, R>,\n\t\tpatterns?: Routes,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R> {\n\t\tconst constructs = await generator.load(patterns);\n\t\treturn generator.build(context, constructs, outputDir, options);\n\t}\n\n\tabstract build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<T>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R>;\n\n\tasync load(\n\t\tpatterns?: Routes,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t): Promise<GeneratedConstruct<T>[]> {\n\t\tconst logger = console;\n\n\t\tconst globPatterns = Array.isArray(patterns)\n\t\t\t? patterns\n\t\t\t: patterns\n\t\t\t\t? [patterns]\n\t\t\t\t: [];\n\n\t\t// Find all files\n\t\tconst files = fg.stream(globPatterns, {\n\t\t\tcwd,\n\t\t\tabsolute: true,\n\t\t});\n\n\t\t// Cache-busted re-imports re-execute user modules, which would try to\n\t\t// re-register Zod schemas with the same `.meta({ id })`. Clear the\n\t\t// global registry once per load to prevent duplicate-id errors.\n\t\tif (bustCache) {\n\t\t\tclearZodGlobalRegistry();\n\t\t}\n\n\t\t// Load constructs\n\t\tconst constructs: GeneratedConstruct<T>[] = [];\n\n\t\tfor await (const f of files) {\n\t\t\ttry {\n\t\t\t\tconst file = f.toString();\n\t\t\t\t// Append cache-busting query param to force re-import of changed modules\n\t\t\t\tconst importPath = bustCache ? `${file}?t=${Date.now()}` : file;\n\t\t\t\tconst module = await import(importPath);\n\n\t\t\t\t// Check all exports for constructs\n\t\t\t\tfor (const [key, construct] of Object.entries(module)) {\n\t\t\t\t\tif (this.isConstruct(construct)) {\n\t\t\t\t\t\tconstructs.push({\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tname: kebabCase(key),\n\t\t\t\t\t\t\tconstruct,\n\t\t\t\t\t\t\tpath: {\n\t\t\t\t\t\t\t\tabsolute: file,\n\t\t\t\t\t\t\t\trelative: relative(process.cwd(), file),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`Failed to load ${f}: ${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\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn constructs;\n\t}\n}\n\nexport interface GeneratedConstruct<T extends Construct> {\n\tkey: string;\n\tname: string;\n\tconstruct: T;\n\tpath: {\n\t\tabsolute: string;\n\t\trelative: string;\n\t};\n}\n","/**\n * Where a deploy runs the project's own code.\n *\n * A deploy holds credentials — Dokploy's token, a registry login, an AWS key —\n * and loading `gkm.config.ts`, sniffing an app's environment and building it\n * all execute code from the repository being deployed. On a developer's own\n * laptop that is the developer's code. On a CI job for a fork, or a shared\n * build runner, it is not, and that code should not be able to read the\n * credentials used to deploy it, hang the deploy, or reach outside the\n * checkout.\n *\n * So every step that runs project code goes through a `Sandbox`: one call,\n * with an argument array rather than a shell line, the complete environment\n * the step needs rather than the host's, a timeout it cannot outlive, secrets\n * as files rather than variables, and a working directory inside the project.\n * The steps that need credentials — provisioning, pushing, releasing — are\n * the deploy's own code and never run in one.\n *\n * `LocalSandbox` is the default: a child process on this machine with an\n * allowlisted environment. A host that builds repositories it does not trust\n * passes its own — a container per build, a VM — through `deploy()`'s\n * `sandbox`.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { existsSync, realpathSync } from 'node:fs';\nimport { isAbsolute, relative, resolve, sep } from 'node:path';\n\n/** Where a command's output goes. */\nexport type SandboxOutput = 'capture' | 'inherit' | 'stderr' | 'ignore';\n\nexport interface SandboxExecOptions {\n\t/**\n\t * Where the command runs: the project root or a directory below it, as an\n\t * absolute path or relative to the root. Anywhere else is refused with\n\t * {@link SandboxCwdEscape}.\n\t */\n\tcwd: string;\n\t/**\n\t * The command's whole environment. Nothing of the host's is added to it:\n\t * start from {@link Sandbox.env} and add what the step needs.\n\t */\n\tenv: Readonly<Record<string, string>>;\n\t/**\n\t * How long the command may run before it is killed. Required: a step that\n\t * waits forever — a sniffed entry that opens a server, a build stuck on a\n\t * prompt — would otherwise hold the deploy, and its lock, forever.\n\t */\n\ttimeoutMs: number;\n\t/**\n\t * Files the command can read, by name. Mounted in a directory of their own\n\t * — named by `GKM_SECRETS_DIR` in the command's environment — and removed\n\t * when it exits. Never set as variables, which every child inherits, a\n\t * crash report prints and `/proc/<pid>/environ` shows.\n\t */\n\tsecrets?: Readonly<Record<string, string>>;\n\t/**\n\t * `capture` (the default) returns stdout and stderr in the result;\n\t * `inherit` gives the command the host's terminal; `stderr` sends both\n\t * streams to the host's stderr; `ignore` discards them.\n\t */\n\toutput?: SandboxOutput;\n\t/** Kills the command when aborted; `exec` rejects with the signal's reason. */\n\tsignal?: AbortSignal;\n}\n\n/** How a command ended. A non-zero exit is a result, not an error. */\nexport interface SandboxResult {\n\texitCode: number | null;\n\tsignal: string | null;\n\t/** What it wrote to stdout, when its output was captured. */\n\tstdout: string;\n\t/** What it wrote to stderr, when its output was captured. */\n\tstderr: string;\n}\n\n/**\n * Runs a command against the project, and nothing else of the host's.\n *\n * `exec` resolves with the result however the command exited. It rejects\n * with {@link CommandTimedOut} once the timeout passes — after the command is\n * gone — with {@link SandboxCwdEscape} for a directory outside the project,\n * with the signal's reason when aborted, and with the spawn error when the\n * program cannot be started.\n */\nexport interface Sandbox {\n\t/** The project: the directory every command runs at or below. */\n\treadonly root: string;\n\t/**\n\t * Whether the code it runs is kept from the host: its files, its\n\t * processes, its memory.\n\t *\n\t * An isolating sandbox shares nothing but what crosses `exec`, so a config\n\t * reaches the deploy as data — a live object in it (a custom state store,\n\t * an inline target) cannot cross, and is refused with\n\t * `ConfigObjectNotSerializable`. A non-isolating one, like\n\t * {@link LocalSandbox}, runs on the host as the host's user; a project\n\t * whose config holds live objects is then loaded in-process as before,\n\t * because a project trusted to run there is trusted to do that.\n\t */\n\treadonly isolating: boolean;\n\t/**\n\t * The environment a command starts from: what any program needs to run\n\t * here — `PATH`, `HOME`, the locale — and no credential.\n\t */\n\treadonly env: Readonly<Record<string, string>>;\n\texec(\n\t\tcommand: string,\n\t\targs: readonly string[],\n\t\toptions: SandboxExecOptions,\n\t): Promise<SandboxResult>;\n}\n\n/** The variable naming the directory a command's secrets are mounted in. */\nexport const SECRETS_DIR_ENV = 'GKM_SECRETS_DIR';\n\n/** A command was asked to run outside the project. */\nexport class SandboxCwdEscape extends Error {\n\tconstructor(\n\t\treadonly cwd: string,\n\t\treadonly root: string,\n\t) {\n\t\tsuper(\n\t\t\t`Refusing to run in '${cwd}': it is outside the project at '${root}'. ` +\n\t\t\t\t'A sandboxed step only runs inside the project it was given — check ' +\n\t\t\t\t'the app paths in gkm.config.ts for `..` or an absolute path.',\n\t\t);\n\t\tthis.name = 'SandboxCwdEscape';\n\t}\n}\n\n/** A path with its symlinks resolved where it exists — `/tmp` is `/private/tmp`. */\nfunction real(path: string): string {\n\treturn existsSync(path) ? realpathSync(path) : path;\n}\n\n/**\n * `cwd` as an absolute directory inside `root`, or {@link SandboxCwdEscape}.\n *\n * Symlinks are resolved on both sides first, so a link inside the project\n * that points out of it is an escape, and a project reached through a link\n * (`/tmp` on macOS) is still itself. For a sandbox of a host's own to call\n * before it runs anything.\n */\nexport function confineCwd(root: string, cwd: string): string {\n\tconst absolute = resolve(root, cwd);\n\tconst from = relative(real(resolve(root)), real(absolute));\n\tif (from === '..' || from.startsWith(`..${sep}`) || isAbsolute(from)) {\n\t\tthrow new SandboxCwdEscape(cwd, root);\n\t}\n\treturn absolute;\n}\n\n/** A secret's file name: one path segment, so it cannot be written elsewhere. */\nexport class SecretNameInvalid extends Error {\n\tconstructor(readonly secretName: string) {\n\t\tsuper(\n\t\t\t`'${secretName}' cannot be a secret's name: it becomes a file name in ` +\n\t\t\t\t'the secrets directory, so it must be one segment of letters, digits, ' +\n\t\t\t\t\"'.', '-' or '_' and not start with '.'.\",\n\t\t);\n\t\tthis.name = 'SecretNameInvalid';\n\t}\n}\n\nconst SECRET_NAME = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;\n\n/** Every secret name, checked before anything is written. */\nexport function assertSecretNames(\n\tsecrets: Readonly<Record<string, string>> | undefined,\n): void {\n\tfor (const name of Object.keys(secrets ?? {})) {\n\t\tif (!SECRET_NAME.test(name)) throw new SecretNameInvalid(name);\n\t}\n}\n\n/** A run's sandbox, and what its workers already answered. */\ninterface SandboxRun {\n\tsandbox: Sandbox;\n\tanswers: Map<string, Promise<unknown>>;\n}\n\nconst active = new AsyncLocalStorage<SandboxRun>();\n\n/**\n * Run `fn` with `sandbox` as the one its steps use.\n *\n * Per run rather than global, as `withOutput` routes a run's lines: two\n * deploys in one host process each build in their own sandbox. A step deep in\n * the engine — discovering constructs, sniffing an app — asks\n * {@link activeSandbox} rather than every function between `deploy()` and it\n * taking one more parameter.\n */\nexport function withSandbox<T>(sandbox: Sandbox, fn: () => T): T {\n\treturn active.run({ sandbox, answers: new Map() }, fn);\n}\n\n/** The sandbox of the run this is part of, if it was started with one. */\nexport function activeSandbox(): Sandbox | undefined {\n\treturn active.getStore()?.sandbox;\n}\n\n/**\n * `ask()`'s answer, asked once per run.\n *\n * A deploy loads its config and discovers its constructs from several places\n * — the first load, the engine, the Dockerfile generator — and in a sandbox\n * each was a child process of its own, for the same answer: the checkout does\n * not change while it deploys. Within a run in `sandbox`, the first answer\n * for `key` is the one every later ask gets. Outside one, or for another\n * sandbox, `ask()` runs each time.\n */\nexport function oncePerRun<T>(\n\tsandbox: Sandbox,\n\tkey: string,\n\task: () => Promise<T>,\n): Promise<T> {\n\tconst run = active.getStore();\n\tif (!run || run.sandbox !== sandbox) return ask();\n\n\tlet answer = run.answers.get(key) as Promise<T> | undefined;\n\tif (!answer) {\n\t\tanswer = ask();\n\t\trun.answers.set(key, answer);\n\t\t// A failure is not remembered: the next ask tries again.\n\t\tanswer.catch(() => run.answers.delete(key));\n\t}\n\treturn answer;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nconst REGISTER = 'owning-tsconfig-jsx-register.mjs';\n\n/** The CLI's `bin/` was not found above the module looking for it. */\nexport class OwningTsconfigJsxHookMissing extends Error {\n\tconstructor(readonly from: string) {\n\t\tsuper(\n\t\t\t`Could not find bin/${REGISTER} in any directory above '${from}'. ` +\n\t\t\t\t'It ships with @geekmidas/cli beside bin/gkm.mjs; reinstall the ' +\n\t\t\t\t'package if it is missing.',\n\t\t);\n\t\tthis.name = 'OwningTsconfigJsxHookMissing';\n\t}\n}\n\n/**\n * The CLI's `bin/owning-tsconfig-jsx-register.mjs`, as a file URL. Searched\n * upward because this module runs from `src/` in the repo and from a chunk in\n * `dist/` once built, and `bin/` sits beside both.\n */\nfunction registerUrl(): string {\n\tconst from = dirname(fileURLToPath(import.meta.url));\n\tfor (let dir = from; ; dir = dirname(dir)) {\n\t\tconst candidate = join(dir, 'bin', REGISTER);\n\t\tif (existsSync(candidate)) return pathToFileURL(candidate).href;\n\t\tif (dirname(dir) === dir) throw new OwningTsconfigJsxHookMissing(from);\n\t}\n}\n\n/**\n * `NODE_OPTIONS` for a process that runs app code through tsx, with the hook\n * that compiles each `.tsx` with its own tsconfig's JSX settings (see\n * `bin/owning-tsconfig-jsx.mjs`) put in front of every other `--import`, so it\n * is registered before tsx and reads the source on tsx's behalf.\n *\n * `bin/gkm.mjs` already starts the CLI this way, and its children inherit it;\n * this is for those that set `NODE_OPTIONS` themselves, or whose CLI was\n * started with tsx already imported.\n */\nexport function withOwningTsconfigJsx(nodeOptions = ''): string {\n\tif (nodeOptions.includes(REGISTER)) return nodeOptions;\n\treturn [`--import=${registerUrl()}`, nodeOptions].filter(Boolean).join(' ');\n}\n","/**\n * Running one of the CLI's own worker scripts inside a sandbox, and reading\n * back the one JSON value it answers with.\n *\n * The worker imports the project's TypeScript — `gkm.config.ts`, construct\n * modules, an app's entry — so it starts with the CLI's own tsx and the two\n * hooks `gkm` itself runs with (JSX by the owning tsconfig, path aliases by\n * the adjacent one). The host process needs none of them loaded: a program\n * calling `deploy()` without `--import tsx` still loads a TypeScript config.\n */\n\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport type { z } from 'zod';\nimport { withOwningTsconfigJsx } from '../owningTsconfigJsx';\nimport { oncePerRun, type Sandbox } from './sandbox';\nimport { WORKER_RESULT_MARKER } from './workerRuntime';\n\nconst here = dirname(fileURLToPath(import.meta.url));\n\n/**\n * A worker's file: `dist/sandbox/<name>.mjs` once built — whether this module\n * was bundled into `dist/` or sits beside it — or the `.ts` source under tsx.\n */\nexport function workerFile(name: string): string {\n\tconst candidates = [\n\t\tjoin(here, 'sandbox', `${name}.mjs`),\n\t\tjoin(here, `${name}.mjs`),\n\t\tjoin(here, '..', 'sandbox', `${name}.mjs`),\n\t\tjoin(here, `${name}.ts`),\n\t];\n\treturn (\n\t\tcandidates.find((path) => existsSync(path)) ?? join(here, `${name}.ts`)\n\t);\n}\n\n/** tsx, from the CLI's own dependencies — never the project's. */\nexport function tsxUrl(): string {\n\treturn pathToFileURL(createRequire(import.meta.url).resolve('tsx')).href;\n}\n\n/**\n * `node`'s arguments for `script`: the CLI's TypeScript loaders, then any\n * further `imports`, then the script and its `args` — an argument array, so\n * nothing about a path is read by a shell.\n */\nexport function nodeWithTsx(\n\tscript: string,\n\targs: readonly string[],\n\timports: readonly string[] = [],\n): string[] {\n\treturn [\n\t\t...withOwningTsconfigJsx(`--import=${tsxUrl()}`).split(' '),\n\t\t...imports.map((path) => `--import=${pathToFileURL(path).href}`),\n\t\tscript,\n\t\t...args,\n\t];\n}\n\n/** A worker ended without the answer it exists to give. */\nexport class SandboxWorkerFailed extends Error {\n\tconstructor(\n\t\treadonly step: string,\n\t\treadonly exitCode: number | null,\n\t\treadonly stderr: string,\n\t) {\n\t\tsuper(\n\t\t\t`The sandboxed ${step} ended (exit code ${exitCode}) without an ` +\n\t\t\t\t`answer.${stderr.trim() ? `\\n${stderr.trim()}` : ''}\\nIts output ` +\n\t\t\t\t'above says why; the sandbox must be able to run `node` with the ' +\n\t\t\t\t\"CLI's own files at the paths they have here.\",\n\t\t);\n\t\tthis.name = 'SandboxWorkerFailed';\n\t}\n}\n\nexport interface WorkerRun<T> {\n\t/** What the worker answered, as the schema reads it. */\n\tvalue: T;\n\t/** What it wrote to stderr: warnings a caller may pass on. */\n\tstderr: string;\n}\n\n/**\n * Run worker `name` in `sandbox`, and parse its answer with `schema`.\n *\n * The answer is the last marked line on stdout. Anything else the project's\n * code printed is ignored, and an answer the schema refuses is a failure\n * rather than data — a worker in an isolating sandbox runs code the host does\n * not trust.\n *\n * Within a run (`withSandbox`), the same worker asked the same question is\n * started once; every ask gets its own copy of the answer, and its stderr, as\n * though it had run again.\n */\nexport async function runWorker<S extends z.ZodType>(\n\tsandbox: Sandbox,\n\tstep: string,\n\toptions: WorkerOptions<S>,\n): Promise<WorkerRun<z.infer<S>>> {\n\tconst key = JSON.stringify([\n\t\toptions.name,\n\t\toptions.cwd,\n\t\toptions.args,\n\t\toptions.env ?? {},\n\t]);\n\tconst answer = await oncePerRun(sandbox, key, () =>\n\t\tstartWorker(sandbox, step, options),\n\t);\n\treturn structuredClone(answer);\n}\n\ninterface WorkerOptions<S extends z.ZodType> {\n\tname: string;\n\targs: readonly string[];\n\tcwd: string;\n\ttimeoutMs: number;\n\tenv?: Readonly<Record<string, string>>;\n\tsignal?: AbortSignal;\n\tschema: S;\n}\n\nasync function startWorker<S extends z.ZodType>(\n\tsandbox: Sandbox,\n\tstep: string,\n\toptions: WorkerOptions<S>,\n): Promise<WorkerRun<z.infer<S>>> {\n\tconst result = await sandbox.exec(\n\t\t'node',\n\t\tnodeWithTsx(workerFile(options.name), options.args),\n\t\t{\n\t\t\tcwd: options.cwd,\n\t\t\tenv: { ...sandbox.env, ...options.env },\n\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\toutput: 'capture',\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t},\n\t);\n\n\tconst line = result.stdout\n\t\t.split('\\n')\n\t\t.reverse()\n\t\t.find((l) => l.startsWith(WORKER_RESULT_MARKER));\n\tif (line) {\n\t\ttry {\n\t\t\tconst parsed = options.schema.safeParse(\n\t\t\t\tJSON.parse(line.slice(WORKER_RESULT_MARKER.length)),\n\t\t\t);\n\t\t\tif (parsed.success) return { value: parsed.data, stderr: result.stderr };\n\t\t} catch {\n\t\t\t// Not JSON: as good as no answer.\n\t\t}\n\t}\n\n\tthrow new SandboxWorkerFailed(step, result.exitCode, result.stderr);\n}\n","/**\n * Discovery — one glob, one structural test.\n *\n * A glob per kind is the same specialness the construct model removes, and\n * resources have no kind to be listed under: a declared `ObjectStorage` would\n * never be found by `routes:` or `crons:`. So there is one `constructs` glob,\n * every export of every matching module is inspected, and the per-kind\n * `isConstruct` checks collapse into a single question — does it have an id and\n * can it declare?\n *\n * Structural rather than `instanceof` on purpose. A construct from a different\n * copy of `@geekmidas/constructs` — a linked workspace, two versions in a\n * lockfile — is still a construct, and `instanceof` is exactly the check that\n * says otherwise.\n */\n\nimport { relative } from 'node:path';\nimport {\n\tassertDerivations,\n\ttype ConstructManifest,\n\tcanonicalId,\n\ttype Declaration,\n} from '@geekmidas/manifest';\nimport fg from 'fast-glob';\nimport { z } from 'zod';\nimport { clearZodGlobalRegistry } from '../generators/Generator';\nimport { output } from '../output';\nimport { activeSandbox, type Sandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** `console`, or the deploy run discovering the manifest. */\nconst logger = output;\n\n/** The construct face discovery needs: an id, and the ability to declare. */\ninterface Declarable {\n\tid: string;\n\tdeclare(): Declaration[];\n}\n\n/**\n * Whether a module export is a construct.\n *\n * Deliberately loose about what else it carries — a construct that also has a\n * `service` is still a construct, and requiring one would exclude the kinds that\n * own no address.\n */\nexport function isDeclarable(value: unknown): value is Declarable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Declarable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.declare === 'function'\n\t);\n}\n\nexport interface DiscoverOptions {\n\t/** The glob(s) to search. One pattern, not one per kind. */\n\tpatterns: string | readonly string[];\n\tcwd?: string;\n\t/**\n\t * Re-import changed modules, for the dev watcher.\n\t *\n\t * A single glob makes discovery more central, not less: a new construct file\n\t * has to be picked up on `add`, not only on `change`.\n\t */\n\tbustCache?: boolean;\n\t/**\n\t * Filled in with where each construct was found, when provided.\n\t *\n\t * Discovery is the only thing that knows: it globbed the files and imported\n\t * them. Everything downstream that needs to *write* an import — the build,\n\t * generating a server entry that reads a surface's logger — would otherwise\n\t * have to be told the path in config, which is the string this removes.\n\t *\n\t * An out-parameter rather than a second return value so that every existing\n\t * caller, which wants the manifest and nothing else, is unchanged.\n\t */\n\tsources?: Record<string, ConstructSource>;\n\t/**\n\t * Filled in, when provided, with the ids each owner's runnables declared an\n\t * edge to — keyed by the surface an endpoint was built from, or the worker\n\t * a cron or subscriber was.\n\t *\n\t * A runnable is not a declaration: a surface's endpoints are found by the\n\t * glob, not listed by the surface, so its node says `endpoints: []` until a\n\t * build folds the routes in. Anything deciding what an app's process reaches\n\t * — which keys its container is given — needs those edges before any build,\n\t * and discovery is already importing the files they are in.\n\t */\n\trunnables?: Record<string, string[]>;\n\t/**\n\t * Import the construct modules in this sandbox rather than in this\n\t * process. Defaults to the run's own (`withSandbox`), so a deploy's every\n\t * discovery — the engine's included — happens there; with neither, they\n\t * are imported here, as before.\n\t */\n\tsandbox?: Sandbox;\n}\n\n/** What the discovery worker answers. Checked: the worker ran project code. */\nconst DiscoverAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('discovered'),\n\t\tmanifest: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ id: z.string(), kind: z.string() }).loose(),\n\t\t),\n\t\trunnables: z.record(z.string(), z.array(z.string())),\n\t}),\n\tz.object({ reason: z.literal('live'), paths: z.array(z.string()) }),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z\n\t\t\t.object({\n\t\t\t\tname: z.string(),\n\t\t\t\tmessage: z.string(),\n\t\t\t\tid: z.string().optional(),\n\t\t\t\tsources: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.loose(),\n\t}),\n]);\n\n/**\n * The manifest, discovered in `sandbox` and handed back as JSON — or\n * `undefined` when it holds something JSON cannot carry and the sandbox is\n * not isolating, for the caller to discover here as before.\n */\nasync function discoverInSandbox(\n\tsandbox: Sandbox,\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest | undefined> {\n\tconst cwd = options.cwd ?? sandbox.root;\n\tconst patterns =\n\t\ttypeof options.patterns === 'string'\n\t\t\t? [options.patterns]\n\t\t\t: [...options.patterns];\n\n\tconst { value, stderr } = await runWorker(sandbox, 'construct discovery', {\n\t\tname: 'discover-worker',\n\t\targs: [JSON.stringify({ patterns, cwd })],\n\t\tcwd,\n\t\ttimeoutMs: DISCOVER_TIMEOUT_MS,\n\t\tschema: DiscoverAnswer,\n\t});\n\n\t// Discovery's own warnings — a glob that matched nothing — are the\n\t// run's, as they would be had it discovered in-process: as written, one\n\t// message, less the newline the worker's `console.warn` ended it with.\n\tif (stderr.trim()) logger.warn(stderr.replace(/\\n$/, ''));\n\n\tswitch (value.reason) {\n\t\tcase 'discovered':\n\t\t\tif (options.runnables) {\n\t\t\t\tfor (const [owner, edges] of Object.entries(value.runnables)) {\n\t\t\t\t\toptions.runnables[owner] = edges;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.manifest as unknown as ConstructManifest;\n\t\tcase 'failed':\n\t\t\tif (value.error.name === 'DuplicateConstruct' && value.error.id) {\n\t\t\t\tthrow new DuplicateConstruct(value.error.id, value.error.sources ?? []);\n\t\t\t}\n\t\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t\tcase 'live':\n\t\t\tif (sandbox.isolating) throw new ConstructsNotSerializable(value.paths);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * A caller asked for the construct objects (`sources`) or a watcher's\n * re-import under an isolating sandbox, where only data comes back.\n */\nexport class LiveConstructsUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'Discovery was asked for the construct objects themselves under an ' +\n\t\t\t\t'isolating sandbox, which hands back only data. Run this step ' +\n\t\t\t\t'without one, or ask only for the manifest.',\n\t\t);\n\t\tthis.name = 'LiveConstructsUnavailable';\n\t}\n}\n\n/** How long discovering a project's constructs may take in a sandbox. */\nconst DISCOVER_TIMEOUT_MS = 60_000;\n\n/** Importing a construct module, or declaring one, threw in the sandbox. */\nexport class ConstructDiscoveryFailed extends Error {\n\tconstructor(\n\t\treadonly errorName: string,\n\t\treadonly detail: string,\n\t) {\n\t\tsuper(`Discovering constructs failed (${errorName}): ${detail}`);\n\t\tthis.name = 'ConstructDiscoveryFailed';\n\t}\n}\n\n/**\n * The constructs' declarations hold something that is not data, and the\n * sandbox they were discovered in hands the deploy nothing but data.\n */\nexport class ConstructsNotSerializable extends Error {\n\tconstructor(readonly paths: readonly string[]) {\n\t\tsuper(\n\t\t\t`The construct manifest holds values that are not plain data at: ` +\n\t\t\t\t`${paths.join(', ')}. Under an isolating sandbox the deploy only ` +\n\t\t\t\t'receives what JSON can carry; deploy with a sandbox that is not ' +\n\t\t\t\t'isolating if the host trusts this project.',\n\t\t);\n\t\tthis.name = 'ConstructsNotSerializable';\n\t}\n}\n\n/** Where a construct was declared, and under what name. */\nexport interface ConstructSource {\n\t/** Absolute path to the module that exported it. */\n\tfile: string;\n\t/** The name it was exported as — what an import statement has to say. */\n\texportName: string;\n\t/**\n\t * The exported construct itself.\n\t *\n\t * What a declaration cannot say — whether it serves itself — the object can\n\t * be asked, and discovery already imported it.\n\t */\n\tconstruct: unknown;\n}\n\n/**\n * Build the construct manifest for a project.\n *\n * Runs the manifest's own validation before returning, so an app is wrong here\n * — where the error names a file — rather than at deploy.\n *\n * @throws {DuplicateConstruct} when two exports claim one id.\n */\nexport async function discover(\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest> {\n\tconst sandbox = options.sandbox ?? activeSandbox();\n\tif (sandbox) {\n\t\tif (!options.sources && !options.bustCache) {\n\t\t\tconst sandboxed = await discoverInSandbox(sandbox, options);\n\t\t\tif (sandboxed) return sandboxed;\n\t\t} else if (sandbox.isolating) {\n\t\t\t// The construct objects themselves, or a re-import for the watcher:\n\t\t\t// neither can cross a sandbox that hands back only data.\n\t\t\tthrow new LiveConstructsUnavailable();\n\t\t}\n\t}\n\n\tconst {\n\t\tpatterns,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t\tsources: out,\n\t} = options;\n\n\t// Re-importing user modules re-executes them, and Zod v4 throws on a\n\t// re-registered `.meta({ id })`. Same reason the generators clear it.\n\tif (bustCache) clearZodGlobalRegistry();\n\n\tconst manifest: Record<string, Declaration> = {};\n\t/** Which file declared each id, for the error when two of them do. */\n\tconst sources: Record<string, string> = {};\n\t/**\n\t * Constructs already seen, by identity.\n\t *\n\t * A re-export is the *same object* reached through a second file — ESM\n\t * bindings are live, so `export * from './database.js'` hands back the\n\t * binding rather than a copy. Without this, a barrel file made every\n\t * construct in it appear declared twice, and `constructs/index.ts` is the\n\t * first thing anyone writes in a shared folder.\n\t *\n\t * Identity rather than file is also the more honest rule: what may not\n\t * happen twice is two *different* constructs claiming one id, and that is\n\t * still an error below.\n\t */\n\tconst seen = new WeakSet<object>();\n\n\tconst globs = Array.isArray(patterns) ? [...patterns] : [patterns as string];\n\tconst files = fg.stream(globs, { cwd, absolute: true });\n\n\t/** Matched files, for the diagnostic below. */\n\tlet matched = 0;\n\n\tfor await (const found of files) {\n\t\tmatched++;\n\t\tconst file = found.toString();\n\t\tconst module = await import(bustCache ? `${file}?t=${Date.now()}` : file);\n\n\t\tfor (const [exportName, exported] of Object.entries(module)) {\n\t\t\tif (!isDeclarable(exported)) {\n\t\t\t\tif (options.runnables) recordRunnable(options.runnables, exported);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// The same construct, reached again through a re-export. Skipped\n\t\t\t// rather than re-declared: it has already claimed its id, from the\n\t\t\t// file that defined it.\n\t\t\tif (seen.has(exported as object)) continue;\n\t\t\tseen.add(exported as object);\n\n\t\t\t// A construct that is also something a process runs — a queue and its\n\t\t\t// consumer, built from a worker — reaches what it depends on through\n\t\t\t// that process, exactly as an endpoint or a cron does.\n\t\t\tif (\n\t\t\t\toptions.runnables &&\n\t\t\t\ttypeof (exported as { owner?: unknown }).owner === 'string'\n\t\t\t) {\n\t\t\t\trecordRunnable(options.runnables, exported);\n\t\t\t}\n\n\t\t\tfor (const declaration of exported.declare()) {\n\t\t\t\t// Canonicalise here too: a construct built by hand rather than through\n\t\t\t\t// a constructor is still subject to the same identity rule.\n\t\t\t\tconst id = canonicalId(declaration.id);\n\t\t\t\tconst source = relative(cwd, file);\n\n\t\t\t\tconst claimed = sources[id];\n\t\t\t\tif (claimed !== undefined && claimed !== source) {\n\t\t\t\t\tthrow new DuplicateConstruct(id, [claimed, source]);\n\t\t\t\t}\n\n\t\t\t\tmanifest[id] = { ...declaration, id };\n\t\t\t\tsources[id] = source;\n\t\t\t\tif (out) out[id] = { file, exportName, construct: exported };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Reference integrity before anyone reads it — a schema tenant naming a\n\t// database that was deleted is a manifest error, not a reconcile failure.\n\tassertDerivations(manifest);\n\n\twarnIfNothingFound(globs, matched, Object.keys(manifest).length);\n\n\treturn manifest;\n}\n\n/**\n * Record a runnable's edges under the construct that owns it — the surface an\n * endpoint was built from, or the worker a cron or subscriber was. Anything\n * with no owner, or that is not a runnable at all, is left alone.\n */\nfunction recordRunnable(\n\trunnables: Record<string, string[]>,\n\texported: unknown,\n): void {\n\tif (typeof exported !== 'object' || exported === null) return;\n\n\tconst runnable = exported as {\n\t\tsurface?: { id?: unknown };\n\t\towner?: unknown;\n\t\tconstructs?: unknown;\n\t};\n\tconst owner =\n\t\ttypeof runnable.surface?.id === 'string'\n\t\t\t? runnable.surface.id\n\t\t\t: typeof runnable.owner === 'string'\n\t\t\t\t? runnable.owner\n\t\t\t\t: undefined;\n\tif (!owner || !Array.isArray(runnable.constructs)) return;\n\n\tconst key = canonicalId(owner);\n\tconst edges = runnables[key] ?? [];\n\trunnables[key] = edges;\n\tfor (const id of runnable.constructs) {\n\t\tif (typeof id !== 'string') continue;\n\t\tconst target = canonicalId(id);\n\t\tif (!edges.includes(target)) edges.push(target);\n\t}\n}\n\n/**\n * Say so when a glob was configured and found nothing.\n *\n * The glob is not a filter over declarations already known — it is *how they\n * are found*, by importing what it matches. So a file it misses is a\n * declaration that does not exist, and every symptom of that appears somewhere\n * other than the cause: no container starts, no env key is written, and the\n * application fails on first use against a resource it can see in its own\n * source.\n *\n * Nothing reported it before, because an unmatched file is indistinguishable\n * from a file nobody wrote. These two cases are the ones that are *not*\n * ambiguous — a glob was configured, so something was expected.\n *\n * Silent when no glob is configured at all: that is a project which has not\n * adopted constructs, and has nothing to be missing.\n */\nfunction warnIfNothingFound(\n\tglobs: readonly string[],\n\tmatched: number,\n\tdeclared: number,\n): void {\n\tif (globs.length === 0) return;\n\n\tif (matched === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched no files, so nothing was declared.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Nothing will be provisioned — no containers, no env keys, no ` +\n\t\t\t\t`resources.\\n` +\n\t\t\t\t` A common cause is depth: '*.ts' matches one level, '**/*.ts' ` +\n\t\t\t\t`matches any.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (declared === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched ${matched} file(s) but none declared ` +\n\t\t\t\t`anything.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Discovery keeps exports with an 'id' that can 'declare()'. A ` +\n\t\t\t\t`construct that is\\n` +\n\t\t\t\t` built but never exported is invisible to it.`,\n\t\t);\n\t}\n}\n\n/** Two constructs claiming one id. */\nexport class DuplicateConstruct extends Error {\n\t/** The id claimed twice. */\n\treadonly id: string;\n\t/** The files that claimed it. */\n\treadonly sources: readonly string[];\n\n\tconstructor(id: string, sources: readonly string[]) {\n\t\tsuper('Two constructs declare the same id');\n\t\tthis.name = 'DuplicateConstruct';\n\t\tthis.id = id;\n\t\tthis.sources = sources;\n\t}\n}\n"],"mappings":"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"}
@@ -1,33 +0,0 @@
1
- let node_path = require("node:path");
2
- let node_os = require("node:os");
3
- //#region src/home.ts
4
- /**
5
- * Where the CLI keeps what belongs to a person rather than a project: stage
6
- * keys and stored provider credentials.
7
- *
8
- * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give
9
- * every run its own instead of reaching into whoever's home directory the
10
- * process happens to have. Unset, it is `~/.gkm`, where it has always been.
11
- */
12
- /** The environment variable that moves the CLI's home. */
13
- const GKM_HOME_ENV = "GKM_HOME";
14
- /** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */
15
- function gkmHome(env = process.env) {
16
- const configured = env[GKM_HOME_ENV];
17
- return configured ? (0, node_path.resolve)(configured) : (0, node_path.join)((0, node_os.homedir)(), ".gkm");
18
- }
19
- //#endregion
20
- Object.defineProperty(exports, "GKM_HOME_ENV", {
21
- enumerable: true,
22
- get: function() {
23
- return GKM_HOME_ENV;
24
- }
25
- });
26
- Object.defineProperty(exports, "gkmHome", {
27
- enumerable: true,
28
- get: function() {
29
- return gkmHome;
30
- }
31
- });
32
-
33
- //# sourceMappingURL=home-DOzBaWaL.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"home-DOzBaWaL.cjs","names":["resolve","join","homedir"],"sources":["../src/home.ts"],"sourcesContent":["/**\n * Where the CLI keeps what belongs to a person rather than a project: stage\n * keys and stored provider credentials.\n *\n * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give\n * every run its own instead of reaching into whoever's home directory the\n * process happens to have. Unset, it is `~/.gkm`, where it has always been.\n */\n\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** The environment variable that moves the CLI's home. */\nexport const GKM_HOME_ENV = 'GKM_HOME';\n\n/** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */\nexport function gkmHome(env: NodeJS.ProcessEnv = process.env): string {\n\tconst configured = env[GKM_HOME_ENV];\n\treturn configured ? resolve(configured) : join(homedir(), '.gkm');\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,eAAe;;AAG5B,SAAgB,QAAQ,MAAyB,QAAQ,KAAa;CACrE,MAAM,aAAa,IAAI;CACvB,OAAO,cAAA,GAAaA,UAAAA,QAAAA,CAAQ,UAAU,KAAA,GAAIC,UAAAA,KAAAA,EAAAA,GAAKC,QAAAA,QAAAA,CAAQ,GAAG,MAAM;AACjE"}
@@ -1,22 +0,0 @@
1
- import { join, resolve } from "node:path";
2
- import { homedir } from "node:os";
3
- //#region src/home.ts
4
- /**
5
- * Where the CLI keeps what belongs to a person rather than a project: stage
6
- * keys and stored provider credentials.
7
- *
8
- * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give
9
- * every run its own instead of reaching into whoever's home directory the
10
- * process happens to have. Unset, it is `~/.gkm`, where it has always been.
11
- */
12
- /** The environment variable that moves the CLI's home. */
13
- const GKM_HOME_ENV = "GKM_HOME";
14
- /** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */
15
- function gkmHome(env = process.env) {
16
- const configured = env[GKM_HOME_ENV];
17
- return configured ? resolve(configured) : join(homedir(), ".gkm");
18
- }
19
- //#endregion
20
- export { gkmHome as n, GKM_HOME_ENV as t };
21
-
22
- //# sourceMappingURL=home-GI7pJl1M.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"home-GI7pJl1M.mjs","names":[],"sources":["../src/home.ts"],"sourcesContent":["/**\n * Where the CLI keeps what belongs to a person rather than a project: stage\n * keys and stored provider credentials.\n *\n * `GKM_HOME` names it, so a CI job, a shared build runner or a test can give\n * every run its own instead of reaching into whoever's home directory the\n * process happens to have. Unset, it is `~/.gkm`, where it has always been.\n */\n\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** The environment variable that moves the CLI's home. */\nexport const GKM_HOME_ENV = 'GKM_HOME';\n\n/** The CLI's home: `GKM_HOME` if set, else `~/.gkm`. */\nexport function gkmHome(env: NodeJS.ProcessEnv = process.env): string {\n\tconst configured = env[GKM_HOME_ENV];\n\treturn configured ? resolve(configured) : join(homedir(), '.gkm');\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,eAAe;;AAG5B,SAAgB,QAAQ,MAAyB,QAAQ,KAAa;CACrE,MAAM,aAAa,IAAI;CACvB,OAAO,aAAa,QAAQ,UAAU,IAAI,KAAK,QAAQ,GAAG,MAAM;AACjE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolve-B1T0hUaR.mjs","names":[],"sources":["../src/target/provider.ts","../src/target/resolve.ts"],"sourcesContent":["/**\n * `gkm deploy --provider`, from before there were targets.\n *\n * It named three things, and only one of them ever deployed a workspace:\n * `dokploy` is now the target of that name; `docker` and `aws-lambda` were\n * accepted and always failed, so they are gone with a pointer to what does\n * the job.\n */\n\nimport { DeployTargetNotYetSupported } from './builtins';\n\n/** What each removed provider's job is done with now. */\nconst REMOVED: Record<string, string> = {\n\tdocker:\n\t\t'Build images with `gkm docker`, or run the stage as one Docker Compose stack with `gkm compose`',\n\t'aws-lambda':\n\t\t\"Deploy to AWS with SST: set deploy: { default: 'sst' } and run `gkm build && sst deploy --stage <stage>`\",\n};\n\n/** A `--provider` that no longer exists. */\nexport class ProviderRemoved extends Error {\n\tconstructor(\n\t\treadonly provider: string,\n\t\t/** What to use instead. */\n\t\treadonly instead: string,\n\t) {\n\t\tsuper(`--provider ${provider} has been removed. ${instead}.`);\n\t\tthis.name = 'ProviderRemoved';\n\t}\n}\n\n/** The deprecation `--provider` prints when it still means something. */\nexport function providerDeprecation(provider: string): string {\n\treturn `--provider is deprecated; use --target ${provider}.`;\n}\n\n/**\n * The target a `--provider` value means. `warn` hears the deprecation; a\n * provider that is gone, or a target not deployable yet, throws.\n */\nexport function targetForProvider(\n\tprovider: string,\n\twarn: (message: string) => void,\n): string {\n\tconst removed = REMOVED[provider];\n\tif (removed) throw new ProviderRemoved(provider, removed);\n\tif (provider === 'vercel' || provider === 'cloudflare') {\n\t\tthrow new DeployTargetNotYetSupported(provider);\n\t}\n\twarn(providerDeprecation(provider));\n\treturn provider;\n}\n","/**\n * From a target's name to the target.\n *\n * In this order, the first that has the name wins:\n *\n * 1. the host's own targets — what a program calling `deploy()` passes\n * 2. the built-ins — `dokploy`\n * 3. `deploy.targets` in gkm.config.ts — a package, an object, or either\n * with options\n *\n * Built-ins come before the config so that a dependency cannot take over\n * `dokploy` by being listed under its name. A name nothing has is\n * `UnknownDeployTarget`. There is deliberately no fourth step that guesses a\n * package from the name (`acme` → `@acme/gkm-target`): an npm scope nobody\n * has claimed can be claimed by anyone, and a deploy would then run their\n * code with the stage's credentials. A target is installed and named.\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tDeployTargetNotYetSupported,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { isDeployTarget } from './define';\nimport { importPackage } from './package';\nimport { declaredRuntime } from './runtime';\nimport type {\n\tAnyDeployTarget,\n\tDeployRuntime,\n\tDeployTargetEntry,\n\tTargetOptionsIssue,\n} from './types';\n\n/** Where a target came from. */\nexport type TargetSourceKind = 'host' | 'builtin' | 'config';\n\nexport interface ResolvedTarget {\n\t/** The name it was asked for by. */\n\tname: string;\n\ttarget: AnyDeployTarget;\n\tsource: TargetSourceKind;\n\t/** Its options as written in the config, before its schema parsed them. */\n\toptions: unknown;\n}\n\nexport interface ResolveTargetOptions {\n\t/** The workspace whose `deploy.targets` is consulted. */\n\tworkspace: {\n\t\troot: string;\n\t\tdeploy?: { targets?: Record<string, DeployTargetEntry> } | undefined;\n\t};\n\t/** The host's targets, consulted first. */\n\thost?: Record<string, AnyDeployTarget>;\n\t/** The stage being deployed, for what to do instead of a refused target. */\n\tstage: string;\n}\n\n/** A target package whose default export is not a target. */\nexport class TargetPackageInvalid extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names \"${packageName}\", whose default export is not a deploy target. A target package exports one as default: export default defineTarget({ … }) from '@geekmidas/cli/target'.`,\n\t\t);\n\t\tthis.name = 'TargetPackageInvalid';\n\t}\n}\n\n/** A `deploy.targets` entry that is not a target, a package name or a pair. */\nexport class TargetEntryInvalid extends Error {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} must be a package name, a target object (defineTarget), or [package or target, options].`,\n\t\t);\n\t\tthis.name = 'TargetEntryInvalid';\n\t}\n}\n\n/** A target whose `runtime` is not the one its package declares. */\nexport class TargetRuntimeMismatch extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly declared: DeployRuntime,\n\t\treadonly actual: DeployRuntime,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" runs on \"${actual}\", but ${packageName}'s package.json declares gkm.runtime \"${declared}\". gkm dev and gkm build chose backends for \"${declared}\", so the two must agree — fix the package.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeMismatch';\n\t}\n}\n\n/** Options a target's schema rejected. */\nexport class InvalidTargetOptions extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly issues: readonly TargetOptionsIssue[],\n\t) {\n\t\tconst lines = issues.map((issue) => {\n\t\t\tconst path = (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\t\t\treturn ` - ${path ? `${path}: ` : ''}${issue.message}`;\n\t\t});\n\t\tsuper(\n\t\t\t`The options for deploy target \"${target}\" are invalid — fix them in deploy.targets.${target} in gkm.config.ts:\\n${lines.join('\\n')}`,\n\t\t);\n\t\tthis.name = 'InvalidTargetOptions';\n\t}\n}\n\n/** The built-ins `gkm deploy` deploys through, loaded only when used. */\nconst BUILTIN_LOADERS: Record<string, () => Promise<AnyDeployTarget>> = {\n\tdokploy: async () => (await import('./dokploy')).dokployTarget,\n};\n\n/** The target `name` means, in this workspace, for this host. */\nexport async function resolveTarget(\n\tname: string,\n\t{ workspace, host, stage }: ResolveTargetOptions,\n): Promise<ResolvedTarget> {\n\tif (host && Object.hasOwn(host, name)) {\n\t\treturn { name, target: host[name]!, source: 'host', options: undefined };\n\t}\n\n\tconst builtin = builtinTarget(name);\n\tif (builtin) {\n\t\tconst load = BUILTIN_LOADERS[name];\n\t\tif (builtin.status !== 'available' || !load) {\n\t\t\tthrow new DeployTargetNotYetSupported(name, builtin.instead?.(stage));\n\t\t}\n\t\treturn {\n\t\t\tname,\n\t\t\ttarget: await load(),\n\t\t\tsource: 'builtin',\n\t\t\toptions: undefined,\n\t\t};\n\t}\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst [implementation, options] = Array.isArray(entry)\n\t\t? (entry as readonly [unknown, unknown])\n\t\t: [entry, undefined];\n\n\tif (typeof implementation === 'string') {\n\t\t// Before the import: a package that does not say where it runs is\n\t\t// refused without running any of its code.\n\t\tconst declared = declaredRuntime(name, implementation, workspace.root);\n\t\tconst loaded = await importPackage(name, implementation, workspace.root);\n\t\tconst target = loaded.default;\n\t\tif (!isDeployTarget(target)) {\n\t\t\tthrow new TargetPackageInvalid(name, implementation);\n\t\t}\n\t\tif (target.runtime !== declared) {\n\t\t\tthrow new TargetRuntimeMismatch(\n\t\t\t\tname,\n\t\t\t\timplementation,\n\t\t\t\tdeclared,\n\t\t\t\ttarget.runtime,\n\t\t\t);\n\t\t}\n\t\treturn { name, target, source: 'config', options };\n\t}\n\n\tif (!isDeployTarget(implementation)) throw new TargetEntryInvalid(name);\n\treturn { name, target: implementation, source: 'config', options };\n}\n\n/** The target's options, parsed by its schema. */\nexport async function parseTargetOptions(\n\tresolved: ResolvedTarget,\n): Promise<unknown> {\n\tconst { name, target, options } = resolved;\n\tif (!target.options) {\n\t\tif (options !== undefined) {\n\t\t\tthrow new InvalidTargetOptions(name, [\n\t\t\t\t{ message: 'this target takes no options' },\n\t\t\t]);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconst result = await target.options['~standard'].validate(options);\n\tif (result.issues) throw new InvalidTargetOptions(name, result.issues);\n\treturn result.value;\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,UAAkC;CACvC,QACC;CACD,cACC;AACF;;AAGA,IAAa,kBAAb,cAAqC,MAAM;CAEhC;CAEA;CAHV,YACC,UAEA,SACC;EACD,MAAM,cAAc,SAAS,qBAAqB,QAAQ,EAAE;EAJnD,KAAA,WAAA;EAEA,KAAA,UAAA;EAGT,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,oBAAoB,UAA0B;CAC7D,OAAO,0CAA0C,SAAS;AAC3D;;;;;AAMA,SAAgB,kBACf,UACA,MACS;CACT,MAAM,UAAU,QAAQ;CACxB,IAAI,SAAS,MAAM,IAAI,gBAAgB,UAAU,OAAO;CACxD,IAAI,aAAa,YAAY,aAAa,cACzC,MAAM,IAAI,4BAA4B,QAAQ;CAE/C,KAAK,oBAAoB,QAAQ,CAAC;CAClC,OAAO;AACR;;;;;;;;;;;;;;;;;;;;;ACSA,IAAa,uBAAb,cAA0C,MAAM;CAErC;CACA;CAFV,YACC,QACA,aACC;EACD,MACC,kBAAkB,OAAO,UAAU,YAAY,0JAChD;EALS,KAAA,SAAA;EACA,KAAA,cAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,qBAAb,cAAwC,MAAM;CACxB;CAArB,YAAY,QAAyB;EACpC,MACC,kBAAkB,OAAO,0FAC1B;EAHoB,KAAA,SAAA;EAIpB,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,wBAAb,cAA2C,MAAM;CAEtC;CACA;CACA;CACA;CAJV,YACC,QACA,aACA,UACA,QACC;EACD,MACC,sBAAsB,OAAO,aAAa,OAAO,SAAS,YAAY,wCAAwC,SAAS,+CAA+C,SAAS,4CAChL;EAPS,KAAA,SAAA;EACA,KAAA,cAAA;EACA,KAAA,WAAA;EACA,KAAA,SAAA;EAKT,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,uBAAb,cAA0C,MAAM;CAErC;CACA;CAFV,YACC,QACA,QACC;EACD,MAAM,QAAQ,OAAO,KAAK,UAAU;GACnC,MAAM,QAAQ,MAAM,QAAQ,CAAC,EAAA,CAC3B,KAAK,YACL,OAAO,YAAY,WAAW,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,CACnE,CAAC,CACA,KAAK,GAAG;GACV,OAAO,OAAO,OAAO,GAAG,KAAK,MAAM,KAAK,MAAM;EAC/C,CAAC;EACD,MACC,kCAAkC,OAAO,6CAA6C,OAAO,sBAAsB,MAAM,KAAK,IAAI,GACnI;EAbS,KAAA,SAAA;EACA,KAAA,SAAA;EAaT,KAAK,OAAO;CACb;AACD;;AAGA,MAAM,kBAAkE,EACvE,SAAS,aAAa,MAAM,OAAO,0BAAA,CAAc,cAClD;;AAGA,eAAsB,cACrB,MACA,EAAE,WAAW,MAAM,SACO;CAC1B,IAAI,QAAQ,OAAO,OAAO,MAAM,IAAI,GACnC,OAAO;EAAE;EAAM,QAAQ,KAAK;EAAQ,QAAQ;EAAQ,SAAS,KAAA;CAAU;CAGxE,MAAM,UAAU,cAAc,IAAI;CAClC,IAAI,SAAS;EACZ,MAAM,OAAO,gBAAgB;EAC7B,IAAI,QAAQ,WAAW,eAAe,CAAC,MACtC,MAAM,IAAI,4BAA4B,MAAM,QAAQ,UAAU,KAAK,CAAC;EAErE,OAAO;GACN;GACA,QAAQ,MAAM,KAAK;GACnB,QAAQ;GACR,SAAS,KAAA;EACV;CACD;CAEA,MAAM,QAAQ,iBAAiB,UAAU,QAAQ,IAAI;CACrD,IAAI,UAAU,KAAA,GACb,MAAM,IAAI,oBAAoB,MAAM,CACnC,GAAG,qBAAqB,GACxB,GAAG,OAAO,KAAK,UAAU,QAAQ,WAAW,CAAC,CAAC,CAC/C,CAAC;CAGF,MAAM,CAAC,gBAAgB,WAAW,MAAM,QAAQ,KAAK,IACjD,QACD,CAAC,OAAO,KAAA,CAAS;CAEpB,IAAI,OAAO,mBAAmB,UAAU;EAGvC,MAAM,WAAW,gBAAgB,MAAM,gBAAgB,UAAU,IAAI;EAErE,MAAM,UAAS,MADM,cAAc,MAAM,gBAAgB,UAAU,IAAI,EAAA,CACjD;EACtB,IAAI,CAAC,eAAe,MAAM,GACzB,MAAM,IAAI,qBAAqB,MAAM,cAAc;EAEpD,IAAI,OAAO,YAAY,UACtB,MAAM,IAAI,sBACT,MACA,gBACA,UACA,OAAO,OACR;EAED,OAAO;GAAE;GAAM;GAAQ,QAAQ;GAAU;EAAQ;CAClD;CAEA,IAAI,CAAC,eAAe,cAAc,GAAG,MAAM,IAAI,mBAAmB,IAAI;CACtE,OAAO;EAAE;EAAM,QAAQ;EAAgB,QAAQ;EAAU;CAAQ;AAClE;;AAGA,eAAsB,mBACrB,UACmB;CACnB,MAAM,EAAE,MAAM,QAAQ,YAAY;CAClC,IAAI,CAAC,OAAO,SAAS;EACpB,IAAI,YAAY,KAAA,GACf,MAAM,IAAI,qBAAqB,MAAM,CACpC,EAAE,SAAS,+BAA+B,CAC3C,CAAC;EAEF;CACD;CAEA,MAAM,SAAS,MAAM,OAAO,QAAQ,YAAY,CAAC,SAAS,OAAO;CACjE,IAAI,OAAO,QAAQ,MAAM,IAAI,qBAAqB,MAAM,OAAO,MAAM;CACrE,OAAO,OAAO;AACf"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolve-xytBTtG4.cjs","names":["DeployTargetNotYetSupported","builtinTarget","DeployTargetNotYetSupported","configuredTarget","UnknownDeployTarget","configurableBuiltins","declaredRuntime","importPackage","isDeployTarget"],"sources":["../src/target/provider.ts","../src/target/resolve.ts"],"sourcesContent":["/**\n * `gkm deploy --provider`, from before there were targets.\n *\n * It named three things, and only one of them ever deployed a workspace:\n * `dokploy` is now the target of that name; `docker` and `aws-lambda` were\n * accepted and always failed, so they are gone with a pointer to what does\n * the job.\n */\n\nimport { DeployTargetNotYetSupported } from './builtins';\n\n/** What each removed provider's job is done with now. */\nconst REMOVED: Record<string, string> = {\n\tdocker:\n\t\t'Build images with `gkm docker`, or run the stage as one Docker Compose stack with `gkm compose`',\n\t'aws-lambda':\n\t\t\"Deploy to AWS with SST: set deploy: { default: 'sst' } and run `gkm build && sst deploy --stage <stage>`\",\n};\n\n/** A `--provider` that no longer exists. */\nexport class ProviderRemoved extends Error {\n\tconstructor(\n\t\treadonly provider: string,\n\t\t/** What to use instead. */\n\t\treadonly instead: string,\n\t) {\n\t\tsuper(`--provider ${provider} has been removed. ${instead}.`);\n\t\tthis.name = 'ProviderRemoved';\n\t}\n}\n\n/** The deprecation `--provider` prints when it still means something. */\nexport function providerDeprecation(provider: string): string {\n\treturn `--provider is deprecated; use --target ${provider}.`;\n}\n\n/**\n * The target a `--provider` value means. `warn` hears the deprecation; a\n * provider that is gone, or a target not deployable yet, throws.\n */\nexport function targetForProvider(\n\tprovider: string,\n\twarn: (message: string) => void,\n): string {\n\tconst removed = REMOVED[provider];\n\tif (removed) throw new ProviderRemoved(provider, removed);\n\tif (provider === 'vercel' || provider === 'cloudflare') {\n\t\tthrow new DeployTargetNotYetSupported(provider);\n\t}\n\twarn(providerDeprecation(provider));\n\treturn provider;\n}\n","/**\n * From a target's name to the target.\n *\n * In this order, the first that has the name wins:\n *\n * 1. the host's own targets — what a program calling `deploy()` passes\n * 2. the built-ins — `dokploy`\n * 3. `deploy.targets` in gkm.config.ts — a package, an object, or either\n * with options\n *\n * Built-ins come before the config so that a dependency cannot take over\n * `dokploy` by being listed under its name. A name nothing has is\n * `UnknownDeployTarget`. There is deliberately no fourth step that guesses a\n * package from the name (`acme` → `@acme/gkm-target`): an npm scope nobody\n * has claimed can be claimed by anyone, and a deploy would then run their\n * code with the stage's credentials. A target is installed and named.\n */\n\nimport {\n\tbuiltinTarget,\n\tconfigurableBuiltins,\n\tconfiguredTarget,\n\tDeployTargetNotYetSupported,\n\tUnknownDeployTarget,\n} from './builtins';\nimport { isDeployTarget } from './define';\nimport { importPackage } from './package';\nimport { declaredRuntime } from './runtime';\nimport type {\n\tAnyDeployTarget,\n\tDeployRuntime,\n\tDeployTargetEntry,\n\tTargetOptionsIssue,\n} from './types';\n\n/** Where a target came from. */\nexport type TargetSourceKind = 'host' | 'builtin' | 'config';\n\nexport interface ResolvedTarget {\n\t/** The name it was asked for by. */\n\tname: string;\n\ttarget: AnyDeployTarget;\n\tsource: TargetSourceKind;\n\t/** Its options as written in the config, before its schema parsed them. */\n\toptions: unknown;\n}\n\nexport interface ResolveTargetOptions {\n\t/** The workspace whose `deploy.targets` is consulted. */\n\tworkspace: {\n\t\troot: string;\n\t\tdeploy?: { targets?: Record<string, DeployTargetEntry> } | undefined;\n\t};\n\t/** The host's targets, consulted first. */\n\thost?: Record<string, AnyDeployTarget>;\n\t/** The stage being deployed, for what to do instead of a refused target. */\n\tstage: string;\n}\n\n/** A target package whose default export is not a target. */\nexport class TargetPackageInvalid extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} names \"${packageName}\", whose default export is not a deploy target. A target package exports one as default: export default defineTarget({ … }) from '@geekmidas/cli/target'.`,\n\t\t);\n\t\tthis.name = 'TargetPackageInvalid';\n\t}\n}\n\n/** A `deploy.targets` entry that is not a target, a package name or a pair. */\nexport class TargetEntryInvalid extends Error {\n\tconstructor(readonly target: string) {\n\t\tsuper(\n\t\t\t`deploy.targets.${target} must be a package name, a target object (defineTarget), or [package or target, options].`,\n\t\t);\n\t\tthis.name = 'TargetEntryInvalid';\n\t}\n}\n\n/** A target whose `runtime` is not the one its package declares. */\nexport class TargetRuntimeMismatch extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly packageName: string,\n\t\treadonly declared: DeployRuntime,\n\t\treadonly actual: DeployRuntime,\n\t) {\n\t\tsuper(\n\t\t\t`The deploy target \"${target}\" runs on \"${actual}\", but ${packageName}'s package.json declares gkm.runtime \"${declared}\". gkm dev and gkm build chose backends for \"${declared}\", so the two must agree — fix the package.`,\n\t\t);\n\t\tthis.name = 'TargetRuntimeMismatch';\n\t}\n}\n\n/** Options a target's schema rejected. */\nexport class InvalidTargetOptions extends Error {\n\tconstructor(\n\t\treadonly target: string,\n\t\treadonly issues: readonly TargetOptionsIssue[],\n\t) {\n\t\tconst lines = issues.map((issue) => {\n\t\t\tconst path = (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\t\t\treturn ` - ${path ? `${path}: ` : ''}${issue.message}`;\n\t\t});\n\t\tsuper(\n\t\t\t`The options for deploy target \"${target}\" are invalid — fix them in deploy.targets.${target} in gkm.config.ts:\\n${lines.join('\\n')}`,\n\t\t);\n\t\tthis.name = 'InvalidTargetOptions';\n\t}\n}\n\n/** The built-ins `gkm deploy` deploys through, loaded only when used. */\nconst BUILTIN_LOADERS: Record<string, () => Promise<AnyDeployTarget>> = {\n\tdokploy: async () => (await import('./dokploy')).dokployTarget,\n};\n\n/** The target `name` means, in this workspace, for this host. */\nexport async function resolveTarget(\n\tname: string,\n\t{ workspace, host, stage }: ResolveTargetOptions,\n): Promise<ResolvedTarget> {\n\tif (host && Object.hasOwn(host, name)) {\n\t\treturn { name, target: host[name]!, source: 'host', options: undefined };\n\t}\n\n\tconst builtin = builtinTarget(name);\n\tif (builtin) {\n\t\tconst load = BUILTIN_LOADERS[name];\n\t\tif (builtin.status !== 'available' || !load) {\n\t\t\tthrow new DeployTargetNotYetSupported(name, builtin.instead?.(stage));\n\t\t}\n\t\treturn {\n\t\t\tname,\n\t\t\ttarget: await load(),\n\t\t\tsource: 'builtin',\n\t\t\toptions: undefined,\n\t\t};\n\t}\n\n\tconst entry = configuredTarget(workspace.deploy, name);\n\tif (entry === undefined) {\n\t\tthrow new UnknownDeployTarget(name, [\n\t\t\t...configurableBuiltins(),\n\t\t\t...Object.keys(workspace.deploy?.targets ?? {}),\n\t\t]);\n\t}\n\n\tconst [implementation, options] = Array.isArray(entry)\n\t\t? (entry as readonly [unknown, unknown])\n\t\t: [entry, undefined];\n\n\tif (typeof implementation === 'string') {\n\t\t// Before the import: a package that does not say where it runs is\n\t\t// refused without running any of its code.\n\t\tconst declared = declaredRuntime(name, implementation, workspace.root);\n\t\tconst loaded = await importPackage(name, implementation, workspace.root);\n\t\tconst target = loaded.default;\n\t\tif (!isDeployTarget(target)) {\n\t\t\tthrow new TargetPackageInvalid(name, implementation);\n\t\t}\n\t\tif (target.runtime !== declared) {\n\t\t\tthrow new TargetRuntimeMismatch(\n\t\t\t\tname,\n\t\t\t\timplementation,\n\t\t\t\tdeclared,\n\t\t\t\ttarget.runtime,\n\t\t\t);\n\t\t}\n\t\treturn { name, target, source: 'config', options };\n\t}\n\n\tif (!isDeployTarget(implementation)) throw new TargetEntryInvalid(name);\n\treturn { name, target: implementation, source: 'config', options };\n}\n\n/** The target's options, parsed by its schema. */\nexport async function parseTargetOptions(\n\tresolved: ResolvedTarget,\n): Promise<unknown> {\n\tconst { name, target, options } = resolved;\n\tif (!target.options) {\n\t\tif (options !== undefined) {\n\t\t\tthrow new InvalidTargetOptions(name, [\n\t\t\t\t{ message: 'this target takes no options' },\n\t\t\t]);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconst result = await target.options['~standard'].validate(options);\n\tif (result.issues) throw new InvalidTargetOptions(name, result.issues);\n\treturn result.value;\n}\n"],"mappings":"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"}