@geekmidas/cli 10.0.0-alpha.10 → 10.0.0-alpha.100

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 (489) hide show
  1. package/README.md +315 -414
  2. package/bin/adjacent-tsconfig.mjs +46 -8
  3. package/bin/gkm.mjs +11 -3
  4. package/bin/owning-tsconfig-jsx-register.mjs +18 -0
  5. package/bin/owning-tsconfig-jsx.mjs +108 -0
  6. package/dist/EndpointGenerator-Br97xgs_.mjs +1031 -0
  7. package/dist/EndpointGenerator-Br97xgs_.mjs.map +1 -0
  8. package/dist/EndpointGenerator-By5_tYE9.cjs +1090 -0
  9. package/dist/EndpointGenerator-By5_tYE9.cjs.map +1 -0
  10. package/dist/GoDaddyProvider-CVnzcWX5.mjs +388 -0
  11. package/dist/GoDaddyProvider-CVnzcWX5.mjs.map +1 -0
  12. package/dist/GoDaddyProvider-DS4Wgu0c.cjs +388 -0
  13. package/dist/GoDaddyProvider-DS4Wgu0c.cjs.map +1 -0
  14. package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-BNpS9aRJ.mjs} +29 -25
  15. package/dist/HostingerProvider-BNpS9aRJ.mjs.map +1 -0
  16. package/dist/{HostingerProvider-h3EbEp-Z.cjs → HostingerProvider-DR1iws1P.cjs} +29 -25
  17. package/dist/HostingerProvider-DR1iws1P.cjs.map +1 -0
  18. package/dist/LegacyStateStore-C2Xlqy4v.mjs +124 -0
  19. package/dist/LegacyStateStore-C2Xlqy4v.mjs.map +1 -0
  20. package/dist/LegacyStateStore-CoHPQMLO.cjs +124 -0
  21. package/dist/LegacyStateStore-CoHPQMLO.cjs.map +1 -0
  22. package/dist/LocalStateStore-BGDzf2f8.cjs +178 -0
  23. package/dist/LocalStateStore-BGDzf2f8.cjs.map +1 -0
  24. package/dist/LocalStateStore-By59pUve.mjs +167 -0
  25. package/dist/LocalStateStore-By59pUve.mjs.map +1 -0
  26. package/dist/OpenApiTsGenerator-BgSX_Z-e.cjs +541 -0
  27. package/dist/OpenApiTsGenerator-BgSX_Z-e.cjs.map +1 -0
  28. package/dist/OpenApiTsGenerator-C8aTX--y.mjs +536 -0
  29. package/dist/OpenApiTsGenerator-C8aTX--y.mjs.map +1 -0
  30. package/dist/{Route53Provider-di2fMM5N.cjs → Route53Provider-Bllus2NR.cjs} +21 -22
  31. package/dist/Route53Provider-Bllus2NR.cjs.map +1 -0
  32. package/dist/{Route53Provider-RdpUDJQk.mjs → Route53Provider-QXxjkZO1.mjs} +13 -13
  33. package/dist/Route53Provider-QXxjkZO1.mjs.map +1 -0
  34. package/dist/S3StateStore-CU485pYn.mjs +223 -0
  35. package/dist/S3StateStore-CU485pYn.mjs.map +1 -0
  36. package/dist/S3StateStore-Re4LfDTl.cjs +222 -0
  37. package/dist/S3StateStore-Re4LfDTl.cjs.map +1 -0
  38. package/dist/SSMStateStore-BquRBbUG.mjs +205 -0
  39. package/dist/SSMStateStore-BquRBbUG.mjs.map +1 -0
  40. package/dist/SSMStateStore-CLX4Dm5d.cjs +204 -0
  41. package/dist/SSMStateStore-CLX4Dm5d.cjs.map +1 -0
  42. package/dist/SubscriberGenerator-1-IsjIwF.mjs +449 -0
  43. package/dist/SubscriberGenerator-1-IsjIwF.mjs.map +1 -0
  44. package/dist/SubscriberGenerator-BlIOdbi-.cjs +490 -0
  45. package/dist/SubscriberGenerator-BlIOdbi-.cjs.map +1 -0
  46. package/dist/add-Blv6Q_YA.mjs +718 -0
  47. package/dist/add-Blv6Q_YA.mjs.map +1 -0
  48. package/dist/add-C6RhiCBX.cjs +720 -0
  49. package/dist/add-C6RhiCBX.cjs.map +1 -0
  50. package/dist/appPorts-C9z9Pzn9.mjs +223 -0
  51. package/dist/appPorts-C9z9Pzn9.mjs.map +1 -0
  52. package/dist/appPorts-Cu79hJF6.cjs +264 -0
  53. package/dist/appPorts-Cu79hJF6.cjs.map +1 -0
  54. package/dist/aws-8QQ8n-t6.mjs +89 -0
  55. package/dist/aws-8QQ8n-t6.mjs.map +1 -0
  56. package/dist/aws-DY9NqQIT.cjs +100 -0
  57. package/dist/aws-DY9NqQIT.cjs.map +1 -0
  58. package/dist/awsStore-Bx5nCFnS.mjs +121 -0
  59. package/dist/awsStore-Bx5nCFnS.mjs.map +1 -0
  60. package/dist/awsStore-u3ehhMoY.cjs +138 -0
  61. package/dist/awsStore-u3ehhMoY.cjs.map +1 -0
  62. package/dist/{backup-provisioner-Bgj5Vi_L.mjs → backup-provisioner-C8DnCmxK.mjs} +11 -8
  63. package/dist/backup-provisioner-C8DnCmxK.mjs.map +1 -0
  64. package/dist/{backup-provisioner-BrsHwYG0.cjs → backup-provisioner-oDEsPj02.cjs} +22 -20
  65. package/dist/backup-provisioner-oDEsPj02.cjs.map +1 -0
  66. package/dist/backups/runner.cjs +519 -0
  67. package/dist/backups/runner.cjs.map +1 -0
  68. package/dist/backups/runner.d.cts +102 -0
  69. package/dist/backups/runner.d.cts.map +1 -0
  70. package/dist/backups/runner.d.mts +102 -0
  71. package/dist/backups/runner.d.mts.map +1 -0
  72. package/dist/backups/runner.mjs +506 -0
  73. package/dist/backups/runner.mjs.map +1 -0
  74. package/dist/{bundler-Be8Zg4Wd.mjs → bundler-Cquc0e8N.mjs} +36 -32
  75. package/dist/bundler-Cquc0e8N.mjs.map +1 -0
  76. package/dist/{bundler-BY1OmV1e.cjs → bundler-DAeBIOlG.cjs} +38 -35
  77. package/dist/bundler-DAeBIOlG.cjs.map +1 -0
  78. package/dist/cli-DbeqYBTs.cjs +71 -0
  79. package/dist/cli-DbeqYBTs.cjs.map +1 -0
  80. package/dist/cli-tWfeiYmO.mjs +71 -0
  81. package/dist/cli-tWfeiYmO.mjs.map +1 -0
  82. package/dist/compose-BftbEv0b.mjs +3154 -0
  83. package/dist/compose-BftbEv0b.mjs.map +1 -0
  84. package/dist/compose-C_mfrSVH.cjs +3267 -0
  85. package/dist/compose-C_mfrSVH.cjs.map +1 -0
  86. package/dist/config-D48erO2j.d.mts +269 -0
  87. package/dist/config-D48erO2j.d.mts.map +1 -0
  88. package/dist/config-DHDtsQrB.d.cts +269 -0
  89. package/dist/config-DHDtsQrB.d.cts.map +1 -0
  90. package/dist/config.cjs +421 -11
  91. package/dist/config.cjs.map +1 -0
  92. package/dist/config.d.cts +4 -120
  93. package/dist/config.d.mts +4 -120
  94. package/dist/config.mjs +405 -4
  95. package/dist/config.mjs.map +1 -0
  96. package/dist/credentialSchemas-DDda4Mmm.cjs +272 -0
  97. package/dist/credentialSchemas-DDda4Mmm.cjs.map +1 -0
  98. package/dist/credentialSchemas-DvitraL-.mjs +237 -0
  99. package/dist/credentialSchemas-DvitraL-.mjs.map +1 -0
  100. package/dist/credentials-B5N5yKk6.mjs +267 -0
  101. package/dist/credentials-B5N5yKk6.mjs.map +1 -0
  102. package/dist/credentials-Zqr3QQYB.cjs +350 -0
  103. package/dist/credentials-Zqr3QQYB.cjs.map +1 -0
  104. package/dist/databases-BeGP5eDh.mjs +495 -0
  105. package/dist/databases-BeGP5eDh.mjs.map +1 -0
  106. package/dist/databases-DGALFDG3.cjs +598 -0
  107. package/dist/databases-DGALFDG3.cjs.map +1 -0
  108. package/dist/define-6poNqm5O.mjs +106 -0
  109. package/dist/define-6poNqm5O.mjs.map +1 -0
  110. package/dist/define-crmMcXFS.cjs +153 -0
  111. package/dist/define-crmMcXFS.cjs.map +1 -0
  112. package/dist/deploy/public.cjs +212 -0
  113. package/dist/deploy/public.cjs.map +1 -0
  114. package/dist/deploy/public.d.cts +653 -0
  115. package/dist/deploy/public.d.cts.map +1 -0
  116. package/dist/deploy/public.d.mts +653 -0
  117. package/dist/deploy/public.d.mts.map +1 -0
  118. package/dist/deploy/public.mjs +145 -0
  119. package/dist/deploy/public.mjs.map +1 -0
  120. package/dist/deploy/sniffer-envkit-patch.cjs +18 -10
  121. package/dist/deploy/sniffer-envkit-patch.cjs.map +1 -1
  122. package/dist/deploy/sniffer-envkit-patch.d.cts +0 -2
  123. package/dist/deploy/sniffer-envkit-patch.d.cts.map +1 -1
  124. package/dist/deploy/sniffer-envkit-patch.d.mts +0 -2
  125. package/dist/deploy/sniffer-envkit-patch.d.mts.map +1 -1
  126. package/dist/deploy/sniffer-envkit-patch.mjs +10 -2
  127. package/dist/deploy/sniffer-envkit-patch.mjs.map +1 -1
  128. package/dist/deploy/sniffer-envparser-worker.cjs +54 -0
  129. package/dist/deploy/sniffer-envparser-worker.cjs.map +1 -0
  130. package/dist/deploy/sniffer-envparser-worker.d.cts +1 -0
  131. package/dist/deploy/sniffer-envparser-worker.d.mts +1 -0
  132. package/dist/deploy/sniffer-envparser-worker.mjs +55 -0
  133. package/dist/deploy/sniffer-envparser-worker.mjs.map +1 -0
  134. package/dist/deploy/sniffer-hooks.cjs +13 -7
  135. package/dist/deploy/sniffer-hooks.cjs.map +1 -1
  136. package/dist/deploy/sniffer-hooks.d.cts +1 -2
  137. package/dist/deploy/sniffer-hooks.d.cts.map +1 -1
  138. package/dist/deploy/sniffer-hooks.d.mts +1 -2
  139. package/dist/deploy/sniffer-hooks.d.mts.map +1 -1
  140. package/dist/deploy/sniffer-hooks.mjs +10 -3
  141. package/dist/deploy/sniffer-hooks.mjs.map +1 -1
  142. package/dist/deploy/sniffer-loader.cjs +16 -7
  143. package/dist/deploy/sniffer-loader.cjs.map +1 -1
  144. package/dist/deploy/sniffer-loader.d.cts +1 -1
  145. package/dist/deploy/sniffer-loader.d.mts +1 -1
  146. package/dist/deploy/sniffer-loader.mjs +14 -3
  147. package/dist/deploy/sniffer-loader.mjs.map +1 -1
  148. package/dist/deploy/sniffer-routes-worker.cjs +11 -11
  149. package/dist/deploy/sniffer-routes-worker.cjs.map +1 -1
  150. package/dist/deploy/sniffer-routes-worker.d.cts +1 -1
  151. package/dist/deploy/sniffer-routes-worker.d.mts +1 -1
  152. package/dist/deploy/sniffer-routes-worker.mjs +4 -4
  153. package/dist/deploy/sniffer-routes-worker.mjs.map +1 -1
  154. package/dist/deploy/sniffer-worker.cjs +15 -6
  155. package/dist/deploy/sniffer-worker.cjs.map +1 -1
  156. package/dist/deploy/sniffer-worker.d.cts +1 -3
  157. package/dist/deploy/sniffer-worker.d.cts.map +1 -1
  158. package/dist/deploy/sniffer-worker.d.mts +1 -3
  159. package/dist/deploy/sniffer-worker.d.mts.map +1 -1
  160. package/dist/deploy/sniffer-worker.mjs +15 -4
  161. package/dist/deploy/sniffer-worker.mjs.map +1 -1
  162. package/dist/deploy-BSilGXuR.mjs +2317 -0
  163. package/dist/deploy-BSilGXuR.mjs.map +1 -0
  164. package/dist/deploy-CktQpmpU.cjs +2390 -0
  165. package/dist/deploy-CktQpmpU.cjs.map +1 -0
  166. package/dist/derive-B4vDpzgP.mjs +150 -0
  167. package/dist/derive-B4vDpzgP.mjs.map +1 -0
  168. package/dist/derive-DAbo49sm.cjs +161 -0
  169. package/dist/derive-DAbo49sm.cjs.map +1 -0
  170. package/dist/discover-BfhVW_kT.cjs +600 -0
  171. package/dist/discover-BfhVW_kT.cjs.map +1 -0
  172. package/dist/discover-CvTtV5ZD.d.cts +108 -0
  173. package/dist/discover-CvTtV5ZD.d.cts.map +1 -0
  174. package/dist/discover-W2kab9Lc.d.mts +108 -0
  175. package/dist/discover-W2kab9Lc.d.mts.map +1 -0
  176. package/dist/discover-kziEht4W.mjs +527 -0
  177. package/dist/discover-kziEht4W.mjs.map +1 -0
  178. package/dist/dns-CQZQL3gj.mjs +926 -0
  179. package/dist/dns-CQZQL3gj.mjs.map +1 -0
  180. package/dist/dns-KPxvcCdL.cjs +1057 -0
  181. package/dist/dns-KPxvcCdL.cjs.map +1 -0
  182. package/dist/dokploy-B7eMa6Pa.cjs +38 -0
  183. package/dist/dokploy-B7eMa6Pa.cjs.map +1 -0
  184. package/dist/dokploy-Dguhz3Uo.mjs +38 -0
  185. package/dist/dokploy-Dguhz3Uo.mjs.map +1 -0
  186. package/dist/drivers-BLU1fNs_.cjs +200 -0
  187. package/dist/drivers-BLU1fNs_.cjs.map +1 -0
  188. package/dist/drivers-C08LL4E8.mjs +177 -0
  189. package/dist/drivers-C08LL4E8.mjs.map +1 -0
  190. package/dist/{emit-CiZS_5Ub.mjs → emit-C1e8qD08.mjs} +13 -26
  191. package/dist/emit-C1e8qD08.mjs.map +1 -0
  192. package/dist/{emit-CbcRolsa.cjs → emit-Dmc1nvdS.cjs} +31 -57
  193. package/dist/emit-Dmc1nvdS.cjs.map +1 -0
  194. package/dist/encryption-CixpDF6e.mjs +89 -0
  195. package/dist/encryption-CixpDF6e.mjs.map +1 -0
  196. package/dist/encryption-DrhCX7G6.cjs +90 -0
  197. package/dist/encryption-DrhCX7G6.cjs.map +1 -0
  198. package/dist/engine-32gL2ju3.mjs +3082 -0
  199. package/dist/engine-32gL2ju3.mjs.map +1 -0
  200. package/dist/engine-CQgycl7o.cjs +3195 -0
  201. package/dist/engine-CQgycl7o.cjs.map +1 -0
  202. package/dist/errors-D8Gwp5kU.mjs +23 -0
  203. package/dist/errors-D8Gwp5kU.mjs.map +1 -0
  204. package/dist/errors-DMC4Umsb.cjs +34 -0
  205. package/dist/errors-DMC4Umsb.cjs.map +1 -0
  206. package/dist/github-DYQ5wvod.mjs +829 -0
  207. package/dist/github-DYQ5wvod.mjs.map +1 -0
  208. package/dist/github-DkSCUoWS.cjs +829 -0
  209. package/dist/github-DkSCUoWS.cjs.map +1 -0
  210. package/dist/identity-CBXr4wNi.mjs +129 -0
  211. package/dist/identity-CBXr4wNi.mjs.map +1 -0
  212. package/dist/identity-CbLfgQNT.cjs +182 -0
  213. package/dist/identity-CbLfgQNT.cjs.map +1 -0
  214. package/dist/{index-C6e-ULLx.d.mts → index-8OfpOtSI.d.cts} +39 -24
  215. package/dist/index-8OfpOtSI.d.cts.map +1 -0
  216. package/dist/{index-CR5urhWX.d.cts → index-Dpji6Bxq.d.mts} +39 -24
  217. package/dist/index-Dpji6Bxq.d.mts.map +1 -0
  218. package/dist/index.cjs +10022 -12718
  219. package/dist/index.cjs.map +1 -1
  220. package/dist/index.d.cts +1 -1
  221. package/dist/index.d.mts +1 -1
  222. package/dist/index.mjs +10648 -13356
  223. package/dist/index.mjs.map +1 -1
  224. package/dist/local-BwC2v2Y8.mjs +224 -0
  225. package/dist/local-BwC2v2Y8.mjs.map +1 -0
  226. package/dist/local-DNhnkugT.cjs +241 -0
  227. package/dist/local-DNhnkugT.cjs.map +1 -0
  228. package/dist/migrate-BoJxKbfR.mjs +181 -0
  229. package/dist/migrate-BoJxKbfR.mjs.map +1 -0
  230. package/dist/migrate-CJTyeBul.cjs +271 -0
  231. package/dist/migrate-CJTyeBul.cjs.map +1 -0
  232. package/dist/migrate-CxmkvMbw.mjs +266 -0
  233. package/dist/migrate-CxmkvMbw.mjs.map +1 -0
  234. package/dist/migrate-ISBZNDKU.cjs +181 -0
  235. package/dist/migrate-ISBZNDKU.cjs.map +1 -0
  236. package/dist/openapi.cjs +214 -10
  237. package/dist/openapi.cjs.map +1 -0
  238. package/dist/openapi.d.cts +38 -17
  239. package/dist/openapi.d.cts.map +1 -1
  240. package/dist/openapi.d.mts +38 -17
  241. package/dist/openapi.d.mts.map +1 -1
  242. package/dist/openapi.mjs +208 -5
  243. package/dist/openapi.mjs.map +1 -0
  244. package/dist/projectBucket-BBbQ1lHF.cjs +263 -0
  245. package/dist/projectBucket-BBbQ1lHF.cjs.map +1 -0
  246. package/dist/projectBucket-C_DN4WzF.mjs +222 -0
  247. package/dist/projectBucket-C_DN4WzF.mjs.map +1 -0
  248. package/dist/provider-BqpjG9QM.cjs +57 -0
  249. package/dist/provider-BqpjG9QM.cjs.map +1 -0
  250. package/dist/provider-CEOKk8NS.mjs +46 -0
  251. package/dist/provider-CEOKk8NS.mjs.map +1 -0
  252. package/dist/ready-BtxiI7Qb.cjs +403 -0
  253. package/dist/ready-BtxiI7Qb.cjs.map +1 -0
  254. package/dist/ready-CzHNHhI6.mjs +374 -0
  255. package/dist/ready-CzHNHhI6.mjs.map +1 -0
  256. package/dist/reconcile/public.cjs +3 -5
  257. package/dist/reconcile/public.d.cts +11 -87
  258. package/dist/reconcile/public.d.cts.map +1 -1
  259. package/dist/reconcile/public.d.mts +11 -87
  260. package/dist/reconcile/public.d.mts.map +1 -1
  261. package/dist/reconcile/public.mjs +3 -4
  262. package/dist/{reconcile-CFs8C_1a.mjs → reconcile--I7V4Klj.mjs} +4 -7
  263. package/dist/reconcile--I7V4Klj.mjs.map +1 -0
  264. package/dist/{reconcile-D0pimNiy.cjs → reconcile-CuCQBa5-.cjs} +5 -8
  265. package/dist/reconcile-CuCQBa5-.cjs.map +1 -0
  266. package/dist/resolve-Bei6BMbw.mjs +263 -0
  267. package/dist/resolve-Bei6BMbw.mjs.map +1 -0
  268. package/dist/resolve-qm7FrBj_.cjs +316 -0
  269. package/dist/resolve-qm7FrBj_.cjs.map +1 -0
  270. package/dist/rollback-BJ3H4kQ8.mjs +136 -0
  271. package/dist/rollback-BJ3H4kQ8.mjs.map +1 -0
  272. package/dist/rollback-Bt4xRXtq.cjs +165 -0
  273. package/dist/rollback-Bt4xRXtq.cjs.map +1 -0
  274. package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
  275. package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-C0BPl7ul.cjs} +23 -10
  276. package/dist/run-BJLIerMM.mjs +133 -0
  277. package/dist/run-BJLIerMM.mjs.map +1 -0
  278. package/dist/run-fVZ-rLnc.cjs +174 -0
  279. package/dist/run-fVZ-rLnc.cjs.map +1 -0
  280. package/dist/runtime-ACdfK59n.d.cts +82 -0
  281. package/dist/runtime-ACdfK59n.d.cts.map +1 -0
  282. package/dist/runtime-YyQuekxi.d.mts +82 -0
  283. package/dist/runtime-YyQuekxi.d.mts.map +1 -0
  284. package/dist/s3-CrPoA89T.cjs +215 -0
  285. package/dist/s3-CrPoA89T.cjs.map +1 -0
  286. package/dist/s3-DQXZdmCM.mjs +215 -0
  287. package/dist/s3-DQXZdmCM.mjs.map +1 -0
  288. package/dist/sandbox/config-worker.cjs +43 -0
  289. package/dist/sandbox/config-worker.cjs.map +1 -0
  290. package/dist/sandbox/config-worker.d.cts +1 -0
  291. package/dist/sandbox/config-worker.d.mts +1 -0
  292. package/dist/sandbox/config-worker.mjs +44 -0
  293. package/dist/sandbox/config-worker.mjs.map +1 -0
  294. package/dist/sandbox/credentials-worker.cjs +54 -0
  295. package/dist/sandbox/credentials-worker.cjs.map +1 -0
  296. package/dist/sandbox/credentials-worker.d.cts +1 -0
  297. package/dist/sandbox/credentials-worker.d.mts +1 -0
  298. package/dist/sandbox/credentials-worker.mjs +55 -0
  299. package/dist/sandbox/credentials-worker.mjs.map +1 -0
  300. package/dist/sandbox/discover-worker.cjs +47 -0
  301. package/dist/sandbox/discover-worker.cjs.map +1 -0
  302. package/dist/sandbox/discover-worker.d.cts +1 -0
  303. package/dist/sandbox/discover-worker.d.mts +1 -0
  304. package/dist/sandbox/discover-worker.mjs +48 -0
  305. package/dist/sandbox/discover-worker.mjs.map +1 -0
  306. package/dist/sandbox/migrate-worker.cjs +75 -0
  307. package/dist/sandbox/migrate-worker.cjs.map +1 -0
  308. package/dist/sandbox/migrate-worker.d.cts +1 -0
  309. package/dist/sandbox/migrate-worker.d.mts +1 -0
  310. package/dist/sandbox/migrate-worker.mjs +76 -0
  311. package/dist/sandbox/migrate-worker.mjs.map +1 -0
  312. package/dist/sandbox-C4g1eG31.d.mts +104 -0
  313. package/dist/sandbox-C4g1eG31.d.mts.map +1 -0
  314. package/dist/sandbox-CHv3OYXg.cjs +165 -0
  315. package/dist/sandbox-CHv3OYXg.cjs.map +1 -0
  316. package/dist/sandbox-CbVB7uOD.mjs +118 -0
  317. package/dist/sandbox-CbVB7uOD.mjs.map +1 -0
  318. package/dist/sandbox-CdKgQ3XU.d.cts +104 -0
  319. package/dist/sandbox-CdKgQ3XU.d.cts.map +1 -0
  320. package/dist/{workspace-C6VJQVtG.cjs → schemas-BCwKKA42.mjs} +958 -1842
  321. package/dist/schemas-BCwKKA42.mjs.map +1 -0
  322. package/dist/{workspace-zoqRbihZ.mjs → schemas-BQ_v0lEX.cjs} +1048 -1658
  323. package/dist/schemas-BQ_v0lEX.cjs.map +1 -0
  324. package/dist/secretsManager-CQORubp9.mjs +97 -0
  325. package/dist/secretsManager-CQORubp9.mjs.map +1 -0
  326. package/dist/secretsManager-RAGcEDX1.cjs +108 -0
  327. package/dist/secretsManager-RAGcEDX1.cjs.map +1 -0
  328. package/dist/seeds-CHIPcMrY.cjs +9115 -0
  329. package/dist/seeds-CHIPcMrY.cjs.map +1 -0
  330. package/dist/seeds-E4nUeXTl.mjs +8148 -0
  331. package/dist/seeds-E4nUeXTl.mjs.map +1 -0
  332. package/dist/sniffer-bUiSXLMj.mjs +1825 -0
  333. package/dist/sniffer-bUiSXLMj.mjs.map +1 -0
  334. package/dist/sniffer-n3TkX6JD.cjs +1998 -0
  335. package/dist/sniffer-n3TkX6JD.cjs.map +1 -0
  336. package/dist/sst-B-Uz4cvm.cjs +464 -0
  337. package/dist/sst-B-Uz4cvm.cjs.map +1 -0
  338. package/dist/sst-C1pxbFEd.mjs +441 -0
  339. package/dist/sst-C1pxbFEd.mjs.map +1 -0
  340. package/dist/stages-DJrOYLZ-.mjs +176 -0
  341. package/dist/stages-DJrOYLZ-.mjs.map +1 -0
  342. package/dist/stages-_3RVNG83.cjs +176 -0
  343. package/dist/stages-_3RVNG83.cjs.map +1 -0
  344. package/dist/target/public.cjs +15 -0
  345. package/dist/target/public.d.cts +28 -0
  346. package/dist/target/public.d.cts.map +1 -0
  347. package/dist/target/public.d.mts +28 -0
  348. package/dist/target/public.d.mts.map +1 -0
  349. package/dist/target/public.mjs +4 -0
  350. package/dist/terminal-Bs_lNQhL.mjs +85 -0
  351. package/dist/terminal-Bs_lNQhL.mjs.map +1 -0
  352. package/dist/terminal-CsQz4oT0.cjs +85 -0
  353. package/dist/terminal-CsQz4oT0.cjs.map +1 -0
  354. package/dist/types-B6UXlEkf.d.cts +7650 -0
  355. package/dist/types-B6UXlEkf.d.cts.map +1 -0
  356. package/dist/types-HqVPddRK.d.mts +7649 -0
  357. package/dist/types-HqVPddRK.d.mts.map +1 -0
  358. package/dist/utils-D2Nk1Nv2.cjs +205 -0
  359. package/dist/utils-D2Nk1Nv2.cjs.map +1 -0
  360. package/dist/utils-D_fxUqvU.mjs +156 -0
  361. package/dist/utils-D_fxUqvU.mjs.map +1 -0
  362. package/dist/vitest.cjs +65 -0
  363. package/dist/vitest.cjs.map +1 -0
  364. package/dist/vitest.d.cts +29 -0
  365. package/dist/vitest.d.cts.map +1 -0
  366. package/dist/vitest.d.mts +29 -0
  367. package/dist/vitest.d.mts.map +1 -0
  368. package/dist/vitest.mjs +65 -0
  369. package/dist/vitest.mjs.map +1 -0
  370. package/dist/workerRuntime-BXfhbe13.cjs +108 -0
  371. package/dist/workerRuntime-BXfhbe13.cjs.map +1 -0
  372. package/dist/workerRuntime-CsOyBRx2.mjs +79 -0
  373. package/dist/workerRuntime-CsOyBRx2.mjs.map +1 -0
  374. package/dist/workspace/index.cjs +8 -4
  375. package/dist/workspace/index.d.cts +3 -3
  376. package/dist/workspace/index.d.mts +3 -3
  377. package/dist/workspace/index.mjs +2 -3
  378. package/dist/workspace-BwqQnool.cjs +2806 -0
  379. package/dist/workspace-BwqQnool.cjs.map +1 -0
  380. package/dist/workspace-D1QbNd55.mjs +2394 -0
  381. package/dist/workspace-D1QbNd55.mjs.map +1 -0
  382. package/package.json +54 -22
  383. package/dist/CachedStateProvider-BLo7zv7S.cjs +0 -3
  384. package/dist/CachedStateProvider-BxoAm-B2.mjs +0 -3
  385. package/dist/CachedStateProvider-CqPdW7CB.cjs +0 -60
  386. package/dist/CachedStateProvider-CqPdW7CB.cjs.map +0 -1
  387. package/dist/CachedStateProvider-DTniehMP.mjs +0 -54
  388. package/dist/CachedStateProvider-DTniehMP.mjs.map +0 -1
  389. package/dist/HostingerProvider-Cft7lEYr.mjs.map +0 -1
  390. package/dist/HostingerProvider-h3EbEp-Z.cjs.map +0 -1
  391. package/dist/LocalStateProvider-Bn6tS-oL.mjs +0 -42
  392. package/dist/LocalStateProvider-Bn6tS-oL.mjs.map +0 -1
  393. package/dist/LocalStateProvider-Db9SEjyH.cjs +0 -43
  394. package/dist/LocalStateProvider-Db9SEjyH.cjs.map +0 -1
  395. package/dist/Route53Provider-RdpUDJQk.mjs.map +0 -1
  396. package/dist/Route53Provider-di2fMM5N.cjs.map +0 -1
  397. package/dist/SSMStateProvider-BRt2py-A.mjs +0 -66
  398. package/dist/SSMStateProvider-BRt2py-A.mjs.map +0 -1
  399. package/dist/SSMStateProvider-DyX8s9HI.cjs +0 -66
  400. package/dist/SSMStateProvider-DyX8s9HI.cjs.map +0 -1
  401. package/dist/backup-provisioner-Bgj5Vi_L.mjs.map +0 -1
  402. package/dist/backup-provisioner-BrsHwYG0.cjs.map +0 -1
  403. package/dist/bundler-BY1OmV1e.cjs.map +0 -1
  404. package/dist/bundler-Be8Zg4Wd.mjs.map +0 -1
  405. package/dist/chunk-Duj1WY3L.mjs +0 -7
  406. package/dist/config-BZ1F0WuA.cjs +0 -462
  407. package/dist/config-BZ1F0WuA.cjs.map +0 -1
  408. package/dist/config-DVVph9yz.mjs +0 -402
  409. package/dist/config-DVVph9yz.mjs.map +0 -1
  410. package/dist/config.d.cts.map +0 -1
  411. package/dist/config.d.mts.map +0 -1
  412. package/dist/credentials-B5zRHdAl.mjs +0 -141
  413. package/dist/credentials-B5zRHdAl.mjs.map +0 -1
  414. package/dist/credentials-BapzjyV5.cjs +0 -195
  415. package/dist/credentials-BapzjyV5.cjs.map +0 -1
  416. package/dist/credentials-Xamqe_NJ.cjs +0 -2681
  417. package/dist/credentials-Xamqe_NJ.cjs.map +0 -1
  418. package/dist/credentials-dP8vRVRv.mjs +0 -2549
  419. package/dist/credentials-dP8vRVRv.mjs.map +0 -1
  420. package/dist/discover-CAlFgYec.mjs +0 -229
  421. package/dist/discover-CAlFgYec.mjs.map +0 -1
  422. package/dist/discover-DTmFeloL.cjs +0 -271
  423. package/dist/discover-DTmFeloL.cjs.map +0 -1
  424. package/dist/dokploy-api-BS2xnJLZ.mjs +0 -3
  425. package/dist/dokploy-api-BsVH0y_s.cjs +0 -718
  426. package/dist/dokploy-api-BsVH0y_s.cjs.map +0 -1
  427. package/dist/dokploy-api-BuxDRo3l.cjs +0 -3
  428. package/dist/dokploy-api-aTFPz7_4.mjs +0 -706
  429. package/dist/dokploy-api-aTFPz7_4.mjs.map +0 -1
  430. package/dist/emit-CbcRolsa.cjs.map +0 -1
  431. package/dist/emit-CiZS_5Ub.mjs.map +0 -1
  432. package/dist/encryption-C6jaU0hE.cjs +0 -54
  433. package/dist/encryption-C6jaU0hE.cjs.map +0 -1
  434. package/dist/encryption-CHzzeR8a.cjs +0 -4
  435. package/dist/encryption-CQUncu7v.mjs +0 -3
  436. package/dist/encryption-D-abyhZx.mjs +0 -42
  437. package/dist/encryption-D-abyhZx.mjs.map +0 -1
  438. package/dist/fullstack-secrets-C-GGohke.cjs +0 -111
  439. package/dist/fullstack-secrets-C-GGohke.cjs.map +0 -1
  440. package/dist/fullstack-secrets-D1o9-G5l.mjs +0 -87
  441. package/dist/fullstack-secrets-D1o9-G5l.mjs.map +0 -1
  442. package/dist/generator-CNzBw7g5.cjs +0 -289
  443. package/dist/generator-CNzBw7g5.cjs.map +0 -1
  444. package/dist/generator-VE2JrFlY.mjs +0 -253
  445. package/dist/generator-VE2JrFlY.mjs.map +0 -1
  446. package/dist/index-C6e-ULLx.d.mts.map +0 -1
  447. package/dist/index-CR5urhWX.d.cts.map +0 -1
  448. package/dist/openapi-SjsgARie.cjs +0 -2075
  449. package/dist/openapi-SjsgARie.cjs.map +0 -1
  450. package/dist/openapi-Xx0A7Wg0.mjs +0 -2021
  451. package/dist/openapi-Xx0A7Wg0.mjs.map +0 -1
  452. package/dist/openapi-react-query-Byltvm_7.mjs +0 -167
  453. package/dist/openapi-react-query-Byltvm_7.mjs.map +0 -1
  454. package/dist/openapi-react-query-CmJ1xDbn.cjs +0 -173
  455. package/dist/openapi-react-query-CmJ1xDbn.cjs.map +0 -1
  456. package/dist/openapi-react-query.cjs +0 -4
  457. package/dist/openapi-react-query.d.cts +0 -11
  458. package/dist/openapi-react-query.d.cts.map +0 -1
  459. package/dist/openapi-react-query.d.mts +0 -11
  460. package/dist/openapi-react-query.d.mts.map +0 -1
  461. package/dist/openapi-react-query.mjs +0 -4
  462. package/dist/reconcile-CFs8C_1a.mjs.map +0 -1
  463. package/dist/reconcile-D0pimNiy.cjs.map +0 -1
  464. package/dist/setup-BA8ciTPU.mjs +0 -11
  465. package/dist/setup-BsZvZP6f.cjs +0 -11
  466. package/dist/setup-C8KOx8_8.mjs +0 -443
  467. package/dist/setup-C8KOx8_8.mjs.map +0 -1
  468. package/dist/setup-hC6hI86f.cjs +0 -473
  469. package/dist/setup-hC6hI86f.cjs.map +0 -1
  470. package/dist/storage-BJmzYxt8.cjs +0 -363
  471. package/dist/storage-BJmzYxt8.cjs.map +0 -1
  472. package/dist/storage-BM9hGpgv.cjs +0 -7
  473. package/dist/storage-Bi24WfoW.mjs +0 -297
  474. package/dist/storage-Bi24WfoW.mjs.map +0 -1
  475. package/dist/storage-CYlGwWTj.mjs +0 -3
  476. package/dist/sync-CmEuNZsB.mjs +0 -76
  477. package/dist/sync-CmEuNZsB.mjs.map +0 -1
  478. package/dist/sync-D306yOWu.cjs +0 -4
  479. package/dist/sync-SizaChmC.cjs +0 -93
  480. package/dist/sync-SizaChmC.cjs.map +0 -1
  481. package/dist/sync-hOqAWHR6.mjs +0 -3
  482. package/dist/types-6pkp2RRj.d.mts +0 -2220
  483. package/dist/types-6pkp2RRj.d.mts.map +0 -1
  484. package/dist/types-Y3fKQSAK.d.cts +0 -2220
  485. package/dist/types-Y3fKQSAK.d.cts.map +0 -1
  486. package/dist/workspace-BzrG_2SI.mjs +0 -8
  487. package/dist/workspace-C6VJQVtG.cjs.map +0 -1
  488. package/dist/workspace-XXtNhqJl.cjs +0 -9
  489. package/dist/workspace-zoqRbihZ.mjs.map +0 -1
@@ -1,2021 +0,0 @@
1
- import { ConstructGenerator, isPartitionedRoutes } from "./discover-CAlFgYec.mjs";
2
- import { loadWorkspaceConfig } from "./config-DVVph9yz.mjs";
3
- import { dirname, join, relative, resolve } from "node:path";
4
- import { kebabCase } from "@geekmidas/manifest";
5
- import { mkdir, writeFile } from "node:fs/promises";
6
- import { spawn } from "node:child_process";
7
- import { Endpoint } from "@geekmidas/constructs/endpoints";
8
- import { fileURLToPath } from "node:url";
9
- import { StandardSchemaJsonSchema, getRegisteredZodJsonSchemas, getSchemaMetadata } from "@geekmidas/schema/conversion";
10
-
11
- //#region src/build/endpoint-analyzer.ts
12
- /**
13
- * Analyze an endpoint to extract its features
14
- */
15
- function analyzeEndpointFeatures(endpoint) {
16
- return {
17
- hasAuth: !!endpoint.authorizer,
18
- hasServices: endpoint.services.length > 0,
19
- hasDatabase: !!endpoint.databaseService,
20
- hasBodyValidation: !!endpoint.input?.body,
21
- hasQueryValidation: !!endpoint.input?.query,
22
- hasParamValidation: !!endpoint.input?.params,
23
- hasAudits: (endpoint.audits?.length ?? 0) > 0,
24
- hasEvents: (endpoint.events?.length ?? 0) > 0,
25
- hasRateLimit: !!endpoint.rateLimit,
26
- hasRls: !!endpoint.rlsConfig && !endpoint.rlsBypass,
27
- hasOutputValidation: !!endpoint.outputSchema
28
- };
29
- }
30
- /**
31
- * Determine the optimization tier for an endpoint based on its features
32
- */
33
- function determineEndpointTier(features) {
34
- const { hasAuth, hasServices, hasDatabase, hasAudits, hasEvents, hasRateLimit, hasRls } = features;
35
- if (!hasAuth && !hasServices && !hasDatabase && !hasAudits && !hasEvents && !hasRateLimit && !hasRls) return "minimal";
36
- if (hasAudits || hasRls || hasRateLimit) return "full";
37
- return "standard";
38
- }
39
- /**
40
- * Perform complete analysis of an endpoint
41
- */
42
- function analyzeEndpoint(endpoint, exportName) {
43
- const features = analyzeEndpointFeatures(endpoint);
44
- const tier = determineEndpointTier(features);
45
- return {
46
- route: endpoint.route,
47
- method: endpoint.method,
48
- exportName,
49
- features,
50
- tier,
51
- serviceNames: endpoint.services.map((s) => s.serviceName),
52
- databaseServiceName: endpoint.databaseService?.serviceName
53
- };
54
- }
55
- /**
56
- * Generate a summary of endpoint analysis for logging
57
- */
58
- function summarizeAnalysis(analyses) {
59
- const byTier = {
60
- minimal: 0,
61
- standard: 0,
62
- full: 0
63
- };
64
- const byFeature = {
65
- hasAuth: 0,
66
- hasServices: 0,
67
- hasDatabase: 0,
68
- hasBodyValidation: 0,
69
- hasQueryValidation: 0,
70
- hasParamValidation: 0,
71
- hasAudits: 0,
72
- hasEvents: 0,
73
- hasRateLimit: 0,
74
- hasRls: 0,
75
- hasOutputValidation: 0
76
- };
77
- for (const analysis of analyses) {
78
- byTier[analysis.tier]++;
79
- for (const [feature, enabled] of Object.entries(analysis.features)) if (enabled) byFeature[feature]++;
80
- }
81
- return {
82
- total: analyses.length,
83
- byTier,
84
- byFeature
85
- };
86
- }
87
-
88
- //#endregion
89
- //#region src/build/handler-templates.ts
90
- /**
91
- * Generate validator references for an endpoint
92
- */
93
- function generateValidators(exportName, features) {
94
- const validators = [];
95
- if (features.hasBodyValidation) validators.push(`validateBody(${exportName})`);
96
- if (features.hasQueryValidation) validators.push(`validateQuery(${exportName})`);
97
- if (features.hasParamValidation) validators.push(`validateParams(${exportName})`);
98
- return validators.length > 0 ? `\n ${validators.join(",\n ")},` : "";
99
- }
100
- /**
101
- * Generate a minimal handler (near-raw-Hono performance)
102
- *
103
- * Used for: Health checks, public endpoints with no services
104
- */
105
- function generateMinimalHandler(analysis) {
106
- const { exportName, features } = analysis;
107
- const method = analysis.method.toLowerCase();
108
- const validators = generateValidators(exportName, features);
109
- const hasValidators = validators.length > 0;
110
- if (!hasValidators && !features.hasOutputValidation) return `
111
- // Minimal handler: ${analysis.route} (${analysis.method})
112
- app.${method}('${analysis.route}', async (c) => {
113
- const result = await ${exportName}.handler(
114
- {
115
- services: {},
116
- logger,
117
- body: undefined,
118
- query: undefined,
119
- params: undefined,
120
- session: undefined,
121
- header: Endpoint.createHeaders(c.req.header()),
122
- cookie: Endpoint.createCookies(c.req.header().cookie),
123
- auditor: undefined,
124
- db: undefined,
125
- } as any,
126
- { getMetadata: () => ({}) } as any,
127
- );
128
- return c.json(result, ${exportName}.status as any);
129
- });`;
130
- return `
131
- // Minimal handler with validation: ${analysis.route} (${analysis.method})
132
- app.${method}('${analysis.route}',${validators}
133
- async (c) => {
134
- const result = await ${exportName}.handler(
135
- {
136
- services: {},
137
- logger,
138
- body: ${features.hasBodyValidation ? "(c.req.valid as any)('json')" : "undefined"},
139
- query: ${features.hasQueryValidation ? "(c.req.valid as any)('query')" : "undefined"},
140
- params: ${features.hasParamValidation ? "(c.req.valid as any)('param')" : "undefined"},
141
- session: undefined,
142
- header: Endpoint.createHeaders(c.req.header()),
143
- cookie: Endpoint.createCookies(c.req.header().cookie),
144
- auditor: undefined,
145
- db: undefined,
146
- } as any,
147
- { getMetadata: () => ({}) } as any,
148
- );
149
- ${features.hasOutputValidation ? `const output = await ${exportName}.parseOutput(result);
150
- return c.json(output, ${exportName}.status as any);` : `return c.json(result, ${exportName}.status as any);`}
151
- }
152
- );`;
153
- }
154
- /**
155
- * Generate a standard handler (auth and/or services)
156
- *
157
- * Used for: Authenticated endpoints, endpoints with services
158
- */
159
- function generateStandardHandler(analysis) {
160
- const { exportName, features } = analysis;
161
- const method = analysis.method.toLowerCase();
162
- const validators = generateValidators(exportName, features);
163
- let serviceResolution = "";
164
- if (features.hasServices || features.hasDatabase) serviceResolution = `
165
- const services = await serviceDiscovery.register(${exportName}.services);
166
- ${features.hasDatabase ? `const db = ${exportName}.databaseService
167
- ? (await serviceDiscovery.register([${exportName}.databaseService]) as any)[${exportName}.databaseService.serviceName]
168
- : undefined;` : "const db = undefined;"}`;
169
- else serviceResolution = `
170
- const services = {};
171
- const db = undefined;`;
172
- let authCode = "";
173
- if (features.hasAuth) authCode = `
174
- // Authentication
175
- const session = await ${exportName}.getSession({
176
- services,
177
- logger,
178
- header,
179
- cookie,
180
- ...(db !== undefined && { db }),
181
- } as any);
182
-
183
- const isAuthorized = await ${exportName}.authorize({
184
- header,
185
- cookie,
186
- services,
187
- logger,
188
- session,
189
- } as any);
190
-
191
- if (!isAuthorized) {
192
- return c.json({ error: 'Unauthorized' }, 401);
193
- }`;
194
- let eventCode = "";
195
- if (features.hasEvents) eventCode = `
196
- // Publish events on success
197
- if (Endpoint.isSuccessStatus(${exportName}.status)) {
198
- await (publishConstructEvents as any)(
199
- ${exportName},
200
- result,
201
- serviceDiscovery,
202
- logger,
203
- );
204
- }`;
205
- return `
206
- // Standard handler: ${analysis.route} (${analysis.method})
207
- app.${method}('${analysis.route}',${validators}
208
- async (c) => {
209
- const headerValues = c.req.header();
210
- const header = Endpoint.createHeaders(headerValues);
211
- const cookie = Endpoint.createCookies(headerValues.cookie);
212
- ${serviceResolution}
213
- ${authCode}
214
-
215
- const responseBuilder = new ResponseBuilder();
216
- const result = await ${exportName}.handler(
217
- {
218
- services,
219
- logger,
220
- body: ${features.hasBodyValidation ? "(c.req.valid as any)('json')" : "undefined"},
221
- query: ${features.hasQueryValidation ? "(c.req.valid as any)('query')" : "undefined"},
222
- params: ${features.hasParamValidation ? "(c.req.valid as any)('param')" : "undefined"},
223
- session: ${features.hasAuth ? "session" : "undefined"},
224
- header,
225
- cookie,
226
- auditor: undefined,
227
- db,
228
- } as any,
229
- responseBuilder,
230
- );
231
-
232
- let data = result;
233
- let metadata = responseBuilder.getMetadata();
234
-
235
- if (Endpoint.hasMetadata(result)) {
236
- data = result.data;
237
- metadata = result.metadata;
238
- }
239
-
240
- ${features.hasOutputValidation ? `const output = ${exportName}.outputSchema
241
- ? await ${exportName}.parseOutput(data)
242
- : data;` : "const output = data;"}
243
- ${eventCode}
244
-
245
- const status = (metadata.status ?? ${exportName}.status) as any;
246
- return c.json(output, status);
247
- }
248
- );`;
249
- }
250
- /**
251
- * Generate validators.ts - Shared validator middleware factories
252
- */
253
- function generateValidatorsFile(analyses) {
254
- const needsBody = analyses.some((a) => a.features.hasBodyValidation);
255
- const needsQuery = analyses.some((a) => a.features.hasQueryValidation);
256
- const needsParams = analyses.some((a) => a.features.hasParamValidation);
257
- if (!needsBody && !needsQuery && !needsParams) return `// No validators needed for this build\nexport {};\n`;
258
- const exports = [];
259
- const factories = [];
260
- if (needsBody) {
261
- exports.push("validateBody");
262
- factories.push(`
263
- export const validateBody = (endpoint: any) =>
264
- validator('json', async (value, c) => {
265
- if (!endpoint.input?.body) return undefined;
266
- const parsed = await Endpoint.validate(endpoint.input.body, value);
267
- if (parsed.issues) return c.json(parsed.issues, 422);
268
- return parsed.value;
269
- });`);
270
- }
271
- if (needsQuery) {
272
- exports.push("validateQuery");
273
- factories.push(`
274
- export const validateQuery = (endpoint: any) =>
275
- validator('query', async (_, c) => {
276
- if (!endpoint.input?.query) return undefined;
277
- const rawQuery = Object.fromEntries(new URL(c.req.url).searchParams);
278
- const parsed = await Endpoint.validate(endpoint.input.query, rawQuery);
279
- if (parsed.issues) return c.json(parsed.issues, 422);
280
- return parsed.value;
281
- });`);
282
- }
283
- if (needsParams) {
284
- exports.push("validateParams");
285
- factories.push(`
286
- export const validateParams = (endpoint: any) =>
287
- validator('param', async (params, c) => {
288
- if (!endpoint.input?.params) return undefined;
289
- const parsed = await Endpoint.validate(endpoint.input.params, params);
290
- if (parsed.issues) return c.json(parsed.issues, 422);
291
- return parsed.value;
292
- });`);
293
- }
294
- return `/**
295
- * Generated validator middleware factories
296
- * Shared across all endpoint tiers that need validation
297
- */
298
- import { validator } from 'hono/validator';
299
- import { Endpoint } from '@geekmidas/constructs/endpoints';
300
- ${factories.join("\n")}
301
- `;
302
- }
303
- /**
304
- * Generate a standalone minimal endpoint file
305
- */
306
- function generateMinimalEndpointFile(analysis, endpointImport) {
307
- const { exportName, features } = analysis;
308
- const needsValidators = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation;
309
- const validatorImport = needsValidators ? generateValidatorImportsForEndpoint(analysis) : "";
310
- const handler = generateMinimalHandler(analysis);
311
- return `/**
312
- * Minimal endpoint: ${analysis.route} (${analysis.method})
313
- * Near-raw-Hono performance
314
- */
315
- import type { Hono } from 'hono';
316
- import type { Logger } from '@geekmidas/logger';
317
- import { Endpoint } from '@geekmidas/constructs/endpoints';
318
- ${validatorImport}
319
- import { ${exportName} } from '${endpointImport.importPath}';
320
-
321
- export function setup${capitalize(exportName)}(
322
- app: Hono,
323
- logger: Logger,
324
- ): void {
325
- ${handler}
326
- }
327
- `;
328
- }
329
- /**
330
- * Generate a standalone standard endpoint file
331
- */
332
- function generateStandardEndpointFile(analysis, endpointImport) {
333
- const { exportName, features } = analysis;
334
- const needsValidators = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation;
335
- const validatorImport = needsValidators ? generateValidatorImportsForEndpoint(analysis) : "";
336
- const eventsImport = features.hasEvents ? `import { publishConstructEvents } from '@geekmidas/constructs/endpoints';` : "";
337
- const handler = generateStandardHandler(analysis);
338
- return `/**
339
- * Standard endpoint: ${analysis.route} (${analysis.method})
340
- * Auth and/or services enabled
341
- */
342
- import type { Hono } from 'hono';
343
- import type { Logger } from '@geekmidas/logger';
344
- import type { ServiceDiscovery } from '@geekmidas/services';
345
- import { Endpoint, ResponseBuilder } from '@geekmidas/constructs/endpoints';
346
- ${eventsImport}
347
- ${validatorImport}
348
- import { ${exportName} } from '${endpointImport.importPath}';
349
-
350
- export function setup${capitalize(exportName)}(
351
- app: Hono,
352
- serviceDiscovery: ServiceDiscovery<any, any>,
353
- logger: Logger,
354
- ): void {
355
- ${handler}
356
- }
357
- `;
358
- }
359
- /**
360
- * Generate a standalone full endpoint file
361
- */
362
- function generateFullEndpointFile(analysis, endpointImport) {
363
- const { exportName } = analysis;
364
- return `/**
365
- * Full endpoint: ${analysis.route} (${analysis.method})
366
- * Complex features: audits, RLS, rate limiting
367
- */
368
- import type { Hono } from 'hono';
369
- import type { ServiceDiscovery } from '@geekmidas/services';
370
- import { HonoEndpoint } from '@geekmidas/constructs/hono';
371
- import { ${exportName} } from '${endpointImport.importPath}';
372
-
373
- export function setup${capitalize(exportName)}(
374
- app: Hono,
375
- serviceDiscovery: ServiceDiscovery<any, any>,
376
- openApiOptions: any,
377
- ): void {
378
- HonoEndpoint.addRoutes([${exportName}] as any, serviceDiscovery, app, openApiOptions);
379
- }
380
- `;
381
- }
382
- /**
383
- * Generate tier index file that imports and calls all endpoint setup functions
384
- */
385
- function generateTierIndexFile(tier, analyses) {
386
- const tierEndpoints = analyses.filter((a) => a.tier === tier);
387
- if (tierEndpoints.length === 0) {
388
- if (tier === "minimal") return `// No minimal-tier endpoints in this build
389
- import type { Hono } from 'hono';
390
- import type { Logger } from '@geekmidas/logger';
391
-
392
- export function setupMinimalEndpoints(
393
- _app: Hono,
394
- _logger: Logger,
395
- ): void {
396
- // No minimal endpoints
397
- }
398
- `;
399
- if (tier === "standard") return `// No standard-tier endpoints in this build
400
- import type { Hono } from 'hono';
401
- import type { Logger } from '@geekmidas/logger';
402
- import type { ServiceDiscovery } from '@geekmidas/services';
403
-
404
- export function setupStandardEndpoints(
405
- _app: Hono,
406
- _serviceDiscovery: ServiceDiscovery<any, any>,
407
- _logger: Logger,
408
- ): void {
409
- // No standard endpoints
410
- }
411
- `;
412
- return `// No full-tier endpoints in this build
413
- import type { Hono } from 'hono';
414
- import type { ServiceDiscovery } from '@geekmidas/services';
415
-
416
- export function setupFullEndpoints(
417
- _app: Hono,
418
- _serviceDiscovery: ServiceDiscovery<any, any>,
419
- _enableOpenApi: boolean,
420
- ): void {
421
- // No full endpoints
422
- }
423
- `;
424
- }
425
- const imports = tierEndpoints.map((a) => `import { setup${capitalize(a.exportName)} } from './${a.exportName}.js';`).join("\n");
426
- if (tier === "minimal") {
427
- const calls$1 = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, logger);`).join("\n");
428
- return `/**
429
- * Minimal-tier endpoint index (${tierEndpoints.length} endpoints)
430
- * Near-raw-Hono performance
431
- */
432
- import type { Hono } from 'hono';
433
- import type { Logger } from '@geekmidas/logger';
434
- ${imports}
435
-
436
- export function setupMinimalEndpoints(
437
- app: Hono,
438
- logger: Logger,
439
- ): void {
440
- ${calls$1}
441
- }
442
- `;
443
- }
444
- if (tier === "standard") {
445
- const calls$1 = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, serviceDiscovery, logger);`).join("\n");
446
- return `/**
447
- * Standard-tier endpoint index (${tierEndpoints.length} endpoints)
448
- * Auth and/or services enabled
449
- */
450
- import type { Hono } from 'hono';
451
- import type { Logger } from '@geekmidas/logger';
452
- import type { ServiceDiscovery } from '@geekmidas/services';
453
- ${imports}
454
-
455
- export function setupStandardEndpoints(
456
- app: Hono,
457
- serviceDiscovery: ServiceDiscovery<any, any>,
458
- logger: Logger,
459
- ): void {
460
- ${calls$1}
461
- }
462
- `;
463
- }
464
- const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, serviceDiscovery, openApiOptions);`).join("\n");
465
- return `/**
466
- * Full-tier endpoint index (${tierEndpoints.length} endpoints)
467
- * Complex features: audits, RLS, rate limiting
468
- */
469
- import type { Hono } from 'hono';
470
- import type { ServiceDiscovery } from '@geekmidas/services';
471
- ${imports}
472
-
473
- export function setupFullEndpoints(
474
- app: Hono,
475
- serviceDiscovery: ServiceDiscovery<any, any>,
476
- enableOpenApi: boolean,
477
- ): void {
478
- const openApiOptions: any = enableOpenApi ? {
479
- docsPath: '/__docs',
480
- openApiOptions: {
481
- title: 'API Documentation',
482
- version: '1.0.0',
483
- description: 'Generated API documentation'
484
- }
485
- } : { docsPath: false };
486
-
487
- ${calls}
488
- }
489
- `;
490
- }
491
- /**
492
- * Generate validator imports for a single endpoint
493
- */
494
- function generateValidatorImportsForEndpoint(analysis) {
495
- const imports = [];
496
- if (analysis.features.hasBodyValidation) imports.push("validateBody");
497
- if (analysis.features.hasQueryValidation) imports.push("validateQuery");
498
- if (analysis.features.hasParamValidation) imports.push("validateParams");
499
- if (imports.length === 0) return "";
500
- return `import { ${imports.join(", ")} } from '../validators.js';`;
501
- }
502
- /**
503
- * Capitalize first letter
504
- */
505
- function capitalize(str) {
506
- return str.charAt(0).toUpperCase() + str.slice(1);
507
- }
508
- /**
509
- * Generate all endpoint files with nested folder structure (per-endpoint files)
510
- */
511
- function generateEndpointFilesNested(analyses, endpointImports) {
512
- const files = {
513
- "validators.ts": generateValidatorsFile(analyses),
514
- "minimal/index.ts": generateTierIndexFile("minimal", analyses),
515
- "standard/index.ts": generateTierIndexFile("standard", analyses),
516
- "full/index.ts": generateTierIndexFile("full", analyses),
517
- "index.ts": generateNestedIndexFile(analyses)
518
- };
519
- for (const analysis of analyses) {
520
- const endpointImport = endpointImports.find((i) => i.exportName === analysis.exportName);
521
- if (!endpointImport) continue;
522
- const fileName = `${analysis.tier}/${analysis.exportName}.ts`;
523
- switch (analysis.tier) {
524
- case "minimal":
525
- files[fileName] = generateMinimalEndpointFile(analysis, endpointImport);
526
- break;
527
- case "standard":
528
- files[fileName] = generateStandardEndpointFile(analysis, endpointImport);
529
- break;
530
- case "full":
531
- files[fileName] = generateFullEndpointFile(analysis, endpointImport);
532
- break;
533
- }
534
- }
535
- return files;
536
- }
537
- /**
538
- * Generate index.ts for nested structure
539
- */
540
- function generateNestedIndexFile(analyses) {
541
- const minimalCount = analyses.filter((a) => a.tier === "minimal").length;
542
- const standardCount = analyses.filter((a) => a.tier === "standard").length;
543
- const fullCount = analyses.filter((a) => a.tier === "full").length;
544
- return `/**
545
- * Generated optimized endpoints
546
- *
547
- * Build-time optimization tiers:
548
- * - minimal: ${minimalCount} endpoints (near-raw-Hono)
549
- * - standard: ${standardCount} endpoints (auth/services)
550
- * - full: ${fullCount} endpoints (audits/rls/rate-limit)
551
- */
552
- import type { EnvironmentParser } from '@geekmidas/envkit';
553
- import type { Logger } from '@geekmidas/logger';
554
- import type { Hono } from 'hono';
555
- import { ServiceDiscovery } from '@geekmidas/services';
556
- import { setupMinimalEndpoints } from './minimal/index.js';
557
- import { setupStandardEndpoints } from './standard/index.js';
558
- import { setupFullEndpoints } from './full/index.js';
559
-
560
- export async function setupEndpoints(
561
- app: Hono,
562
- envParser: EnvironmentParser<any>,
563
- logger: Logger,
564
- enableOpenApi: boolean = false,
565
- ): Promise<void> {
566
- const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
567
-
568
- // Minimal handlers (${minimalCount} endpoints) - near-raw-Hono performance
569
- setupMinimalEndpoints(app, logger);
570
-
571
- // Standard handlers (${standardCount} endpoints) - auth/services
572
- setupStandardEndpoints(app, serviceDiscovery, logger);
573
-
574
- // Full handlers (${fullCount} endpoints) - audits/rls/rate-limit
575
- setupFullEndpoints(app, serviceDiscovery, enableOpenApi);
576
-
577
- // Add Swagger UI if OpenAPI is enabled
578
- if (enableOpenApi) {
579
- try {
580
- const { swaggerUI } = await import('@hono/swagger-ui');
581
- app.get('/__docs/ui', swaggerUI({ url: '/__docs' }));
582
- } catch {
583
- // @hono/swagger-ui not installed, skip Swagger UI
584
- }
585
- }
586
- }
587
- `;
588
- }
589
-
590
- //#endregion
591
- //#region src/generators/EndpointGenerator.ts
592
- /**
593
- * How a generated entry gets its logger and environment parser.
594
- *
595
- * From the surface it serves, when there is one: the surface holds both as
596
- * *objects*, and discovery already recorded which module declares it, so the
597
- * entry imports that module and reads them off it.
598
- *
599
- * The alternative — the shape this replaces — was naming both in config as
600
- * module paths, `envParser: './config/env#envParser'`, and printing an import
601
- * for each. Two strings per app, checked by nothing, describing files the
602
- * surface was already holding the contents of.
603
- *
604
- * Falls back to the configured paths for an app that declares no surface.
605
- */
606
- function runtimeFor(context, fromDir, owner) {
607
- const module = owner ? context.owners?.[owner] ?? context.surface?.module : context.surface?.module;
608
- if (module) {
609
- const specifier = importSpecifier(fromDir, module.specifier);
610
- return {
611
- imports: `import { ${module.exportName} as __surface } from '${specifier}';`,
612
- bindings: [
613
- "// What this construct was declared with. Objects, not module paths:",
614
- "// the entry imports the owner, so there is nothing to print.",
615
- "const envParser = __surface.envParser;",
616
- "const logger = __surface.logger;"
617
- ].join("\n")
618
- };
619
- }
620
- throw new Error(`No owner to take a logger and an environment parser from${owner ? ` for "${owner}"` : ""}. Build it from a \`RestApi\` or a \`Worker\`.`);
621
- }
622
- /** A relative specifier ESM will accept: always prefixed, never bare. */
623
- function importSpecifier(fromDir, target) {
624
- const rel = relative(fromDir, target).replace(/\.ts$/, ".js");
625
- return rel.startsWith(".") ? rel : `./${rel}`;
626
- }
627
- /**
628
- * CORS for a surface, derived rather than hand-written.
629
- *
630
- * Who may call a surface is already in the graph — every construct that
631
- * declared an edge to it — and reaches the process as one comma-separated
632
- * value. An application that maintained this by hand maintained a list that was
633
- * wrong in two directions at once: it trusted origins nothing was serving, and
634
- * it could not name hosts a deploy had not chosen yet.
635
- *
636
- * Only the parts a graph cannot answer are configurable, and every one has a
637
- * default: a surface that says nothing about CORS still gets it.
638
- */
639
- function corsFor(surface) {
640
- if (!surface) return {
641
- imports: "",
642
- setup: ""
643
- };
644
- const cors = surface.cors ?? {};
645
- const allowHeaders = [
646
- "content-type",
647
- "authorization",
648
- ...cors.allowHeaders ?? []
649
- ];
650
- return {
651
- imports: `import { cors } from 'hono/cors';`,
652
- setup: `
653
- // Who may call ${surface.id}, read off the graph rather than listed here.
654
- {
655
- const { origins } = envParser
656
- .create((get) => ({
657
- origins: get('${surface.trustedOriginsKey}')
658
- .string()
659
- .default('')
660
- .transform((value: string) =>
661
- value.split(',').map((origin) => origin.trim()).filter(Boolean),
662
- ),
663
- }))
664
- .parse();
665
-
666
- honoApp.use('*', cors({
667
- origin: origins,
668
- allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
669
- allowHeaders: ${JSON.stringify(allowHeaders)},${cors.exposeHeaders ? `\n exposeHeaders: ${JSON.stringify(cors.exposeHeaders)},` : ""}
670
- credentials: ${cors.credentials ?? true},
671
- maxAge: ${cors.maxAge ?? 86400},
672
- }));
673
- }
674
- `
675
- };
676
- }
677
- var EndpointGenerator = class extends ConstructGenerator {
678
- isConstruct(value) {
679
- return Endpoint.isEndpoint(value);
680
- }
681
- async build(context, constructs, outputDir, options) {
682
- const provider = options?.provider || "aws-apigatewayv2";
683
- const enableOpenApi = options?.enableOpenApi || false;
684
- const logger = console;
685
- const routes = [];
686
- if (constructs.length === 0) return routes;
687
- if (provider === "server") {
688
- await this.generateEndpointsFile(outputDir, constructs, context);
689
- const appFile = await this.generateAppFile(outputDir, context);
690
- routes.push({
691
- path: "*",
692
- method: "ALL",
693
- handler: relative(process.cwd(), appFile),
694
- authorizer: "none"
695
- });
696
- logger.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
697
- } else if (provider === "aws-lambda") {
698
- const routesDir = join(outputDir, "routes");
699
- await mkdir(routesDir, { recursive: true });
700
- for (const { key, construct, path } of constructs) {
701
- const handlerFile = await this.generateHandlerFile(routesDir, path.relative, key, "aws-apigatewayv2", construct, context);
702
- const routeInfo = {
703
- path: construct._path,
704
- method: construct.method,
705
- handler: relative(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
706
- timeout: construct.timeout,
707
- memorySize: construct.memorySize,
708
- environment: await construct.getEnvironment({ markOptional: context.markOptional }),
709
- dependencies: construct.constructs,
710
- authorizer: construct.authorizer?.name ?? "none"
711
- };
712
- routes.push(routeInfo);
713
- logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
714
- }
715
- } else for (const { key, construct, path } of constructs) {
716
- const handlerFile = await this.generateHandlerFile(outputDir, path.relative, key, provider, construct, context);
717
- const routeInfo = {
718
- path: construct._path,
719
- method: construct.method,
720
- handler: relative(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
721
- timeout: construct.timeout,
722
- memorySize: construct.memorySize,
723
- environment: await construct.getEnvironment({ markOptional: context.markOptional }),
724
- dependencies: construct.constructs,
725
- authorizer: construct.authorizer?.name ?? "none"
726
- };
727
- routes.push(routeInfo);
728
- logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
729
- }
730
- return routes;
731
- }
732
- async generateHandlerFile(outputDir, sourceFile, exportName, provider, _endpoint, context) {
733
- const handlerFileName = `${exportName}.ts`;
734
- const handlerPath = join(outputDir, handlerFileName);
735
- const relativePath = relative(dirname(handlerPath), sourceFile);
736
- const importPath = relativePath.replace(/\.ts$/, ".js");
737
- let content;
738
- switch (provider) {
739
- case "aws-apigatewayv1":
740
- content = this.generateAWSApiGatewayV1Handler(importPath, exportName, context.storageDrivers);
741
- break;
742
- case "aws-apigatewayv2":
743
- content = this.generateAWSApiGatewayV2Handler(importPath, exportName, context.storageDrivers);
744
- break;
745
- case "server":
746
- content = this.generateServerHandler(importPath, exportName);
747
- break;
748
- default: throw new Error(`Unsupported provider: ${provider}`);
749
- }
750
- await writeFile(handlerPath, content);
751
- return handlerPath;
752
- }
753
- async generateEndpointsFile(outputDir, endpoints, context) {
754
- const endpointsFileName = "endpoints.ts";
755
- const endpointsPath = join(outputDir, endpointsFileName);
756
- const importsByFile = /* @__PURE__ */ new Map();
757
- for (const { path, key } of endpoints) {
758
- const relativePath = relative(dirname(endpointsPath), path.relative);
759
- const importPath = relativePath.replace(/\.ts$/, ".js");
760
- if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
761
- importsByFile.get(importPath)?.push(key);
762
- }
763
- const endpointImports = Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n");
764
- const allExportNames = endpoints.map(({ key }) => key);
765
- if (context.production?.enabled && context.production.optimizedHandlers) return this.generateOptimizedEndpointsFile(endpointsPath, endpoints, endpointImports, allExportNames);
766
- const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
767
- import type { Logger } from '@geekmidas/logger';
768
- import { HonoEndpoint } from '@geekmidas/constructs/hono';
769
- import { Endpoint } from '@geekmidas/constructs/endpoints';
770
- import { ServiceDiscovery } from '@geekmidas/services';
771
- import type { Hono } from 'hono';
772
- ${endpointImports}
773
-
774
- export const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any, any, any>[] = [
775
- ${allExportNames.join(",\n ")}
776
- ];
777
-
778
- export async function setupEndpoints(
779
- app: Hono,
780
- envParser: EnvironmentParser<any>,
781
- logger: Logger,
782
- enableOpenApi: boolean = true,
783
- ): Promise<void> {
784
- const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
785
-
786
- // Configure OpenAPI options based on enableOpenApi flag
787
- const openApiOptions: any = enableOpenApi ? {
788
- docsPath: '/__docs',
789
- openApiOptions: {
790
- title: 'API Documentation',
791
- version: '1.0.0',
792
- description: 'Generated API documentation'
793
- }
794
- } : { docsPath: false };
795
-
796
- HonoEndpoint.addRoutes(endpoints, serviceDiscovery, app, openApiOptions);
797
-
798
- // Add Swagger UI if OpenAPI is enabled
799
- if (enableOpenApi) {
800
- try {
801
- const { swaggerUI } = await import('@hono/swagger-ui');
802
- app.get('/__docs/ui', swaggerUI({ url: '/__docs' }));
803
- } catch {
804
- // @hono/swagger-ui not installed, skip Swagger UI
805
- }
806
- }
807
- }
808
- `;
809
- await writeFile(endpointsPath, content);
810
- return endpointsPath;
811
- }
812
- /**
813
- * Generate optimized endpoints files with nested folder structure (per-endpoint files)
814
- */
815
- async generateOptimizedEndpointsFile(endpointsPath, endpoints, _endpointImports, _allExportNames) {
816
- const logger = console;
817
- const outputDir = dirname(endpointsPath);
818
- const endpointsDir = join(outputDir, "endpoints");
819
- await mkdir(join(endpointsDir, "minimal"), { recursive: true });
820
- await mkdir(join(endpointsDir, "standard"), { recursive: true });
821
- await mkdir(join(endpointsDir, "full"), { recursive: true });
822
- const analyses = endpoints.map(({ key, construct }) => analyzeEndpoint(construct, key));
823
- const endpointImports = endpoints.map(({ key, path }) => {
824
- const tierDir = join(endpointsDir, "standard");
825
- const relativePath = relative(tierDir, path.relative);
826
- const importPath = relativePath.replace(/\.ts$/, ".js");
827
- return {
828
- exportName: key,
829
- importPath
830
- };
831
- });
832
- const summary = summarizeAnalysis(analyses);
833
- logger.log(`\n📊 Endpoint Analysis:`);
834
- logger.log(` Total: ${summary.total} endpoints`);
835
- logger.log(` - Minimal (near-raw-Hono): ${summary.byTier.minimal} endpoints`);
836
- logger.log(` - Standard (auth/services): ${summary.byTier.standard} endpoints`);
837
- logger.log(` - Full (audits/rls/rate-limit): ${summary.byTier.full} endpoints`);
838
- const files = generateEndpointFilesNested(analyses, endpointImports);
839
- for (const [filename, content] of Object.entries(files)) {
840
- const filePath = join(endpointsDir, filename);
841
- await mkdir(dirname(filePath), { recursive: true });
842
- await writeFile(filePath, content);
843
- }
844
- const endpointFiles = Object.keys(files).filter((f) => !f.endsWith("index.ts") && !f.endsWith("validators.ts")).length;
845
- const indexFiles = Object.keys(files).filter((f) => f.endsWith("index.ts")).length;
846
- logger.log(` Generated ${endpointFiles} endpoint files + ${indexFiles} index files + validators.ts`);
847
- return join(endpointsDir, "index.ts");
848
- }
849
- async generateAppFile(outputDir, context) {
850
- if (context.production?.enabled) return this.generateProductionAppFile(outputDir, context);
851
- const appFileName = "app.ts";
852
- const appPath = join(outputDir, appFileName);
853
- const runtime = runtimeFor(context, dirname(appPath));
854
- const telescopeEnabled = context.telescope?.enabled;
855
- const telescopeWebSocketEnabled = context.telescope?.websocket;
856
- const usesExternalTelescope = !!context.telescope?.telescopePath;
857
- const studioEnabled = context.studio?.enabled;
858
- const usesExternalStudio = !!context.studio?.studioPath;
859
- const studioFromDatabase = !usesExternalStudio && !!context.studio?.database;
860
- const telescopeFromSurface = !!context.surface?.module && !usesExternalTelescope;
861
- let telescopeImports = "";
862
- if (telescopeEnabled) if (telescopeFromSurface) telescopeImports = "import { createMiddleware, createUI } from '@geekmidas/telescope/hono';";
863
- else if (usesExternalTelescope) {
864
- const relativeTelescopePath = relative(dirname(appPath), context.telescope?.telescopePath);
865
- telescopeImports = `import ${context.telescope?.telescopeImportPattern} from '${relativeTelescopePath}';
866
- import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
867
- } else telescopeImports = `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
868
- import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
869
- let studioImports = "";
870
- if (studioEnabled) if (usesExternalStudio) {
871
- const relativeStudioPath = relative(dirname(appPath), context.studio?.studioPath);
872
- studioImports = `import ${context.studio?.studioImportPattern} from '${relativeStudioPath}';
873
- import { createStudioApp } from '@geekmidas/studio/server/hono';`;
874
- } else if (studioFromDatabase) {
875
- const dbSpecifier = importSpecifier(dirname(appPath), context.studio.database.specifier);
876
- studioImports = `import { snifferContext } from '@geekmidas/constructs';
877
- import { Direction, InMemoryMonitoringStorage, Studio } from '@geekmidas/studio';
878
- import { ${context.studio.database.exportName} as __studioDb } from '${dbSpecifier}';
879
- import { createStudioApp } from '@geekmidas/studio/server/hono';`;
880
- } else studioImports = "";
881
- const cors = corsFor(context.surface);
882
- let hooksImports = "";
883
- let beforeSetupCall = "";
884
- let afterSetupCall = "";
885
- if (context.hooks?.serverHooksPath) {
886
- const relativeHooksPath = relative(dirname(appPath), context.hooks.serverHooksPath);
887
- hooksImports = `import * as serverHooks from '${relativeHooksPath}';`;
888
- beforeSetupCall = `
889
- // Call beforeSetup hook if defined
890
- if (typeof serverHooks.beforeSetup === 'function') {
891
- await serverHooks.beforeSetup(honoApp, { envParser, logger });
892
- }
893
- `;
894
- afterSetupCall = `
895
- // Call afterSetup hook if defined
896
- if (typeof serverHooks.afterSetup === 'function') {
897
- await serverHooks.afterSetup(honoApp, { envParser, logger });
898
- }
899
- `;
900
- }
901
- const telescopeWebSocketSetupCode = telescopeWebSocketEnabled ? `
902
- // Setup WebSocket for real-time telescope updates
903
- try {
904
- const { createNodeWebSocket } = await import('@hono/node-ws');
905
- const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: honoApp });
906
- // Add WebSocket route directly to main app (sub-app routes don't support WS upgrade)
907
- honoApp.get('${context.telescope?.path}/ws', upgradeWebSocket(() => ({
908
- onOpen: (_event: Event, ws: any) => {
909
- telescope.addWsClient(ws);
910
- },
911
- onClose: (_event: Event, ws: any) => {
912
- telescope.removeWsClient(ws);
913
- },
914
- onMessage: (event: MessageEvent, ws: any) => {
915
- try {
916
- const data = JSON.parse(event.data);
917
- if (data.type === 'ping') {
918
- ws.send(JSON.stringify({ type: 'pong' }));
919
- }
920
- } catch {
921
- // Ignore invalid messages
922
- }
923
- },
924
- })));
925
- // Store injectWebSocket for server entry to call after serve()
926
- (honoApp as any).__injectWebSocket = injectWebSocket;
927
- logger.info('Telescope WebSocket enabled');
928
- } catch (e) {
929
- logger.warn({ error: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
930
- }
931
- ` : "";
932
- let telescopeSetup = "";
933
- if (telescopeEnabled) if (telescopeFromSurface || usesExternalTelescope) telescopeSetup = `
934
- ${telescopeWebSocketSetupCode}
935
- // Add telescope middleware (before endpoints to capture all requests)
936
- honoApp.use('*', createMiddleware(telescope));
937
-
938
- // Mount telescope UI
939
- const telescopeUI = createUI(telescope);
940
- honoApp.route('${context.telescope?.path}', telescopeUI);
941
- `;
942
- else telescopeSetup = `
943
- // Setup Telescope for debugging/monitoring
944
- const telescopeStorage = new InMemoryStorage({ maxEntries: ${context.telescope?.maxEntries} });
945
- const telescope = new Telescope({
946
- enabled: true,
947
- path: '${context.telescope?.path}',
948
- ignorePatterns: ${JSON.stringify(context.telescope?.ignore)},
949
- recordBody: ${context.telescope?.recordBody},
950
- storage: telescopeStorage,
951
- });
952
- ${telescopeWebSocketSetupCode}
953
- // Add telescope middleware (before endpoints to capture all requests)
954
- honoApp.use('*', createMiddleware(telescope));
955
-
956
- // Mount telescope UI
957
- const telescopeUI = createUI(telescope);
958
- honoApp.route('${context.telescope?.path}', telescopeUI);
959
- `;
960
- let studioSetup = "";
961
- if (studioEnabled && studioFromDatabase) studioSetup = `
962
- // Studio, built from the declared database. The client comes from the
963
- // construct, so what you inspect is by definition what the handlers write to.
964
- const studio = new Studio({
965
- monitoring: { storage: new InMemoryMonitoringStorage({ maxEntries: 100 }) },
966
- data: {
967
- db: await __studioDb.service.register({ envParser, context: snifferContext }),
968
- cursor: { field: 'id', direction: Direction.Desc },
969
- },
970
- enabled: true,
971
- });
972
-
973
- const studioApp = createStudioApp(studio);
974
- honoApp.route('${context.studio?.path}', studioApp);
975
- `;
976
- else if (studioEnabled && usesExternalStudio) studioSetup = `
977
- // Mount Studio data browser UI
978
- const studioApp = createStudioApp(studio);
979
- honoApp.route('${context.studio?.path}', studioApp);
980
- `;
981
- const content = `/**
982
- * Generated server application
983
- *
984
- * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY
985
- * The subscriber polling mechanism is not production-ready.
986
- * For production, use AWS Lambda with SQS/SNS event sources.
987
- */
988
- import { Hono } from 'hono';
989
- import type { Hono as HonoType } from 'hono';
990
- import { setupEndpoints } from './endpoints.js';
991
- import { setupSubscribers } from './subscribers.js';
992
- import { setupQueues } from './queues.js';
993
- import { setupCrons } from './crons.js';
994
- ${runtime.imports}
995
- ${telescopeImports}
996
- ${studioImports}
997
- ${hooksImports}
998
- ${cors.imports}
999
- ${context.storageDrivers?.imports ?? ""}
1000
-
1001
- ${runtime.bindings}
1002
- ${telescopeFromSurface ? "const telescope = __surface.telescope;" : ""}
1003
-
1004
- ${context.storageDrivers?.setup ? `// Which storage drivers exist is the entry point's decision: the scheme in
1005
- // each injected URL picks one, so no construct and no application module names
1006
- // a provider.
1007
- ${context.storageDrivers.setup}
1008
- ` : ""}
1009
- export interface ServerApp {
1010
- app: HonoType;
1011
- start: (options?: {
1012
- port?: number;
1013
- serve: (app: HonoType, port: number) => void | Promise<void>;
1014
- }) => Promise<void>;
1015
- }
1016
-
1017
- /**
1018
- * Create and configure the Hono application
1019
- *
1020
- * @param app - Optional Hono app instance to configure (creates new one if not provided)
1021
- * @param enableOpenApi - Enable OpenAPI documentation (default: true)
1022
- * @returns Server app with configured Hono app and start function
1023
- *
1024
- * @example
1025
- * // With Bun
1026
- * import { createApp } from './.gkm/server/app.js';
1027
- *
1028
- * const { app, start } = await createApp();
1029
- *
1030
- * await start({
1031
- * port: 3000,
1032
- * serve: (app, port) => {
1033
- * Bun.serve({ port, fetch: app.fetch });
1034
- * }
1035
- * });
1036
- *
1037
- * @example
1038
- * // With Node.js (using @hono/node-server)
1039
- * import { serve } from '@hono/node-server';
1040
- * import { createApp } from './.gkm/server/app.js';
1041
- *
1042
- * const { app, start } = await createApp();
1043
- *
1044
- * await start({
1045
- * port: 3000,
1046
- * serve: (app, port) => {
1047
- * serve({ fetch: app.fetch, port });
1048
- * }
1049
- * });
1050
- */
1051
- export async function createApp(app?: HonoType, enableOpenApi: boolean = true): Promise<ServerApp> {
1052
- const honoApp = app || new Hono();
1053
- ${telescopeSetup}${cors.setup}${beforeSetupCall}${studioSetup}
1054
- // Setup HTTP endpoints
1055
- await setupEndpoints(honoApp, envParser, logger, enableOpenApi);
1056
- ${afterSetupCall}
1057
-
1058
- return {
1059
- app: honoApp,
1060
- async start(options) {
1061
- if (!options?.serve) {
1062
- throw new Error(
1063
- 'serve function is required. Pass a serve function for your runtime:\\n' +
1064
- ' - Bun: (app, port) => Bun.serve({ port, fetch: app.fetch })\\n' +
1065
- ' - Node: (app, port) => serve({ fetch: app.fetch, port })'
1066
- );
1067
- }
1068
-
1069
- const port = options.port ?? 3000;
1070
-
1071
- // Start subscribers in background (non-blocking, local development only)
1072
- await setupSubscribers(envParser, logger).catch((error) => {
1073
- logger.error({ error }, 'Failed to start subscribers');
1074
- });
1075
-
1076
- // Start queue workers in background (non-blocking, local development only)
1077
- await setupQueues(envParser, logger).catch((error) => {
1078
- logger.error({ error }, 'Failed to start queue workers');
1079
- });
1080
-
1081
- // Schedule this app's crons. Caught like the others: a scheduler that
1082
- // cannot start is not a reason for the HTTP server not to.
1083
- await setupCrons(envParser, logger).catch((error) => {
1084
- logger.error({ error }, 'Failed to schedule crons');
1085
- });
1086
-
1087
- logger.info({ port }, 'Starting server');
1088
-
1089
- // Start HTTP server using provided serve function
1090
- await options.serve(honoApp, port);
1091
-
1092
- logger.info({ port }, 'Server started');
1093
- }
1094
- };
1095
- }
1096
-
1097
- // Default export for convenience
1098
- export default createApp;
1099
- `;
1100
- await writeFile(appPath, content);
1101
- return appPath;
1102
- }
1103
- /**
1104
- * One Lambda, one endpoint — and no environment import.
1105
- *
1106
- * The endpoint was built from its surface, so it carries the parser the
1107
- * adaptor needs. This used to read
1108
- * `import { envParser } from '../../config/env'`, a line the build wrote
1109
- * because a generator can print a module specifier and cannot print an
1110
- * object. Nothing has to be printed now, which is also why nothing has to be
1111
- * named in config.
1112
- */
1113
- generateAWSApiGatewayV1Handler(importPath, exportName, drivers) {
1114
- return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
1115
- import { ${exportName} } from '${importPath}';
1116
- ${drivers?.imports ?? ""}
1117
- ${drivers?.setup ? `\n// The handler registers the drivers its target needs.\n${drivers.setup}\n` : ""}
1118
- const adapter = new AmazonApiGatewayV1Endpoint(${exportName});
1119
-
1120
- export const handler = adapter.handler;
1121
- `;
1122
- }
1123
- /**
1124
- * One Lambda, one endpoint — and no environment import.
1125
- *
1126
- * The endpoint was built from its surface, so it carries the parser the
1127
- * adaptor needs. This used to read
1128
- * `import { envParser } from '../../config/env'`, a line the build wrote
1129
- * because a generator can print a module specifier and cannot print an
1130
- * object. Nothing has to be printed now, which is also why nothing has to be
1131
- * named in config.
1132
- */
1133
- generateAWSApiGatewayV2Handler(importPath, exportName, drivers) {
1134
- return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
1135
- import { ${exportName} } from '${importPath}';
1136
- ${drivers?.imports ?? ""}
1137
- ${drivers?.setup ? `\n// The handler registers the drivers its target needs.\n${drivers.setup}\n` : ""}
1138
- const adapter = new AmazonApiGatewayV2Endpoint(${exportName});
1139
-
1140
- export const handler = adapter.handler;
1141
- `;
1142
- }
1143
- generateServerHandler(importPath, exportName) {
1144
- return `import { ${exportName} } from '${importPath}';
1145
-
1146
- // Server handler - implement based on your server framework
1147
- export const handler = ${exportName};
1148
- `;
1149
- }
1150
- /**
1151
- * Generate a production-optimized app.ts file
1152
- * No dev tools (Telescope, Studio, WebSocket), includes health checks and graceful shutdown
1153
- */
1154
- async generateProductionAppFile(outputDir, context) {
1155
- const appFileName = "app.ts";
1156
- const appPath = join(outputDir, appFileName);
1157
- const runtime = runtimeFor(context, dirname(appPath));
1158
- const production = context.production;
1159
- const healthCheckPath = production.healthCheck;
1160
- const enableGracefulShutdown = production.gracefulShutdown;
1161
- const enableOpenApi = production.openapi;
1162
- const includeSubscribers = production.subscribers === "include";
1163
- const cors = corsFor(context.surface);
1164
- let hooksImports = "";
1165
- let beforeSetupCall = "";
1166
- let afterSetupCall = "";
1167
- if (context.hooks?.serverHooksPath) {
1168
- const relativeHooksPath = relative(dirname(appPath), context.hooks.serverHooksPath);
1169
- hooksImports = `import * as serverHooks from '${relativeHooksPath}';`;
1170
- beforeSetupCall = `
1171
- // Call beforeSetup hook if defined
1172
- if (typeof serverHooks.beforeSetup === 'function') {
1173
- await serverHooks.beforeSetup(honoApp, { envParser, logger });
1174
- }
1175
- `;
1176
- afterSetupCall = `
1177
- // Call afterSetup hook if defined
1178
- if (typeof serverHooks.afterSetup === 'function') {
1179
- await serverHooks.afterSetup(honoApp, { envParser, logger });
1180
- }
1181
- `;
1182
- }
1183
- const subscriberSetup = includeSubscribers ? `
1184
- // Start subscribers in background
1185
- await setupSubscribers(envParser, logger).catch((error) => {
1186
- logger.error({ error }, 'Failed to start subscribers');
1187
- });
1188
-
1189
- // Start queue workers in background
1190
- await setupQueues(envParser, logger).catch((error) => {
1191
- logger.error({ error }, 'Failed to start queue workers');
1192
- });
1193
-
1194
- // Schedule this app's crons. Caught like the others: a scheduler that
1195
- // cannot start is not a reason for the HTTP server not to.
1196
- await setupCrons(envParser, logger).catch((error) => {
1197
- logger.error({ error }, 'Failed to schedule crons');
1198
- });
1199
- ` : "";
1200
- const subscriberImport = includeSubscribers ? `import { setupSubscribers } from './subscribers.js';
1201
- import { setupQueues } from './queues.js';
1202
- import { setupCrons } from './crons.js';` : "";
1203
- const gracefulShutdownCode = enableGracefulShutdown ? `
1204
- // Graceful shutdown handling
1205
- let isShuttingDown = false;
1206
-
1207
- const shutdown = async () => {
1208
- if (isShuttingDown) return;
1209
- isShuttingDown = true;
1210
- logger.info('Graceful shutdown initiated');
1211
- // Allow in-flight requests to complete (30s timeout)
1212
- setTimeout(() => process.exit(0), 30000);
1213
- };
1214
-
1215
- process.on('SIGTERM', shutdown);
1216
- process.on('SIGINT', shutdown);
1217
- ` : "";
1218
- const endpointsImportPath = production.optimizedHandlers ? "./endpoints/index.js" : "./endpoints.js";
1219
- const content = `/**
1220
- * Generated production server application
1221
- *
1222
- * This is a production-optimized build without dev tools.
1223
- * - No Telescope debugging dashboard
1224
- * - No Studio database browser
1225
- * - No WebSocket updates
1226
- * - Includes health checks and graceful shutdown
1227
- */
1228
- import { Hono } from 'hono';
1229
- import type { Hono as HonoType } from 'hono';
1230
- import { setupEndpoints } from '${endpointsImportPath}';
1231
- ${subscriberImport}
1232
- ${runtime.imports}
1233
- ${runtime.bindings}
1234
- ${hooksImports}
1235
- ${cors.imports}
1236
- ${context.storageDrivers?.imports ?? ""}
1237
-
1238
- ${context.storageDrivers?.setup ? `// The entry point registers the drivers its target needs.
1239
- ${context.storageDrivers.setup}
1240
- ` : ""}
1241
- export interface ServerApp {
1242
- app: HonoType;
1243
- start: (options?: {
1244
- port?: number;
1245
- serve: (app: HonoType, port: number) => void | Promise<void>;
1246
- }) => Promise<void>;
1247
- }
1248
-
1249
- /**
1250
- * Create and configure the production Hono application
1251
- */
1252
- export async function createApp(app?: HonoType): Promise<ServerApp> {
1253
- const honoApp = app || new Hono();
1254
-
1255
- // Health check endpoint (always first)
1256
- honoApp.get('${healthCheckPath}', (c) => c.json({ status: 'ok', timestamp: Date.now() }));
1257
- honoApp.get('/ready', (c) => c.json({ ready: true }));
1258
- ${cors.setup}${beforeSetupCall}
1259
- // Setup HTTP endpoints (OpenAPI: ${enableOpenApi})
1260
- await setupEndpoints(honoApp, envParser, logger, ${enableOpenApi});
1261
- ${afterSetupCall}
1262
- return {
1263
- app: honoApp,
1264
- async start(options) {
1265
- if (!options?.serve) {
1266
- throw new Error(
1267
- 'serve function is required. Pass a serve function for your runtime:\\n' +
1268
- ' - Bun: (app, port) => Bun.serve({ port, fetch: app.fetch })\\n' +
1269
- ' - Node: (app, port) => serve({ fetch: app.fetch, port })'
1270
- );
1271
- }
1272
-
1273
- const port = options.port ?? Number(process.env.PORT) ?? 3000;
1274
- ${gracefulShutdownCode}${subscriberSetup}
1275
- logger.info({ port }, 'Starting production server');
1276
-
1277
- // Start HTTP server using provided serve function
1278
- await options.serve(honoApp, port);
1279
-
1280
- logger.info({ port }, 'Production server started');
1281
- }
1282
- };
1283
- }
1284
-
1285
- // Default export for convenience
1286
- export default createApp;
1287
- `;
1288
- await writeFile(appPath, content);
1289
- await this.generateProductionServerEntry(outputDir);
1290
- return appPath;
1291
- }
1292
- /**
1293
- * Generate production server.ts entry point
1294
- */
1295
- async generateProductionServerEntry(outputDir) {
1296
- const serverPath = join(outputDir, "server.ts");
1297
- const content = `#!/usr/bin/env node
1298
- /**
1299
- * Production server entry point
1300
- * Generated by 'gkm build --provider server --production'
1301
- */
1302
- import { serve } from '@hono/node-server';
1303
- import { createApp } from './app.js';
1304
-
1305
- const port = Number(process.env.PORT) || 3000;
1306
-
1307
- const { start } = await createApp();
1308
-
1309
- await start({
1310
- port,
1311
- serve: (app, port) => { serve({ fetch: app.fetch, port }); },
1312
- });
1313
- `;
1314
- await writeFile(serverPath, content);
1315
- }
1316
- };
1317
-
1318
- //#endregion
1319
- //#region src/generators/OpenApiTsGenerator.ts
1320
- /**
1321
- * Generates TypeScript OpenAPI module from endpoints.
1322
- * Outputs:
1323
- * - securitySchemes: typed security scheme definitions
1324
- * - endpointAuth: runtime map of endpoints to auth requirements
1325
- * - paths: TypeScript interface for type-safe fetcher
1326
- * - schema interfaces: reusable TypeScript types from Zod/Valibot schemas
1327
- */
1328
- var OpenApiTsGenerator = class {
1329
- async generate(endpoints, options = {}) {
1330
- const { title = "API", version = "1.0.0", description } = options;
1331
- const endpointInfos = await this.extractEndpointInfos(endpoints);
1332
- const securitySchemes = this.collectSecuritySchemes(endpointInfos);
1333
- const endpointAuth = this.buildEndpointAuthMap(endpointInfos);
1334
- const schemaInterfaces = await this.generateSchemaInterfaces(endpointInfos);
1335
- const pathsInterface = await this.generatePathsInterface(endpointInfos);
1336
- return this.buildModule({
1337
- title,
1338
- version,
1339
- description,
1340
- securitySchemes,
1341
- endpointAuth,
1342
- schemaInterfaces,
1343
- pathsInterface
1344
- });
1345
- }
1346
- async extractEndpointInfos(endpoints) {
1347
- return endpoints.map((ep) => {
1348
- const route = ep.route.replace(/:(\w+)/g, "{$1}");
1349
- const method = ep.method.toUpperCase();
1350
- const securityScheme = ep.authorizer?.securityScheme;
1351
- return {
1352
- endpoint: `${method} ${route}`,
1353
- route,
1354
- method,
1355
- authorizerName: ep.authorizer?.name ?? null,
1356
- authorizerType: ep.authorizer?.type ?? null,
1357
- securityScheme: securityScheme ?? null,
1358
- input: ep.input,
1359
- output: ep.outputSchema,
1360
- description: ep.description,
1361
- tags: ep.tags,
1362
- operationId: ep.operationId,
1363
- responseType: ep.responseType ?? "application/json"
1364
- };
1365
- });
1366
- }
1367
- collectSecuritySchemes(endpointInfos) {
1368
- const schemes = /* @__PURE__ */ new Map();
1369
- for (const info of endpointInfos) if (info.authorizerName && !schemes.has(info.authorizerName)) {
1370
- const scheme = info.securityScheme ?? (info.authorizerType ? this.mapAuthorizerToSecurityScheme(info.authorizerType, info.authorizerName) : null);
1371
- if (scheme) schemes.set(info.authorizerName, {
1372
- name: info.authorizerName,
1373
- type: scheme.type,
1374
- scheme
1375
- });
1376
- }
1377
- return Array.from(schemes.values());
1378
- }
1379
- mapAuthorizerToSecurityScheme(type, _name) {
1380
- switch (type.toLowerCase()) {
1381
- case "jwt":
1382
- case "bearer": return {
1383
- type: "http",
1384
- scheme: "bearer",
1385
- bearerFormat: "JWT"
1386
- };
1387
- case "iam":
1388
- case "aws-sigv4":
1389
- case "sigv4": return {
1390
- type: "apiKey",
1391
- in: "header",
1392
- name: "Authorization",
1393
- "x-amazon-apigateway-authtype": "awsSigv4"
1394
- };
1395
- case "apikey":
1396
- case "api-key": return {
1397
- type: "apiKey",
1398
- in: "header",
1399
- name: "X-API-Key"
1400
- };
1401
- case "oauth2": return {
1402
- type: "oauth2",
1403
- flows: {}
1404
- };
1405
- case "oidc":
1406
- case "openidconnect": return {
1407
- type: "openIdConnect",
1408
- openIdConnectUrl: ""
1409
- };
1410
- default: return {
1411
- type: "http",
1412
- scheme: "bearer"
1413
- };
1414
- }
1415
- }
1416
- buildEndpointAuthMap(endpointInfos) {
1417
- const authMap = {};
1418
- for (const info of endpointInfos) authMap[info.endpoint] = info.authorizerName;
1419
- return authMap;
1420
- }
1421
- async generateSchemaInterfaces(endpointInfos) {
1422
- const interfaces = [];
1423
- const generatedNames = /* @__PURE__ */ new Set();
1424
- const collectedDefs = /* @__PURE__ */ new Map();
1425
- for (const info of endpointInfos) {
1426
- const baseName = this.getSchemaBaseName(info);
1427
- if (info.input?.body) {
1428
- const name = await this.getSchemaName(info.input.body, `${baseName}Input`);
1429
- if (!generatedNames.has(name)) {
1430
- const schema = await this.schemaToInterfaceWithDefs(info.input.body, name, collectedDefs);
1431
- if (schema) {
1432
- interfaces.push(schema);
1433
- generatedNames.add(name);
1434
- }
1435
- }
1436
- }
1437
- if (info.input?.params) {
1438
- const name = await this.getSchemaName(info.input.params, `${baseName}Params`);
1439
- if (!generatedNames.has(name)) {
1440
- const schema = await this.schemaToInterfaceWithDefs(info.input.params, name, collectedDefs);
1441
- if (schema) {
1442
- interfaces.push(schema);
1443
- generatedNames.add(name);
1444
- }
1445
- }
1446
- }
1447
- if (info.input?.query) {
1448
- const name = await this.getSchemaName(info.input.query, `${baseName}Query`);
1449
- if (!generatedNames.has(name)) {
1450
- const schema = await this.schemaToInterfaceWithDefs(info.input.query, name, collectedDefs);
1451
- if (schema) {
1452
- interfaces.push(schema);
1453
- generatedNames.add(name);
1454
- }
1455
- }
1456
- }
1457
- if (info.output) {
1458
- const name = await this.getSchemaName(info.output, `${baseName}Output`);
1459
- if (!generatedNames.has(name)) {
1460
- const schema = await this.schemaToInterfaceWithDefs(info.output, name, collectedDefs);
1461
- if (schema) {
1462
- interfaces.push(schema);
1463
- generatedNames.add(name);
1464
- }
1465
- }
1466
- }
1467
- }
1468
- const registrySchemas = await getRegisteredZodJsonSchemas();
1469
- for (const [rawName, rawSchema] of Object.entries(registrySchemas)) {
1470
- const defName = this.pascalCase(rawName);
1471
- if (collectedDefs.has(defName) || generatedNames.has(defName)) continue;
1472
- const { id: _id, $defs: _defs,...rest } = rawSchema;
1473
- collectedDefs.set(defName, rest);
1474
- }
1475
- for (const [defName, defSchema] of collectedDefs) if (!generatedNames.has(defName)) {
1476
- const interfaceStr = this.jsonSchemaToInterface(defSchema, defName);
1477
- interfaces.push(interfaceStr);
1478
- generatedNames.add(defName);
1479
- }
1480
- return interfaces.join("\n\n");
1481
- }
1482
- /**
1483
- * Get the name for a schema, using metadata `id` if available,
1484
- * otherwise falling back to the provided default name.
1485
- */
1486
- async getSchemaName(schema, defaultName) {
1487
- try {
1488
- const metadata = await getSchemaMetadata(schema);
1489
- if (metadata?.id) return this.pascalCase(metadata.id);
1490
- } catch {}
1491
- return defaultName;
1492
- }
1493
- getSchemaBaseName(info) {
1494
- if (info.operationId) return this.pascalCase(info.operationId);
1495
- const routeParts = info.route.replace(/[{}]/g, "").split("/").filter(Boolean).map((part) => this.pascalCase(part));
1496
- return `${this.pascalCase(info.method.toLowerCase())}${routeParts.join("")}`;
1497
- }
1498
- pascalCase(str) {
1499
- return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase());
1500
- }
1501
- /**
1502
- * Convert schema to interface while collecting $defs for nested schemas
1503
- * with .meta({ id: 'X' }).
1504
- */
1505
- async schemaToInterfaceWithDefs(schema, name, collectedDefs) {
1506
- try {
1507
- const vendor = schema["~standard"]?.vendor;
1508
- if (!vendor || !(vendor in StandardSchemaJsonSchema)) return null;
1509
- const toJsonSchema = StandardSchemaJsonSchema[vendor];
1510
- const jsonSchema = await toJsonSchema(schema);
1511
- if (!jsonSchema) return null;
1512
- if (jsonSchema.$defs && typeof jsonSchema.$defs === "object") {
1513
- for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) if (!collectedDefs.has(defName)) {
1514
- const { id,...schemaWithoutId } = defSchema;
1515
- collectedDefs.set(defName, schemaWithoutId);
1516
- }
1517
- }
1518
- const { $defs,...schemaWithoutDefs } = jsonSchema;
1519
- const ref = schemaWithoutDefs.$ref;
1520
- if (ref && Object.keys(schemaWithoutDefs).every((k) => k === "$ref" || k === "$schema")) {
1521
- const target = ref.split("/").pop();
1522
- return target === name ? null : `export type ${name} = ${target};`;
1523
- }
1524
- return this.jsonSchemaToInterface(schemaWithoutDefs, name);
1525
- } catch {
1526
- return null;
1527
- }
1528
- }
1529
- jsonSchemaToInterface(schema, name) {
1530
- if (schema.type !== "object" || !schema.properties) {
1531
- const typeStr = this.jsonSchemaTypeToTs(schema);
1532
- return `export type ${name} = ${typeStr};`;
1533
- }
1534
- const props = [];
1535
- const required = new Set(schema.required || []);
1536
- for (const [propName, propSchema] of Object.entries(schema.properties)) {
1537
- const isRequired = required.has(propName);
1538
- const typeStr = this.jsonSchemaTypeToTs(propSchema);
1539
- const optionalMark = isRequired ? "" : "?";
1540
- props.push(` ${propName}${optionalMark}: ${typeStr};`);
1541
- }
1542
- return `export interface ${name} {\n${props.join("\n")}\n}`;
1543
- }
1544
- jsonSchemaTypeToTs(schema) {
1545
- if (!schema) return "unknown";
1546
- if (schema.$ref) {
1547
- const refName = schema.$ref.split("/").pop() || "unknown";
1548
- return refName;
1549
- }
1550
- if (schema.anyOf) return schema.anyOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
1551
- if (schema.oneOf) return schema.oneOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
1552
- if (schema.allOf) return schema.allOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" & ");
1553
- switch (schema.type) {
1554
- case "string":
1555
- if (schema.enum) return schema.enum.map((e) => `'${e}'`).join(" | ");
1556
- return "string";
1557
- case "number":
1558
- case "integer": return "number";
1559
- case "boolean": return "boolean";
1560
- case "null": return "null";
1561
- case "array":
1562
- if (schema.items) return `Array<${this.jsonSchemaTypeToTs(schema.items)}>`;
1563
- return "Array<unknown>";
1564
- case "object":
1565
- if (schema.properties) {
1566
- const props = [];
1567
- const required = new Set(schema.required || []);
1568
- for (const [propName, propSchema] of Object.entries(schema.properties)) {
1569
- const isRequired = required.has(propName);
1570
- const typeStr = this.jsonSchemaTypeToTs(propSchema);
1571
- const optionalMark = isRequired ? "" : "?";
1572
- props.push(`${propName}${optionalMark}: ${typeStr}`);
1573
- }
1574
- return `{ ${props.join("; ")} }`;
1575
- }
1576
- if (schema.additionalProperties) {
1577
- const valueType = this.jsonSchemaTypeToTs(schema.additionalProperties);
1578
- return `Record<string, ${valueType}>`;
1579
- }
1580
- return "Record<string, unknown>";
1581
- default: return "unknown";
1582
- }
1583
- }
1584
- async generatePathsInterface(endpointInfos) {
1585
- const pathGroups = /* @__PURE__ */ new Map();
1586
- for (const info of endpointInfos) {
1587
- const existing = pathGroups.get(info.route) || [];
1588
- existing.push(info);
1589
- pathGroups.set(info.route, existing);
1590
- }
1591
- const pathEntries = [];
1592
- for (const [route, infos] of pathGroups) {
1593
- const methodEntries = [];
1594
- for (const info of infos) {
1595
- const methodDef = await this.generateMethodDefinition(info);
1596
- methodEntries.push(` ${info.method.toLowerCase()}: ${methodDef};`);
1597
- }
1598
- const firstWithParams = infos.find((i) => i.input?.params);
1599
- let paramsEntry = "";
1600
- if (firstWithParams?.input?.params) {
1601
- const paramsName = await this.getSchemaName(firstWithParams.input.params, `${this.getSchemaBaseName(firstWithParams)}Params`);
1602
- paramsEntry = `\n parameters: {\n path: ${paramsName};\n };`;
1603
- }
1604
- pathEntries.push(` '${route}': {${paramsEntry}\n${methodEntries.join("\n")}\n };`);
1605
- }
1606
- return `export interface paths {\n${pathEntries.join("\n")}\n}`;
1607
- }
1608
- async generateMethodDefinition(info) {
1609
- const parts = [];
1610
- const baseName = this.getSchemaBaseName(info);
1611
- if (info.input?.body) {
1612
- const bodyName = await this.getSchemaName(info.input.body, `${baseName}Input`);
1613
- parts.push(`requestBody: {
1614
- content: {
1615
- 'application/json': ${bodyName};
1616
- };
1617
- }`);
1618
- }
1619
- if (info.input?.query) {
1620
- const queryName = await this.getSchemaName(info.input.query, `${baseName}Query`);
1621
- parts.push(`parameters: {
1622
- query: ${queryName};
1623
- }`);
1624
- }
1625
- const outputName = info.output ? await this.getSchemaName(info.output, `${baseName}Output`) : "unknown";
1626
- parts.push(`responses: {
1627
- 200: {
1628
- content: {
1629
- '${info.responseType}': ${outputName};
1630
- };
1631
- };
1632
- }`);
1633
- return `{\n ${parts.join(";\n ")};\n }`;
1634
- }
1635
- buildModule(params) {
1636
- const { title, version, description, securitySchemes, endpointAuth, schemaInterfaces, pathsInterface } = params;
1637
- const securitySchemesObj = securitySchemes.reduce((acc, s) => {
1638
- acc[s.name] = s.scheme;
1639
- return acc;
1640
- }, {});
1641
- const schemeNames = securitySchemes.map((s) => `'${s.name}'`).join(" | ");
1642
- const hasSecuritySchemes = schemeNames.length > 0;
1643
- const createApiSection = hasSecuritySchemes ? `
1644
- // ============================================================
1645
- // API Client Factory
1646
- // ============================================================
1647
-
1648
- import {
1649
- createAuthAwareFetcher,
1650
- type AuthStrategy,
1651
- } from '@geekmidas/client/auth-fetcher';
1652
- import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
1653
- import type { QueryClient } from '@tanstack/react-query';
1654
-
1655
- /**
1656
- * Options for creating the API client.
1657
- */
1658
- export interface CreateApiOptions {
1659
- /** Base URL for all API requests (required) */
1660
- baseURL: string;
1661
- /** Auth strategies for each security scheme used in this API */
1662
- authStrategies: Record<SecuritySchemeId, AuthStrategy>;
1663
- /** Optional React Query client instance */
1664
- queryClient?: QueryClient;
1665
- /** Optional request interceptor */
1666
- onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
1667
- }
1668
-
1669
- /**
1670
- * Create a type-safe API client with authentication and React Query hooks.
1671
- *
1672
- * @example
1673
- * \`\`\`typescript
1674
- * const api = createApi({
1675
- * baseURL: 'https://api.example.com',
1676
- * authStrategies: {
1677
- * jwt: { type: 'bearer', tokenProvider },
1678
- * },
1679
- * });
1680
- *
1681
- * // Imperative fetch
1682
- * const user = await api('GET /users/{id}', { params: { id: '123' } });
1683
- *
1684
- * // React Query hooks
1685
- * const { data } = api.useQuery('GET /users/{id}', { params: { id: '123' } });
1686
- * const mutation = api.useMutation('POST /users');
1687
- * \`\`\`
1688
- */
1689
- export function createApi(options: CreateApiOptions) {
1690
- const fetcher = createAuthAwareFetcher<paths, typeof endpointAuth, typeof securitySchemes>({
1691
- baseURL: options.baseURL,
1692
- endpointAuth,
1693
- securitySchemes,
1694
- authStrategies: options.authStrategies,
1695
- onRequest: options.onRequest,
1696
- });
1697
-
1698
- const hooks = createEndpointHooks<paths>(fetcher, { queryClient: options.queryClient });
1699
-
1700
- return Object.assign(fetcher, hooks);
1701
- }
1702
- ` : `
1703
- // ============================================================
1704
- // API Client Factory
1705
- // ============================================================
1706
-
1707
- import { createTypedFetcher, type FetcherOptions } from '@geekmidas/client/fetcher';
1708
- import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
1709
- import type { QueryClient } from '@tanstack/react-query';
1710
-
1711
- /**
1712
- * Options for creating the API client.
1713
- */
1714
- export interface CreateApiOptions extends Omit<FetcherOptions, 'baseURL'> {
1715
- /** Base URL for all API requests (required) */
1716
- baseURL: string;
1717
- /** Optional React Query client instance */
1718
- queryClient?: QueryClient;
1719
- }
1720
-
1721
- /**
1722
- * Create a type-safe API client with React Query hooks.
1723
- *
1724
- * @example
1725
- * \`\`\`typescript
1726
- * const api = createApi({
1727
- * baseURL: 'https://api.example.com',
1728
- * });
1729
- *
1730
- * // Imperative fetch
1731
- * const data = await api('GET /health');
1732
- *
1733
- * // React Query hooks
1734
- * const { data } = api.useQuery('GET /health');
1735
- * \`\`\`
1736
- */
1737
- export function createApi(options: CreateApiOptions) {
1738
- const { queryClient, ...fetcherOptions } = options;
1739
- const request = createTypedFetcher<paths>(fetcherOptions);
1740
-
1741
- const hooks = createEndpointHooks<paths>(request, { queryClient });
1742
-
1743
- return Object.assign(request, hooks);
1744
- }
1745
- `;
1746
- return `// Auto-generated by @geekmidas/cli - DO NOT EDIT
1747
-
1748
- // ============================================================
1749
- // Security Scheme Type
1750
- // ============================================================
1751
-
1752
- interface SecuritySchemeObject {
1753
- type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
1754
- description?: string;
1755
- name?: string;
1756
- in?: 'query' | 'header' | 'cookie';
1757
- scheme?: string;
1758
- bearerFormat?: string;
1759
- flows?: Record<string, unknown>;
1760
- openIdConnectUrl?: string;
1761
- [key: string]: unknown;
1762
- }
1763
-
1764
- // ============================================================
1765
- // API Info
1766
- // ============================================================
1767
-
1768
- export const apiInfo = {
1769
- title: '${title}',
1770
- version: '${version}',${description ? `\n description: '${description.replace(/'/g, "\\'")}',` : ""}
1771
- } as const;
1772
-
1773
- // ============================================================
1774
- // Security Schemes
1775
- // ============================================================
1776
-
1777
- /**
1778
- * Available security schemes for this API.
1779
- * Maps authorizer names to OpenAPI security scheme definitions.
1780
- */
1781
- export const securitySchemes = ${JSON.stringify(securitySchemesObj, null, 2).replace(/"([a-zA-Z_$][a-zA-Z0-9_$]*)":/g, "$1:")} as const satisfies Record<string, SecuritySchemeObject>;
1782
-
1783
- export type SecuritySchemeId = ${schemeNames || "never"};
1784
-
1785
- // ============================================================
1786
- // Endpoint Authentication Map
1787
- // ============================================================
1788
-
1789
- /**
1790
- * Runtime map of endpoints to their required authentication scheme.
1791
- * \`null\` indicates a public endpoint (no auth required).
1792
- */
1793
- export const endpointAuth = ${JSON.stringify(endpointAuth, null, 2).replace(/"([^"]+)":/g, "'$1':")} as const satisfies Record<string, SecuritySchemeId | null>;
1794
-
1795
- export type EndpointString = keyof typeof endpointAuth;
1796
-
1797
- export type AuthenticatedEndpoint = {
1798
- [K in EndpointString]: typeof endpointAuth[K] extends null ? never : K;
1799
- }[EndpointString];
1800
-
1801
- export type PublicEndpoint = {
1802
- [K in EndpointString]: typeof endpointAuth[K] extends null ? K : never;
1803
- }[EndpointString];
1804
-
1805
- // ============================================================
1806
- // Schema Definitions
1807
- // ============================================================
1808
-
1809
- ${schemaInterfaces}
1810
-
1811
- // ============================================================
1812
- // OpenAPI Paths
1813
- // ============================================================
1814
-
1815
- ${pathsInterface}
1816
- ${createApiSection}
1817
- `;
1818
- }
1819
- };
1820
-
1821
- //#endregion
1822
- //#region src/workspace/client-generator.ts
1823
- /**
1824
- * Normalize routes to an array of patterns.
1825
- * Handles string, string[], and PartitionedRoutes (extracts paths).
1826
- * @internal Exported for use in dev command
1827
- */
1828
- function normalizeRoutes(routes) {
1829
- if (!routes) return [];
1830
- if (isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
1831
- return Array.isArray(routes) ? routes : [routes];
1832
- }
1833
-
1834
- //#endregion
1835
- //#region src/openapi.ts
1836
- /**
1837
- * Default output path for generated OpenAPI client (used for single-app configs)
1838
- */
1839
- const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
1840
- /**
1841
- * Where a surface's generated client lands.
1842
- *
1843
- * Named from the surface, so `new RestApi('Webhooks')` writes
1844
- * `.gkm/openapi/webhooks.ts` — the same kebab form that gives it its container
1845
- * name and its `WEBHOOKS_URL`.
1846
- */
1847
- function openApiPathFor(surfaceId) {
1848
- return `./.gkm/openapi/${kebabCase(surfaceId)}.ts`;
1849
- }
1850
- /**
1851
- * Resolve OpenAPI config from GkmConfig
1852
- */
1853
- function resolveOpenApiConfig(config) {
1854
- if (config.openapi === false) return { enabled: false };
1855
- if (config.openapi === true || config.openapi === void 0) return {
1856
- enabled: true,
1857
- title: "API Documentation",
1858
- version: "1.0.0",
1859
- description: "Auto-generated API documentation from endpoints"
1860
- };
1861
- return {
1862
- enabled: config.openapi.enabled !== false,
1863
- title: config.openapi.title || "API Documentation",
1864
- version: config.openapi.version || "1.0.0",
1865
- description: config.openapi.description || "Auto-generated API documentation from endpoints"
1866
- };
1867
- }
1868
- /**
1869
- * Load endpoints from a glob, then generate.
1870
- *
1871
- * For the callers that have no endpoints in hand — `gkm openapi`, and `gkm dev`
1872
- * regenerating on reload. The glob is the app's derived one — the conventional
1873
- * directories under it — not a `routes` field anybody wrote.
1874
- */
1875
- async function generateOpenApiFrom(routes, options = {}) {
1876
- const loaded = await new EndpointGenerator().load(routes, void 0, options.bustCache);
1877
- return generateOpenApi(loaded.map(({ construct }) => construct), options);
1878
- }
1879
- /**
1880
- * Generate an OpenAPI spec for each surface these endpoints name.
1881
- *
1882
- * Takes the endpoints, not a glob to find them with. The build has already
1883
- * loaded every one of them to generate handlers, so globbing again was a second
1884
- * discovery pass over the same files — and the reason this function needed a
1885
- * `routes` to be told where to look, which is how a retired config field stayed
1886
- * load-bearing.
1887
- *
1888
- * @returns What was written, or null if disabled or there were none
1889
- */
1890
- async function generateOpenApi(endpoints, options = {}) {
1891
- const logger = options.silent ? { log: () => {} } : console;
1892
- const openApiConfig = resolveOpenApiConfig({ openapi: options.openapi });
1893
- if (!openApiConfig.enabled) return null;
1894
- if (endpoints.length === 0) {
1895
- logger.log("No valid endpoints found for OpenAPI generation");
1896
- return null;
1897
- }
1898
- const bySurface = /* @__PURE__ */ new Map();
1899
- for (const endpoint of endpoints) {
1900
- const owner = endpoint.owner ?? endpoint.surface?.id;
1901
- if (!owner) continue;
1902
- const existing = bySurface.get(owner);
1903
- if (existing) existing.push(endpoint);
1904
- else bySurface.set(owner, [endpoint]);
1905
- }
1906
- if (bySurface.size === 0) {
1907
- logger.log("No endpoints named a surface, so no OpenAPI was generated");
1908
- return null;
1909
- }
1910
- const tsGenerator = new OpenApiTsGenerator();
1911
- const written = [];
1912
- for (const [surfaceId, surfaceEndpoints] of bySurface) {
1913
- const relative$1 = openApiPathFor(surfaceId);
1914
- const outputPath = join(process.cwd(), relative$1);
1915
- await mkdir(dirname(outputPath), { recursive: true });
1916
- const tsContent = await tsGenerator.generate(surfaceEndpoints, {
1917
- title: openApiConfig.title ?? surfaceId,
1918
- version: openApiConfig.version,
1919
- description: openApiConfig.description
1920
- });
1921
- await writeFile(outputPath, tsContent);
1922
- written.push(relative$1);
1923
- logger.log(`📄 OpenAPI client generated: ${relative$1} (${surfaceEndpoints.length} endpoints)`);
1924
- }
1925
- return {
1926
- outputPath: join(process.cwd(), written[0]),
1927
- outputPaths: written.map((r) => join(process.cwd(), r)),
1928
- endpointCount: endpoints.length
1929
- };
1930
- }
1931
- async function openapiCommand(options = {}) {
1932
- const logger = console;
1933
- try {
1934
- const loadedConfig = await loadWorkspaceConfig(options.cwd);
1935
- if (loadedConfig.type === "single") {
1936
- const config = loadedConfig.raw;
1937
- if (!config.openapi) config.openapi = { enabled: true };
1938
- const result = await generateOpenApiFrom(config.constructs, { openapi: config.openapi });
1939
- if (result) logger.log(`Found ${result.endpointCount} endpoints`);
1940
- } else {
1941
- const { workspace } = loadedConfig;
1942
- const workspaceRoot = workspace.root;
1943
- const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend" && app.openapi !== false && (typeof app.openapi !== "object" || app.openapi.enabled !== false));
1944
- if (backendApps.length === 0) {
1945
- logger.log("No backend apps with OpenAPI enabled found");
1946
- return;
1947
- }
1948
- if (options.app) {
1949
- const entry = backendApps.find(([name]) => name === options.app);
1950
- if (!entry) throw new Error(`App "${options.app}" not found or has OpenAPI disabled`);
1951
- const [appName, app] = entry;
1952
- const result = await generateOpenApiForApp(workspaceRoot, appName, app);
1953
- if (result) logger.log(`📄 [${appName}] Generated OpenAPI (${result.endpointCount} endpoints)`);
1954
- return;
1955
- }
1956
- for (const [appName, app] of backendApps) {
1957
- const appPath = join(workspaceRoot, app.path);
1958
- if (resolve(appPath) === resolve(workspaceRoot)) {
1959
- const result = await generateOpenApiForApp(workspaceRoot, appName, app, false);
1960
- if (result) logger.log(`Found ${result.endpointCount} endpoints`);
1961
- continue;
1962
- }
1963
- await runOpenApiInSubprocess(appPath, appName);
1964
- }
1965
- }
1966
- } catch (error) {
1967
- throw new Error(`OpenAPI generation failed: ${error.message}`);
1968
- }
1969
- }
1970
- /**
1971
- * Generate OpenAPI for a single named app within a workspace.
1972
- * Runs in-process. The caller is responsible for ensuring `process.cwd()`
1973
- * is the app's directory so tsx loads the app's tsconfig path aliases.
1974
- */
1975
- async function generateOpenApiForApp(workspaceRoot, _appName, app, silent = true) {
1976
- if (app.type !== "backend") return null;
1977
- const appPath = join(workspaceRoot, app.path);
1978
- const globs = [join(appPath, "**/*.ts")];
1979
- return generateOpenApiFrom(globs, {
1980
- openapi: app.openapi ?? { enabled: true },
1981
- silent
1982
- });
1983
- }
1984
- /**
1985
- * Resolve the gkm bin path. Tests can override via `GKM_BIN_PATH` env var
1986
- * to avoid depending on the built dist.
1987
- */
1988
- function resolveGkmBinPath() {
1989
- if (process.env.GKM_BIN_PATH) return process.env.GKM_BIN_PATH;
1990
- return fileURLToPath(new URL("../bin/gkm.mjs", import.meta.url));
1991
- }
1992
- /**
1993
- * Spawn a subprocess that runs `gkm openapi --app <name>` with `cwd` set to
1994
- * the app's directory. Inherits `NODE_OPTIONS` (which already contains
1995
- * `--import tsx`), so the child gets a fresh tsx instance whose tsconfig
1996
- * discovery picks up the app's tsconfig path aliases.
1997
- */
1998
- async function runOpenApiInSubprocess(appCwd, appName) {
1999
- const binPath = resolveGkmBinPath();
2000
- await new Promise((resolve$1, reject) => {
2001
- const child = spawn(process.execPath, [
2002
- binPath,
2003
- "openapi",
2004
- "--app",
2005
- appName
2006
- ], {
2007
- cwd: appCwd,
2008
- stdio: "inherit",
2009
- env: process.env
2010
- });
2011
- child.on("error", reject);
2012
- child.on("close", (code) => {
2013
- if (code === 0) resolve$1();
2014
- else reject(new Error(`OpenAPI generation for app "${appName}" exited with code ${code}`));
2015
- });
2016
- });
2017
- }
2018
-
2019
- //#endregion
2020
- export { EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, generateOpenApiFrom, normalizeRoutes, openApiPathFor, openapiCommand, resolveOpenApiConfig, runtimeFor };
2021
- //# sourceMappingURL=openapi-Xx0A7Wg0.mjs.map