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