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

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 (216) hide show
  1. package/README.md +1 -1
  2. package/dist/{HostingerProvider-mJ7YruxH.cjs → HostingerProvider-Dlmbfass.cjs} +3 -3
  3. package/dist/{HostingerProvider-mJ7YruxH.cjs.map → HostingerProvider-Dlmbfass.cjs.map} +1 -1
  4. package/dist/{HostingerProvider-DBBwpDjn.mjs → HostingerProvider-x9gQTAGZ.mjs} +2 -2
  5. package/dist/{HostingerProvider-DBBwpDjn.mjs.map → HostingerProvider-x9gQTAGZ.mjs.map} +1 -1
  6. package/dist/{LegacyStateStore-CP7SZwTP.cjs → LegacyStateStore-BGoo__sO.cjs} +2 -2
  7. package/dist/{LegacyStateStore-CP7SZwTP.cjs.map → LegacyStateStore-BGoo__sO.cjs.map} +1 -1
  8. package/dist/{LegacyStateStore-Q3GmKOdw.mjs → LegacyStateStore-BUu1nQ5u.mjs} +2 -2
  9. package/dist/{LegacyStateStore-Q3GmKOdw.mjs.map → LegacyStateStore-BUu1nQ5u.mjs.map} +1 -1
  10. package/dist/{LocalStateStore-sS8mvLeq.cjs → LocalStateStore-93urXyQe.cjs} +2 -2
  11. package/dist/{LocalStateStore-sS8mvLeq.cjs.map → LocalStateStore-93urXyQe.cjs.map} +1 -1
  12. package/dist/{LocalStateStore-BGIXcrvX.mjs → LocalStateStore-BRhMQRuy.mjs} +2 -2
  13. package/dist/{LocalStateStore-BGIXcrvX.mjs.map → LocalStateStore-BRhMQRuy.mjs.map} +1 -1
  14. package/dist/{OpenApiTsGenerator-CjHWFRDd.cjs → OpenApiTsGenerator-BWuDRHe9.cjs} +2 -2
  15. package/dist/{OpenApiTsGenerator-CjHWFRDd.cjs.map → OpenApiTsGenerator-BWuDRHe9.cjs.map} +1 -1
  16. package/dist/{OpenApiTsGenerator-CnAwhGxi.mjs → OpenApiTsGenerator-C6v-IeHt.mjs} +2 -2
  17. package/dist/{OpenApiTsGenerator-CnAwhGxi.mjs.map → OpenApiTsGenerator-C6v-IeHt.mjs.map} +1 -1
  18. package/dist/{S3StateStore-6jqITH2F.cjs → S3StateStore-F4dxw6kS.cjs} +2 -2
  19. package/dist/{S3StateStore-6jqITH2F.cjs.map → S3StateStore-F4dxw6kS.cjs.map} +1 -1
  20. package/dist/{S3StateStore-D7l_lWJ3.mjs → S3StateStore-pw1GhWwt.mjs} +2 -2
  21. package/dist/{S3StateStore-D7l_lWJ3.mjs.map → S3StateStore-pw1GhWwt.mjs.map} +1 -1
  22. package/dist/{SSMStateStore-B__F7IJa.cjs → SSMStateStore-Bt9acuAF.cjs} +2 -2
  23. package/dist/{SSMStateStore-B__F7IJa.cjs.map → SSMStateStore-Bt9acuAF.cjs.map} +1 -1
  24. package/dist/{SSMStateStore-CAQDVpoc.mjs → SSMStateStore-Dmj7zzFO.mjs} +2 -2
  25. package/dist/{SSMStateStore-CAQDVpoc.mjs.map → SSMStateStore-Dmj7zzFO.mjs.map} +1 -1
  26. package/dist/{bundler-DLfOn0ls.cjs → bundler-D6MlIfBT.cjs} +3 -3
  27. package/dist/{bundler-DLfOn0ls.cjs.map → bundler-D6MlIfBT.cjs.map} +1 -1
  28. package/dist/{bundler-DyWI41Iy.mjs → bundler-D_14JLZF.mjs} +3 -3
  29. package/dist/{bundler-DyWI41Iy.mjs.map → bundler-D_14JLZF.mjs.map} +1 -1
  30. package/dist/{cli-D-ZM-X2s.cjs → cli-BfH1deAT.cjs} +8 -7
  31. package/dist/{cli-D-ZM-X2s.cjs.map → cli-BfH1deAT.cjs.map} +1 -1
  32. package/dist/{cli-PkVF28LM.mjs → cli-P56vvrDQ.mjs} +5 -4
  33. package/dist/{cli-PkVF28LM.mjs.map → cli-P56vvrDQ.mjs.map} +1 -1
  34. package/dist/compose-391oEKj1.cjs +1982 -0
  35. package/dist/compose-391oEKj1.cjs.map +1 -0
  36. package/dist/compose-DprE3ASm.mjs +1862 -0
  37. package/dist/compose-DprE3ASm.mjs.map +1 -0
  38. package/dist/{config-C2BUosLm.d.mts → config-BonvTW8p.d.mts} +3 -3
  39. package/dist/{config-C2BUosLm.d.mts.map → config-BonvTW8p.d.mts.map} +1 -1
  40. package/dist/{config-CemHVcIr.d.cts → config-V_X_BMpm.d.cts} +3 -3
  41. package/dist/{config-CemHVcIr.d.cts.map → config-V_X_BMpm.d.cts.map} +1 -1
  42. package/dist/config.cjs +416 -17
  43. package/dist/config.cjs.map +1 -0
  44. package/dist/config.d.cts +3 -3
  45. package/dist/config.d.mts +3 -3
  46. package/dist/config.mjs +401 -2
  47. package/dist/config.mjs.map +1 -0
  48. package/dist/credentials-Bzbg23n8.cjs +298 -0
  49. package/dist/credentials-Bzbg23n8.cjs.map +1 -0
  50. package/dist/credentials-Dq1MnWQf.mjs +233 -0
  51. package/dist/credentials-Dq1MnWQf.mjs.map +1 -0
  52. package/dist/{define-CHBIEc5j.mjs → define-DR8xGYfL.mjs} +6 -3
  53. package/dist/define-DR8xGYfL.mjs.map +1 -0
  54. package/dist/{define-Cv_QvDrg.cjs → define-DzRz8FgH.cjs} +6 -3
  55. package/dist/define-DzRz8FgH.cjs.map +1 -0
  56. package/dist/deploy/public.cjs +39 -33
  57. package/dist/deploy/public.cjs.map +1 -1
  58. package/dist/deploy/public.d.cts +44 -5
  59. package/dist/deploy/public.d.cts.map +1 -1
  60. package/dist/deploy/public.d.mts +44 -5
  61. package/dist/deploy/public.d.mts.map +1 -1
  62. package/dist/deploy/public.mjs +15 -12
  63. package/dist/deploy/public.mjs.map +1 -1
  64. package/dist/{deploy-CGW-QY9D.mjs → deploy-9MBG_QLd.mjs} +11 -9
  65. package/dist/deploy-9MBG_QLd.mjs.map +1 -0
  66. package/dist/{deploy-BiMrP9i7.cjs → deploy-B80idPUZ.cjs} +17 -15
  67. package/dist/deploy-B80idPUZ.cjs.map +1 -0
  68. package/dist/{deploy-CG8bfFij.mjs → deploy-CZ5nlpsu.mjs} +16 -119
  69. package/dist/deploy-CZ5nlpsu.mjs.map +1 -0
  70. package/dist/{deploy-ABBI0lf1.cjs → deploy-Cy8igpQF.cjs} +48 -151
  71. package/dist/deploy-Cy8igpQF.cjs.map +1 -0
  72. package/dist/derive-B4vDpzgP.mjs +150 -0
  73. package/dist/derive-B4vDpzgP.mjs.map +1 -0
  74. package/dist/derive-DAbo49sm.cjs +161 -0
  75. package/dist/derive-DAbo49sm.cjs.map +1 -0
  76. package/dist/{discover-C_6COHEv.cjs → discover-DHdECueV.cjs} +6 -157
  77. package/dist/discover-DHdECueV.cjs.map +1 -0
  78. package/dist/{discover-BaT6bpnA.mjs → discover-LMrqsWSU.mjs} +8 -117
  79. package/dist/discover-LMrqsWSU.mjs.map +1 -0
  80. package/dist/{dokploy-CwdmlyQL.mjs → dokploy-BdtBePjp.mjs} +3 -3
  81. package/dist/{dokploy-CwdmlyQL.mjs.map → dokploy-BdtBePjp.mjs.map} +1 -1
  82. package/dist/{dokploy-QJxMhxdf.cjs → dokploy-iFY8MY-L.cjs} +3 -3
  83. package/dist/{dokploy-QJxMhxdf.cjs.map → dokploy-iFY8MY-L.cjs.map} +1 -1
  84. package/dist/{encryption-DXw3jj0c.cjs → encryption-B1wJwgae.cjs} +6 -6
  85. package/dist/{encryption-DXw3jj0c.cjs.map → encryption-B1wJwgae.cjs.map} +1 -1
  86. package/dist/{encryption-CbQG_ayW.mjs → encryption-DF_hgIpl.mjs} +5 -5
  87. package/dist/{encryption-CbQG_ayW.mjs.map → encryption-DF_hgIpl.mjs.map} +1 -1
  88. package/dist/{github-ciwbIwVa.mjs → github-B0YYE98x.mjs} +4 -4
  89. package/dist/{github-ciwbIwVa.mjs.map → github-B0YYE98x.mjs.map} +1 -1
  90. package/dist/{github-BH_mETav.cjs → github-CYcmTdFs.cjs} +4 -4
  91. package/dist/{github-BH_mETav.cjs.map → github-CYcmTdFs.cjs.map} +1 -1
  92. package/dist/{index-DrKzpHl-.d.mts → index-DPUAGJaK.d.cts} +16 -3
  93. package/dist/index-DPUAGJaK.d.cts.map +1 -0
  94. package/dist/{index-BtXDZQuF.d.cts → index-DwKD_8lt.d.mts} +16 -3
  95. package/dist/index-DwKD_8lt.d.mts.map +1 -0
  96. package/dist/index.cjs +280 -1849
  97. package/dist/index.cjs.map +1 -1
  98. package/dist/index.mjs +221 -1774
  99. package/dist/index.mjs.map +1 -1
  100. package/dist/local-BdH4XN0E.cjs +409 -0
  101. package/dist/local-BdH4XN0E.cjs.map +1 -0
  102. package/dist/local-CWR4Y_kW.mjs +350 -0
  103. package/dist/local-CWR4Y_kW.mjs.map +1 -0
  104. package/dist/{migrate-ImBKTBcW.mjs → migrate-B2qL5wj4.mjs} +8 -7
  105. package/dist/{migrate-ImBKTBcW.mjs.map → migrate-B2qL5wj4.mjs.map} +1 -1
  106. package/dist/{migrate-6oa9y_f2.cjs → migrate-q4pPAXtO.cjs} +21 -20
  107. package/dist/{migrate-6oa9y_f2.cjs.map → migrate-q4pPAXtO.cjs.map} +1 -1
  108. package/dist/openapi.cjs +2 -2
  109. package/dist/openapi.d.cts +1 -1
  110. package/dist/openapi.d.mts +1 -1
  111. package/dist/openapi.mjs +2 -2
  112. package/dist/provider-C9_-45d5.cjs +56 -0
  113. package/dist/provider-C9_-45d5.cjs.map +1 -0
  114. package/dist/provider-q4lsYzYG.mjs +45 -0
  115. package/dist/provider-q4lsYzYG.mjs.map +1 -0
  116. package/dist/{ready-Bpdnn2ON.mjs → ready-bQfu9GES.mjs} +3 -3
  117. package/dist/{ready-Bpdnn2ON.mjs.map → ready-bQfu9GES.mjs.map} +1 -1
  118. package/dist/{ready-BiG0rt4h.cjs → ready-brEhh68f.cjs} +3 -3
  119. package/dist/{ready-BiG0rt4h.cjs.map → ready-brEhh68f.cjs.map} +1 -1
  120. package/dist/reconcile/public.cjs +1 -1
  121. package/dist/reconcile/public.d.cts +1 -1
  122. package/dist/reconcile/public.d.mts +1 -1
  123. package/dist/reconcile/public.mjs +1 -1
  124. package/dist/resolve-DLkIXTct.mjs +262 -0
  125. package/dist/resolve-DLkIXTct.mjs.map +1 -0
  126. package/dist/resolve-N_i4XNd-.cjs +315 -0
  127. package/dist/resolve-N_i4XNd-.cjs.map +1 -0
  128. package/dist/{runtime-Dn_n-29S.d.cts → runtime-BnD7Nn96.d.cts} +2 -2
  129. package/dist/{runtime-CXPlkZzs.d.mts.map → runtime-BnD7Nn96.d.cts.map} +1 -1
  130. package/dist/{runtime-CXPlkZzs.d.mts → runtime-j-tmFL65.d.mts} +2 -2
  131. package/dist/{runtime-Dn_n-29S.d.cts.map → runtime-j-tmFL65.d.mts.map} +1 -1
  132. package/dist/sandbox/discover-worker.cjs +1 -1
  133. package/dist/sandbox/discover-worker.mjs +1 -1
  134. package/dist/sandbox-CL--ZDui.cjs +164 -0
  135. package/dist/sandbox-CL--ZDui.cjs.map +1 -0
  136. package/dist/sandbox-Dm247NGx.mjs +117 -0
  137. package/dist/sandbox-Dm247NGx.mjs.map +1 -0
  138. package/dist/sniffer-BSwaL-dX.cjs +2236 -0
  139. package/dist/sniffer-BSwaL-dX.cjs.map +1 -0
  140. package/dist/sniffer-BZ-OJO4Y.mjs +2068 -0
  141. package/dist/sniffer-BZ-OJO4Y.mjs.map +1 -0
  142. package/dist/sst-B2HbrDR3.mjs +430 -0
  143. package/dist/sst-B2HbrDR3.mjs.map +1 -0
  144. package/dist/sst-DcfsVH6x.cjs +453 -0
  145. package/dist/sst-DcfsVH6x.cjs.map +1 -0
  146. package/dist/{sniffer-aO_-s5vq.mjs → state-B8YwmUZU.mjs} +1204 -3236
  147. package/dist/state-B8YwmUZU.mjs.map +1 -0
  148. package/dist/{sniffer-D_SYc_pO.cjs → state-DF26e_lo.cjs} +1251 -3494
  149. package/dist/state-DF26e_lo.cjs.map +1 -0
  150. package/dist/{store-KvNQwYaB.cjs → store-CJF1Tqkq.cjs} +4 -4
  151. package/dist/{store-KvNQwYaB.cjs.map → store-CJF1Tqkq.cjs.map} +1 -1
  152. package/dist/{store-BS8A7NcA.mjs → store-CLiHnqOY.mjs} +2 -2
  153. package/dist/{store-BS8A7NcA.mjs.map → store-CLiHnqOY.mjs.map} +1 -1
  154. package/dist/target/public.cjs +6 -6
  155. package/dist/target/public.d.cts +3 -3
  156. package/dist/target/public.d.mts +3 -3
  157. package/dist/target/public.mjs +3 -3
  158. package/dist/terminal-Bs5E1oxm.cjs +88 -0
  159. package/dist/terminal-Bs5E1oxm.cjs.map +1 -0
  160. package/dist/terminal-CfbiYUbZ.mjs +84 -0
  161. package/dist/terminal-CfbiYUbZ.mjs.map +1 -0
  162. package/dist/{types-DIA7Li-J.d.cts → types-BCzMWBb6.d.mts} +84 -17
  163. package/dist/types-BCzMWBb6.d.mts.map +1 -0
  164. package/dist/{types-CfLKGfC_.d.mts → types-ByMWkXKP.d.cts} +85 -16
  165. package/dist/types-ByMWkXKP.d.cts.map +1 -0
  166. package/dist/utils-D2Nk1Nv2.cjs +205 -0
  167. package/dist/utils-D2Nk1Nv2.cjs.map +1 -0
  168. package/dist/utils-D_fxUqvU.mjs +156 -0
  169. package/dist/utils-D_fxUqvU.mjs.map +1 -0
  170. package/dist/vitest.cjs +1 -1
  171. package/dist/vitest.mjs +1 -1
  172. package/dist/workspace/index.cjs +3 -1
  173. package/dist/workspace/index.d.cts +3 -3
  174. package/dist/workspace/index.d.mts +3 -3
  175. package/dist/workspace/index.mjs +2 -2
  176. package/dist/{workspace-Kl4NG9IH.cjs → workspace-BewAHZIo.cjs} +41 -6
  177. package/dist/workspace-BewAHZIo.cjs.map +1 -0
  178. package/dist/{workspace-Dh7rr7l4.mjs → workspace-C06_pW4g.mjs} +30 -7
  179. package/dist/workspace-C06_pW4g.mjs.map +1 -0
  180. package/package.json +13 -13
  181. package/dist/config-BEJYKd4s.cjs +0 -648
  182. package/dist/config-BEJYKd4s.cjs.map +0 -1
  183. package/dist/config-LKKCVCnC.mjs +0 -547
  184. package/dist/config-LKKCVCnC.mjs.map +0 -1
  185. package/dist/define-CHBIEc5j.mjs.map +0 -1
  186. package/dist/define-Cv_QvDrg.cjs.map +0 -1
  187. package/dist/deploy-ABBI0lf1.cjs.map +0 -1
  188. package/dist/deploy-BiMrP9i7.cjs.map +0 -1
  189. package/dist/deploy-CG8bfFij.mjs.map +0 -1
  190. package/dist/deploy-CGW-QY9D.mjs.map +0 -1
  191. package/dist/discover-BaT6bpnA.mjs.map +0 -1
  192. package/dist/discover-C_6COHEv.cjs.map +0 -1
  193. package/dist/home-DOzBaWaL.cjs +0 -33
  194. package/dist/home-DOzBaWaL.cjs.map +0 -1
  195. package/dist/home-GI7pJl1M.mjs +0 -22
  196. package/dist/home-GI7pJl1M.mjs.map +0 -1
  197. package/dist/index-BtXDZQuF.d.cts.map +0 -1
  198. package/dist/index-DrKzpHl-.d.mts.map +0 -1
  199. package/dist/resolve-B1T0hUaR.mjs +0 -170
  200. package/dist/resolve-B1T0hUaR.mjs.map +0 -1
  201. package/dist/resolve-xytBTtG4.cjs +0 -217
  202. package/dist/resolve-xytBTtG4.cjs.map +0 -1
  203. package/dist/runtime-CMwtq0AL.cjs +0 -163
  204. package/dist/runtime-CMwtq0AL.cjs.map +0 -1
  205. package/dist/runtime-DbakJS8u.mjs +0 -134
  206. package/dist/runtime-DbakJS8u.mjs.map +0 -1
  207. package/dist/sniffer-D_SYc_pO.cjs.map +0 -1
  208. package/dist/sniffer-aO_-s5vq.mjs.map +0 -1
  209. package/dist/terminal-D0f1u0LG.cjs +0 -576
  210. package/dist/terminal-D0f1u0LG.cjs.map +0 -1
  211. package/dist/terminal-gMxAo9Dj.mjs +0 -517
  212. package/dist/terminal-gMxAo9Dj.mjs.map +0 -1
  213. package/dist/types-CfLKGfC_.d.mts.map +0 -1
  214. package/dist/types-DIA7Li-J.d.cts.map +0 -1
  215. package/dist/workspace-Dh7rr7l4.mjs.map +0 -1
  216. package/dist/workspace-Kl4NG9IH.cjs.map +0 -1
@@ -0,0 +1,150 @@
1
+ import { kebabCase } from "@geekmidas/manifest";
2
+ //#region src/workspace/derive.ts
3
+ /**
4
+ * The apps a manifest implies.
5
+ *
6
+ * `gkm.config.ts` used to carry an `apps` block naming every app: its type, its
7
+ * path, its port, its framework, which other apps it depended on. Every one of
8
+ * those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`
9
+ * and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',
10
+ * dependencies: ['api'] }` are the same statement written twice, and only one of
11
+ * them was checked against anything — so the copy in config was free to drift,
12
+ * and a surface config had no entry for simply never deployed.
13
+ *
14
+ * So the list comes from the graph. A `site` is an app, and so is every
15
+ * `rest-api` — one surface, one container, at the `path` it declared.
16
+ *
17
+ * What config still supplies is what no graph can answer: the backends a cache
18
+ * and a mailer resolve to, the deploy endpoint, the stage's domain.
19
+ */
20
+ /** Which frontend framework builds each site variant. */
21
+ const FRAMEWORKS = {
22
+ static: "vite",
23
+ next: "nextjs",
24
+ tanstack: "tanstack-start"
25
+ };
26
+ /**
27
+ * The app key a construct id becomes.
28
+ *
29
+ * The same kebab form every physical name is built from, so `Api` is `api` in
30
+ * the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an
31
+ * environment — one id, three renderings, no second list.
32
+ */
33
+ function appKey(id) {
34
+ return kebabCase(id);
35
+ }
36
+ /**
37
+ * The app serving a surface: its own, always.
38
+ *
39
+ * Every surface gets a container. There is no arrangement in which one runs
40
+ * inside another — two surfaces in a process share a filesystem, an
41
+ * environment, and every credential either was granted, so an auth server
42
+ * beside an API is one bug in the API away from being read by it.
43
+ */
44
+ function hostOf(manifest, id) {
45
+ const declaration = manifest[id];
46
+ if (!declaration || declaration.kind !== "rest-api") return void 0;
47
+ return id;
48
+ }
49
+ /**
50
+ * Local ports, assigned so that adding a site does not renumber the others.
51
+ *
52
+ * Backends first, then the site holding the base domain, then the rest
53
+ * alphabetically. The ordering is arbitrary but it is *fixed*, which is the
54
+ * property that matters: a port that moves when an unrelated app is added is a
55
+ * port nobody can put in a bookmark. A construct that names its own port keeps
56
+ * it, and is skipped here.
57
+ */
58
+ function assignPorts(apps) {
59
+ const rank = (name, app) => [
60
+ app.type === "backend" ? 0 : app.type === "web" ? 1 : 2,
61
+ app.root ? 0 : 1,
62
+ name
63
+ ];
64
+ const ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {
65
+ const [at, ar, an] = rank(aName, a);
66
+ const [bt, br, bn] = rank(bName, b);
67
+ return at - bt || ar - br || an.localeCompare(bn);
68
+ });
69
+ const taken = new Set(ordered.map(([, app]) => app.port).filter((p) => !!p));
70
+ let next = 3e3;
71
+ for (const [, app] of ordered) {
72
+ if (app.port) continue;
73
+ while (taken.has(next)) next += 1;
74
+ app.port = next;
75
+ taken.add(next);
76
+ }
77
+ }
78
+ /**
79
+ * Whichever site holds the base domain.
80
+ *
81
+ * The convention first — a site named `web` — because it is one people already
82
+ * rely on. Then an explicit `root: true`. A project with one site needs neither.
83
+ */
84
+ function markRoot(apps) {
85
+ const sites = Object.entries(apps).filter(([, a]) => a.type === "web");
86
+ if (sites.length === 0) return;
87
+ if (sites.some(([, a]) => a.root)) return;
88
+ const chosen = sites.find(([name]) => name === "web") ?? (sites.length === 1 ? sites[0] : void 0);
89
+ if (chosen) chosen[1].root = true;
90
+ }
91
+ function derivedApps(manifest, workspace) {
92
+ const apps = {};
93
+ const defaultTarget = workspace.deploy?.default ?? "dokploy";
94
+ for (const [id, declaration] of Object.entries(manifest)) {
95
+ if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
96
+ const spec = declaration.kind === "site" || declaration.kind === "mobile-app" ? declaration.app : {
97
+ path: declaration.path,
98
+ ...declaration.telescope ? { telescope: true } : {}
99
+ };
100
+ const name = appKey(id);
101
+ const configured = workspace.apps[name];
102
+ apps[name] = {
103
+ ...configured,
104
+ type: declaration.kind === "site" ? "web" : declaration.kind === "mobile-app" ? "mobile" : "backend",
105
+ path: spec.path,
106
+ port: spec.port ?? configured?.port ?? 0,
107
+ ...(declaration.kind === "rest-api" || declaration.kind === "site") && declaration.subdomain ? { subdomain: declaration.subdomain } : {},
108
+ dependencies: [],
109
+ resolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,
110
+ ...declaration.kind === "site" ? {
111
+ framework: configured?.framework ?? FRAMEWORKS[declaration.variant],
112
+ ...declaration.root ? { root: true } : {},
113
+ ...spec.config ? { config: spec.config } : {}
114
+ } : {},
115
+ ...declaration.kind === "mobile-app" ? {
116
+ framework: configured?.framework ?? declaration.variant,
117
+ ...spec.config ? { config: spec.config } : {}
118
+ } : {},
119
+ ...spec.telescope !== void 0 ? { telescope: spec.telescope } : {},
120
+ ...spec.openapi !== void 0 ? { openapi: spec.openapi } : {},
121
+ ...spec.runtime !== void 0 ? { runtime: spec.runtime } : {},
122
+ ...spec.env !== void 0 ? { env: spec.env } : {},
123
+ ...spec.entry !== void 0 ? { entry: spec.entry } : {},
124
+ ...configured?.domain ? { domain: configured.domain } : {}
125
+ };
126
+ }
127
+ for (const [id, declaration] of Object.entries(manifest)) {
128
+ if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
129
+ const app = apps[appKey(id)];
130
+ if (!app) continue;
131
+ const edges = declaration.kind === "rest-api" ? declaration.calls ?? [] : declaration.dependencies ?? [];
132
+ const names = /* @__PURE__ */ new Set();
133
+ for (const edge of edges) {
134
+ if (edge.kind !== "rest-api") continue;
135
+ const host = hostOf(manifest, edge.target);
136
+ if (!host) continue;
137
+ const key = appKey(host);
138
+ if (key !== appKey(id) && apps[key]) names.add(key);
139
+ }
140
+ app.dependencies = [...names].sort();
141
+ }
142
+ markRoot(apps);
143
+ assignPorts(apps);
144
+ for (const [name, app] of Object.entries(workspace.apps)) if (!apps[name]) apps[name] = app;
145
+ return apps;
146
+ }
147
+ //#endregion
148
+ export { derivedApps as n, appKey as t };
149
+
150
+ //# sourceMappingURL=derive-B4vDpzgP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-B4vDpzgP.mjs","names":[],"sources":["../src/workspace/derive.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"],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ let _geekmidas_manifest = require("@geekmidas/manifest");
2
+ //#region src/workspace/derive.ts
3
+ /**
4
+ * The apps a manifest implies.
5
+ *
6
+ * `gkm.config.ts` used to carry an `apps` block naming every app: its type, its
7
+ * path, its port, its framework, which other apps it depended on. Every one of
8
+ * those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`
9
+ * and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',
10
+ * dependencies: ['api'] }` are the same statement written twice, and only one of
11
+ * them was checked against anything — so the copy in config was free to drift,
12
+ * and a surface config had no entry for simply never deployed.
13
+ *
14
+ * So the list comes from the graph. A `site` is an app, and so is every
15
+ * `rest-api` — one surface, one container, at the `path` it declared.
16
+ *
17
+ * What config still supplies is what no graph can answer: the backends a cache
18
+ * and a mailer resolve to, the deploy endpoint, the stage's domain.
19
+ */
20
+ /** Which frontend framework builds each site variant. */
21
+ const FRAMEWORKS = {
22
+ static: "vite",
23
+ next: "nextjs",
24
+ tanstack: "tanstack-start"
25
+ };
26
+ /**
27
+ * The app key a construct id becomes.
28
+ *
29
+ * The same kebab form every physical name is built from, so `Api` is `api` in
30
+ * the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an
31
+ * environment — one id, three renderings, no second list.
32
+ */
33
+ function appKey(id) {
34
+ return (0, _geekmidas_manifest.kebabCase)(id);
35
+ }
36
+ /**
37
+ * The app serving a surface: its own, always.
38
+ *
39
+ * Every surface gets a container. There is no arrangement in which one runs
40
+ * inside another — two surfaces in a process share a filesystem, an
41
+ * environment, and every credential either was granted, so an auth server
42
+ * beside an API is one bug in the API away from being read by it.
43
+ */
44
+ function hostOf(manifest, id) {
45
+ const declaration = manifest[id];
46
+ if (!declaration || declaration.kind !== "rest-api") return void 0;
47
+ return id;
48
+ }
49
+ /**
50
+ * Local ports, assigned so that adding a site does not renumber the others.
51
+ *
52
+ * Backends first, then the site holding the base domain, then the rest
53
+ * alphabetically. The ordering is arbitrary but it is *fixed*, which is the
54
+ * property that matters: a port that moves when an unrelated app is added is a
55
+ * port nobody can put in a bookmark. A construct that names its own port keeps
56
+ * it, and is skipped here.
57
+ */
58
+ function assignPorts(apps) {
59
+ const rank = (name, app) => [
60
+ app.type === "backend" ? 0 : app.type === "web" ? 1 : 2,
61
+ app.root ? 0 : 1,
62
+ name
63
+ ];
64
+ const ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {
65
+ const [at, ar, an] = rank(aName, a);
66
+ const [bt, br, bn] = rank(bName, b);
67
+ return at - bt || ar - br || an.localeCompare(bn);
68
+ });
69
+ const taken = new Set(ordered.map(([, app]) => app.port).filter((p) => !!p));
70
+ let next = 3e3;
71
+ for (const [, app] of ordered) {
72
+ if (app.port) continue;
73
+ while (taken.has(next)) next += 1;
74
+ app.port = next;
75
+ taken.add(next);
76
+ }
77
+ }
78
+ /**
79
+ * Whichever site holds the base domain.
80
+ *
81
+ * The convention first — a site named `web` — because it is one people already
82
+ * rely on. Then an explicit `root: true`. A project with one site needs neither.
83
+ */
84
+ function markRoot(apps) {
85
+ const sites = Object.entries(apps).filter(([, a]) => a.type === "web");
86
+ if (sites.length === 0) return;
87
+ if (sites.some(([, a]) => a.root)) return;
88
+ const chosen = sites.find(([name]) => name === "web") ?? (sites.length === 1 ? sites[0] : void 0);
89
+ if (chosen) chosen[1].root = true;
90
+ }
91
+ function derivedApps(manifest, workspace) {
92
+ const apps = {};
93
+ const defaultTarget = workspace.deploy?.default ?? "dokploy";
94
+ for (const [id, declaration] of Object.entries(manifest)) {
95
+ if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
96
+ const spec = declaration.kind === "site" || declaration.kind === "mobile-app" ? declaration.app : {
97
+ path: declaration.path,
98
+ ...declaration.telescope ? { telescope: true } : {}
99
+ };
100
+ const name = appKey(id);
101
+ const configured = workspace.apps[name];
102
+ apps[name] = {
103
+ ...configured,
104
+ type: declaration.kind === "site" ? "web" : declaration.kind === "mobile-app" ? "mobile" : "backend",
105
+ path: spec.path,
106
+ port: spec.port ?? configured?.port ?? 0,
107
+ ...(declaration.kind === "rest-api" || declaration.kind === "site") && declaration.subdomain ? { subdomain: declaration.subdomain } : {},
108
+ dependencies: [],
109
+ resolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,
110
+ ...declaration.kind === "site" ? {
111
+ framework: configured?.framework ?? FRAMEWORKS[declaration.variant],
112
+ ...declaration.root ? { root: true } : {},
113
+ ...spec.config ? { config: spec.config } : {}
114
+ } : {},
115
+ ...declaration.kind === "mobile-app" ? {
116
+ framework: configured?.framework ?? declaration.variant,
117
+ ...spec.config ? { config: spec.config } : {}
118
+ } : {},
119
+ ...spec.telescope !== void 0 ? { telescope: spec.telescope } : {},
120
+ ...spec.openapi !== void 0 ? { openapi: spec.openapi } : {},
121
+ ...spec.runtime !== void 0 ? { runtime: spec.runtime } : {},
122
+ ...spec.env !== void 0 ? { env: spec.env } : {},
123
+ ...spec.entry !== void 0 ? { entry: spec.entry } : {},
124
+ ...configured?.domain ? { domain: configured.domain } : {}
125
+ };
126
+ }
127
+ for (const [id, declaration] of Object.entries(manifest)) {
128
+ if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
129
+ const app = apps[appKey(id)];
130
+ if (!app) continue;
131
+ const edges = declaration.kind === "rest-api" ? declaration.calls ?? [] : declaration.dependencies ?? [];
132
+ const names = /* @__PURE__ */ new Set();
133
+ for (const edge of edges) {
134
+ if (edge.kind !== "rest-api") continue;
135
+ const host = hostOf(manifest, edge.target);
136
+ if (!host) continue;
137
+ const key = appKey(host);
138
+ if (key !== appKey(id) && apps[key]) names.add(key);
139
+ }
140
+ app.dependencies = [...names].sort();
141
+ }
142
+ markRoot(apps);
143
+ assignPorts(apps);
144
+ for (const [name, app] of Object.entries(workspace.apps)) if (!apps[name]) apps[name] = app;
145
+ return apps;
146
+ }
147
+ //#endregion
148
+ Object.defineProperty(exports, "appKey", {
149
+ enumerable: true,
150
+ get: function() {
151
+ return appKey;
152
+ }
153
+ });
154
+ Object.defineProperty(exports, "derivedApps", {
155
+ enumerable: true,
156
+ get: function() {
157
+ return derivedApps;
158
+ }
159
+ });
160
+
161
+ //# sourceMappingURL=derive-DAbo49sm.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-DAbo49sm.cjs","names":["kebabCase"],"sources":["../src/workspace/derive.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"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
2
  const require_schemas = require("./schemas-Ckm_aBnF.cjs");
3
+ const require_sandbox = require("./sandbox-CL--ZDui.cjs");
3
4
  const require_workerRuntime = require("./workerRuntime-BXfhbe13.cjs");
4
5
  let node_path = require("node:path");
5
6
  let node_fs = require("node:fs");
@@ -102,117 +103,6 @@ var ConstructGenerator = class {
102
103
  }
103
104
  };
104
105
  //#endregion
105
- //#region src/sandbox/sandbox.ts
106
- /**
107
- * Where a deploy runs the project's own code.
108
- *
109
- * A deploy holds credentials — Dokploy's token, a registry login, an AWS key —
110
- * and loading `gkm.config.ts`, sniffing an app's environment and building it
111
- * all execute code from the repository being deployed. On a developer's own
112
- * laptop that is the developer's code. On a CI job for a fork, or a shared
113
- * build runner, it is not, and that code should not be able to read the
114
- * credentials used to deploy it, hang the deploy, or reach outside the
115
- * checkout.
116
- *
117
- * So every step that runs project code goes through a `Sandbox`: one call,
118
- * with an argument array rather than a shell line, the complete environment
119
- * the step needs rather than the host's, a timeout it cannot outlive, secrets
120
- * as files rather than variables, and a working directory inside the project.
121
- * The steps that need credentials — provisioning, pushing, releasing — are
122
- * the deploy's own code and never run in one.
123
- *
124
- * `LocalSandbox` is the default: a child process on this machine with an
125
- * allowlisted environment. A host that builds repositories it does not trust
126
- * passes its own — a container per build, a VM — through `deploy()`'s
127
- * `sandbox`.
128
- */
129
- /** The variable naming the directory a command's secrets are mounted in. */
130
- const SECRETS_DIR_ENV = "GKM_SECRETS_DIR";
131
- /** A command was asked to run outside the project. */
132
- var SandboxCwdEscape = class extends Error {
133
- cwd;
134
- root;
135
- constructor(cwd, root) {
136
- super(`Refusing to run in '${cwd}': it is outside the project at '${root}'. A sandboxed step only runs inside the project it was given — check the app paths in gkm.config.ts for \`..\` or an absolute path.`);
137
- this.cwd = cwd;
138
- this.root = root;
139
- this.name = "SandboxCwdEscape";
140
- }
141
- };
142
- /** A path with its symlinks resolved where it exists — `/tmp` is `/private/tmp`. */
143
- function real(path) {
144
- return (0, node_fs.existsSync)(path) ? (0, node_fs.realpathSync)(path) : path;
145
- }
146
- /**
147
- * `cwd` as an absolute directory inside `root`, or {@link SandboxCwdEscape}.
148
- *
149
- * Symlinks are resolved on both sides first, so a link inside the project
150
- * that points out of it is an escape, and a project reached through a link
151
- * (`/tmp` on macOS) is still itself. For a sandbox of a host's own to call
152
- * before it runs anything.
153
- */
154
- function confineCwd(root, cwd) {
155
- const absolute = (0, node_path.resolve)(root, cwd);
156
- const from = (0, node_path.relative)(real((0, node_path.resolve)(root)), real(absolute));
157
- if (from === ".." || from.startsWith(`..${node_path.sep}`) || (0, node_path.isAbsolute)(from)) throw new SandboxCwdEscape(cwd, root);
158
- return absolute;
159
- }
160
- /** A secret's file name: one path segment, so it cannot be written elsewhere. */
161
- var SecretNameInvalid = class extends Error {
162
- secretName;
163
- constructor(secretName) {
164
- super(`'${secretName}' cannot be a secret's name: it becomes a file name in the secrets directory, so it must be one segment of letters, digits, '.', '-' or '_' and not start with '.'.`);
165
- this.secretName = secretName;
166
- this.name = "SecretNameInvalid";
167
- }
168
- };
169
- const SECRET_NAME = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
170
- /** Every secret name, checked before anything is written. */
171
- function assertSecretNames(secrets) {
172
- for (const name of Object.keys(secrets ?? {})) if (!SECRET_NAME.test(name)) throw new SecretNameInvalid(name);
173
- }
174
- const active = new node_async_hooks.AsyncLocalStorage();
175
- /**
176
- * Run `fn` with `sandbox` as the one its steps use.
177
- *
178
- * Per run rather than global, as `withOutput` routes a run's lines: two
179
- * deploys in one host process each build in their own sandbox. A step deep in
180
- * the engine — discovering constructs, sniffing an app — asks
181
- * {@link activeSandbox} rather than every function between `deploy()` and it
182
- * taking one more parameter.
183
- */
184
- function withSandbox(sandbox, fn) {
185
- return active.run({
186
- sandbox,
187
- answers: /* @__PURE__ */ new Map()
188
- }, fn);
189
- }
190
- /** The sandbox of the run this is part of, if it was started with one. */
191
- function activeSandbox() {
192
- return active.getStore()?.sandbox;
193
- }
194
- /**
195
- * `ask()`'s answer, asked once per run.
196
- *
197
- * A deploy loads its config and discovers its constructs from several places
198
- * — the first load, the engine, the Dockerfile generator — and in a sandbox
199
- * each was a child process of its own, for the same answer: the checkout does
200
- * not change while it deploys. Within a run in `sandbox`, the first answer
201
- * for `key` is the one every later ask gets. Outside one, or for another
202
- * sandbox, `ask()` runs each time.
203
- */
204
- function oncePerRun(sandbox, key, ask) {
205
- const run = active.getStore();
206
- if (!run || run.sandbox !== sandbox) return ask();
207
- let answer = run.answers.get(key);
208
- if (!answer) {
209
- answer = ask();
210
- run.answers.set(key, answer);
211
- answer.catch(() => run.answers.delete(key));
212
- }
213
- return answer;
214
- }
215
- //#endregion
216
106
  //#region src/owningTsconfigJsx.ts
217
107
  const REGISTER = "owning-tsconfig-jsx-register.mjs";
218
108
  /** The CLI's `bin/` was not found above the module looking for it. */
@@ -319,12 +209,13 @@ var SandboxWorkerFailed = class extends Error {
319
209
  * though it had run again.
320
210
  */
321
211
  async function runWorker(sandbox, step, options) {
322
- const answer = await oncePerRun(sandbox, JSON.stringify([
212
+ const key = JSON.stringify([
323
213
  options.name,
324
214
  options.cwd,
325
215
  options.args,
326
216
  options.env ?? {}
327
- ]), () => startWorker(sandbox, step, options));
217
+ ]);
218
+ const answer = await require_sandbox.oncePerRun(sandbox, key, () => startWorker(sandbox, step, options));
328
219
  return structuredClone(answer);
329
220
  }
330
221
  async function startWorker(sandbox, step, options) {
@@ -486,7 +377,7 @@ var ConstructsNotSerializable = class extends Error {
486
377
  * @throws {DuplicateConstruct} when two exports claim one id.
487
378
  */
488
379
  async function discover(options) {
489
- const sandbox = options.sandbox ?? activeSandbox();
380
+ const sandbox = options.sandbox ?? require_sandbox.activeSandbox();
490
381
  if (sandbox) {
491
382
  if (!options.sources && !options.bustCache) {
492
383
  const sandboxed = await discoverInSandbox(sandbox, options);
@@ -629,48 +520,12 @@ Object.defineProperty(exports, "ConstructsNotSerializable", {
629
520
  return ConstructsNotSerializable;
630
521
  }
631
522
  });
632
- Object.defineProperty(exports, "SECRETS_DIR_ENV", {
633
- enumerable: true,
634
- get: function() {
635
- return SECRETS_DIR_ENV;
636
- }
637
- });
638
- Object.defineProperty(exports, "SandboxCwdEscape", {
639
- enumerable: true,
640
- get: function() {
641
- return SandboxCwdEscape;
642
- }
643
- });
644
523
  Object.defineProperty(exports, "SandboxWorkerFailed", {
645
524
  enumerable: true,
646
525
  get: function() {
647
526
  return SandboxWorkerFailed;
648
527
  }
649
528
  });
650
- Object.defineProperty(exports, "SecretNameInvalid", {
651
- enumerable: true,
652
- get: function() {
653
- return SecretNameInvalid;
654
- }
655
- });
656
- Object.defineProperty(exports, "activeSandbox", {
657
- enumerable: true,
658
- get: function() {
659
- return activeSandbox;
660
- }
661
- });
662
- Object.defineProperty(exports, "assertSecretNames", {
663
- enumerable: true,
664
- get: function() {
665
- return assertSecretNames;
666
- }
667
- });
668
- Object.defineProperty(exports, "confineCwd", {
669
- enumerable: true,
670
- get: function() {
671
- return confineCwd;
672
- }
673
- });
674
529
  Object.defineProperty(exports, "discover", {
675
530
  enumerable: true,
676
531
  get: function() {
@@ -719,11 +574,5 @@ Object.defineProperty(exports, "withOwningTsconfigJsx", {
719
574
  return withOwningTsconfigJsx;
720
575
  }
721
576
  });
722
- Object.defineProperty(exports, "withSandbox", {
723
- enumerable: true,
724
- get: function() {
725
- return withSandbox;
726
- }
727
- });
728
577
 
729
- //# sourceMappingURL=discover-C_6COHEv.cjs.map
578
+ //# sourceMappingURL=discover-DHdECueV.cjs.map