stratal 0.0.26 → 0.1.0

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 (284) hide show
  1. package/CHANGELOG.md +912 -0
  2. package/README.md +96 -14
  3. package/dist/bin/cloudflare-workers-loader.mjs +18 -3
  4. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  5. package/dist/bin/quarry.mjs +85 -14
  6. package/dist/bin/quarry.mjs.map +1 -1
  7. package/dist/cache/index.d.mts +8 -9
  8. package/dist/cache/index.d.mts.map +1 -1
  9. package/dist/cache/index.mjs +56 -17
  10. package/dist/cache/index.mjs.map +1 -1
  11. package/dist/{cache.service-uElmBtdS.d.mts → cache.service-Dg0Hj0gp.d.mts} +27 -12
  12. package/dist/cache.service-Dg0Hj0gp.d.mts.map +1 -0
  13. package/dist/{command-DoBD2Cwl.d.mts → command-BXMccV_9.d.mts} +6 -3
  14. package/dist/command-BXMccV_9.d.mts.map +1 -0
  15. package/dist/{command-BvmUAPPQ.mjs → command-Bb820B6W.mjs} +36 -13
  16. package/dist/command-Bb820B6W.mjs.map +1 -0
  17. package/dist/common.schemas-BigQCwYB.mjs +89 -0
  18. package/dist/common.schemas-BigQCwYB.mjs.map +1 -0
  19. package/dist/config/index.d.mts +15 -15
  20. package/dist/config/index.d.mts.map +1 -1
  21. package/dist/config/index.mjs +4 -6
  22. package/dist/config/index.mjs.map +1 -1
  23. package/dist/{consumer-registry-D3iMTSdy.d.mts → consumer-registry-i9oCdarv.d.mts} +2 -3
  24. package/dist/consumer-registry-i9oCdarv.d.mts.map +1 -0
  25. package/dist/{container-storage-BmOJ4_Na.mjs → container-storage-DfF7SXdV.mjs} +11 -1
  26. package/dist/container-storage-DfF7SXdV.mjs.map +1 -0
  27. package/dist/{controller.decorator-YSTPQntu.mjs → controller.decorator-BB0JcwMg.mjs} +18 -9
  28. package/dist/controller.decorator-BB0JcwMg.mjs.map +1 -0
  29. package/dist/cron/index.d.mts +6 -7
  30. package/dist/cron/index.d.mts.map +1 -1
  31. package/dist/cron/index.mjs +1 -1
  32. package/dist/{cron-job-NesZRk8F.d.mts → cron-job-DAgNw4Bn.d.mts} +1 -2
  33. package/dist/cron-job-DAgNw4Bn.d.mts.map +1 -0
  34. package/dist/{cron.module-C81HTzR7.mjs → cron.module-Dnyl9sFk.mjs} +6 -7
  35. package/dist/{cron.module-C81HTzR7.mjs.map → cron.module-Dnyl9sFk.mjs.map} +1 -1
  36. package/dist/{decorate-CuAoSZvs.mjs → decorate-C79yt3Wt.mjs} +2 -2
  37. package/dist/di/index.d.mts +1 -1
  38. package/dist/di/index.mjs +2 -3
  39. package/dist/{di-D7qmrAir.mjs → di-DQ3xbjgf.mjs} +48 -6
  40. package/dist/di-DQ3xbjgf.mjs.map +1 -0
  41. package/dist/email/index.d.mts +158 -133
  42. package/dist/email/index.d.mts.map +1 -1
  43. package/dist/email/index.mjs +66 -78
  44. package/dist/email/index.mjs.map +1 -1
  45. package/dist/{en-CDZBMcc1.mjs → en-CCL84z4k.mjs} +2 -2
  46. package/dist/{en-CDZBMcc1.mjs.map → en-CCL84z4k.mjs.map} +1 -1
  47. package/dist/env-ug22bJj7.d.mts.map +1 -1
  48. package/dist/errors/index.d.mts +1 -1
  49. package/dist/errors/index.mjs +3 -3
  50. package/dist/{errors-C01O2T-n.mjs → errors-CrOXI_y5.mjs} +6 -8
  51. package/dist/errors-CrOXI_y5.mjs.map +1 -0
  52. package/dist/events/index.d.mts +8 -9
  53. package/dist/events/index.d.mts.map +1 -1
  54. package/dist/events/index.mjs +1 -1
  55. package/dist/{events-BhEQuT1X.mjs → events-GtwGEHyT.mjs} +5 -6
  56. package/dist/events-GtwGEHyT.mjs.map +1 -0
  57. package/dist/{exception-context-D-kvney-.mjs → exception-context-CdnGTQNF.mjs} +13 -7
  58. package/dist/exception-context-CdnGTQNF.mjs.map +1 -0
  59. package/dist/{gateway-context-m7kEzRa2.mjs → gateway-context-Cmc1NRS0.mjs} +7 -7
  60. package/dist/{gateway-context-m7kEzRa2.mjs.map → gateway-context-Cmc1NRS0.mjs.map} +1 -1
  61. package/dist/gateway-mode-0rUaeW3g.mjs +53 -0
  62. package/dist/gateway-mode-0rUaeW3g.mjs.map +1 -0
  63. package/dist/guards/index.d.mts +38 -20
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +2 -2
  66. package/dist/{guards-DALPXy3_.mjs → guards-DOGly9IF.mjs} +34 -11
  67. package/dist/guards-DOGly9IF.mjs.map +1 -0
  68. package/dist/hono-app-IhdqL0Fk.mjs +399 -0
  69. package/dist/hono-app-IhdqL0Fk.mjs.map +1 -0
  70. package/dist/{http-method.decorator-BljM8BDj.mjs → http-method.decorator-BDi9LTWj.mjs} +9 -8
  71. package/dist/http-method.decorator-BDi9LTWj.mjs.map +1 -0
  72. package/dist/i18n/index.d.mts +26 -137
  73. package/dist/i18n/index.d.mts.map +1 -1
  74. package/dist/i18n/index.mjs +4 -5
  75. package/dist/i18n/index.mjs.map +1 -1
  76. package/dist/i18n/messages/en/index.d.mts +1 -1
  77. package/dist/i18n/messages/en/index.mjs +1 -1
  78. package/dist/i18n/utils/index.d.mts +1 -2
  79. package/dist/i18n/utils/index.d.mts.map +1 -1
  80. package/dist/i18n/validation/index.d.mts +80 -5
  81. package/dist/i18n/validation/index.d.mts.map +1 -0
  82. package/dist/i18n/validation/index.mjs +4 -5
  83. package/dist/{i18n.module-B2DvWUPa.mjs → i18n.module-Bm3xlViA.mjs} +28 -13
  84. package/dist/i18n.module-Bm3xlViA.mjs.map +1 -0
  85. package/dist/index-0ItCjaqw.d.mts.map +1 -1
  86. package/dist/{index-CNuFQSNj.d.mts → index-3HJfhLlE.d.mts} +9 -11
  87. package/dist/index-3HJfhLlE.d.mts.map +1 -0
  88. package/dist/{index-uybm0bhQ.d.mts → index-B2WtEagR.d.mts} +1187 -234
  89. package/dist/index-B2WtEagR.d.mts.map +1 -0
  90. package/dist/index-BUt92sAE.d.mts.map +1 -1
  91. package/dist/index-CAHNCpvr.d.mts +203 -0
  92. package/dist/index-CAHNCpvr.d.mts.map +1 -0
  93. package/dist/index.d.mts +4 -4
  94. package/dist/index.mjs +2 -2
  95. package/dist/{is-command-CEPO9n8c.mjs → is-command-CSVv14wh.mjs} +2 -2
  96. package/dist/{is-command-CEPO9n8c.mjs.map → is-command-CSVv14wh.mjs.map} +1 -1
  97. package/dist/{is-seeder-Gvh_AM71.mjs → is-seeder-gLgXYbqC.mjs} +2 -2
  98. package/dist/is-seeder-gLgXYbqC.mjs.map +1 -0
  99. package/dist/{lazy-module-loader-M6YKudNL.d.mts → lazy-module-loader-C3OHoUnR.d.mts} +4 -5
  100. package/dist/lazy-module-loader-C3OHoUnR.d.mts.map +1 -0
  101. package/dist/limit-BE0HNAF6.mjs +116 -0
  102. package/dist/limit-BE0HNAF6.mjs.map +1 -0
  103. package/dist/locale-path.service-BqzDIrgy.mjs +213 -0
  104. package/dist/locale-path.service-BqzDIrgy.mjs.map +1 -0
  105. package/dist/locale-url-nZrZxqJP.mjs.map +1 -1
  106. package/dist/{locale-url.service-6bgia24_.mjs → locale-url.service-H8PH6GGh.mjs} +15 -5
  107. package/dist/{locale-url.service-6bgia24_.mjs.map → locale-url.service-H8PH6GGh.mjs.map} +1 -1
  108. package/dist/logger/index.mjs +3 -5
  109. package/dist/logger/index.mjs.map +1 -1
  110. package/dist/macroable-cvDTFZ_A.mjs.map +1 -1
  111. package/dist/metadata-Ba8Fxs1F.mjs +48 -0
  112. package/dist/metadata-Ba8Fxs1F.mjs.map +1 -0
  113. package/dist/module/index.d.mts +8 -9
  114. package/dist/module/index.d.mts.map +1 -1
  115. package/dist/module/index.mjs +3 -4
  116. package/dist/module/index.mjs.map +1 -1
  117. package/dist/{module-registry-NxX5O0Qk.mjs → module-registry-lkQPDuQe.mjs} +17 -15
  118. package/dist/module-registry-lkQPDuQe.mjs.map +1 -0
  119. package/dist/{module.decorator-CYHY6pG5.mjs → module.decorator-CYbrOlX9.mjs} +2 -2
  120. package/dist/{module.decorator-CYHY6pG5.mjs.map → module.decorator-CYbrOlX9.mjs.map} +1 -1
  121. package/dist/openapi/index.d.mts +19 -16
  122. package/dist/openapi/index.d.mts.map +1 -1
  123. package/dist/openapi/index.mjs +2 -2
  124. package/dist/{openapi-CMwuCp31.mjs → openapi-DBfBa5Qh.mjs} +41 -65
  125. package/dist/openapi-DBfBa5Qh.mjs.map +1 -0
  126. package/dist/openapi-generator-CCwiu8AU.mjs +134 -0
  127. package/dist/openapi-generator-CCwiu8AU.mjs.map +1 -0
  128. package/dist/{openapi-tools.service-BC5EC3R3.mjs → openapi-tools.service-VKZJlTIX.mjs} +12 -4
  129. package/dist/openapi-tools.service-VKZJlTIX.mjs.map +1 -0
  130. package/dist/openapi.service-Ds-R1tih.d.mts +43 -0
  131. package/dist/openapi.service-Ds-R1tih.d.mts.map +1 -0
  132. package/dist/quarry/index.d.mts +10 -11
  133. package/dist/quarry/index.d.mts.map +1 -1
  134. package/dist/quarry/index.mjs +4 -4
  135. package/dist/quarry/runner.d.mts +19 -20
  136. package/dist/quarry/runner.d.mts.map +1 -1
  137. package/dist/quarry/runner.mjs +16 -13
  138. package/dist/quarry/runner.mjs.map +1 -1
  139. package/dist/{quarry-registry-DRnV-DDa.d.mts → quarry-registry-Ci4k58FZ.d.mts} +3 -4
  140. package/dist/quarry-registry-Ci4k58FZ.d.mts.map +1 -0
  141. package/dist/{quarry.module-CcGxU2dJ.mjs → quarry.module-BssRR8f0.mjs} +20 -37
  142. package/dist/quarry.module-BssRR8f0.mjs.map +1 -0
  143. package/dist/queue/index.d.mts +2 -2
  144. package/dist/queue/index.mjs +3 -3
  145. package/dist/queue/index.mjs.map +1 -1
  146. package/dist/{queue.module-CEs4_kEM.mjs → queue.module-DnAdSbR-.mjs} +40 -41
  147. package/dist/queue.module-DnAdSbR-.mjs.map +1 -0
  148. package/dist/{r2-storage.provider-BoZmR6Ut.mjs → r2-storage.provider-wU_6api4.mjs} +45 -6
  149. package/dist/r2-storage.provider-wU_6api4.mjs.map +1 -0
  150. package/dist/{rate-limit.decorator-Djs4oYDB.mjs → rate-limit.decorator-PYQ9EYqs.mjs} +10 -5
  151. package/dist/{rate-limit.decorator-Djs4oYDB.mjs.map → rate-limit.decorator-PYQ9EYqs.mjs.map} +1 -1
  152. package/dist/rate-limiter/index.d.mts +64 -19
  153. package/dist/rate-limiter/index.d.mts.map +1 -1
  154. package/dist/rate-limiter/index.mjs +67 -83
  155. package/dist/rate-limiter/index.mjs.map +1 -1
  156. package/dist/response-cache/index.d.mts +326 -0
  157. package/dist/response-cache/index.d.mts.map +1 -0
  158. package/dist/response-cache/index.mjs +511 -0
  159. package/dist/response-cache/index.mjs.map +1 -0
  160. package/dist/response-cache.error-B4D0zy9W.mjs +24 -0
  161. package/dist/response-cache.error-B4D0zy9W.mjs.map +1 -0
  162. package/dist/response-headers-BqA57S_X.mjs +158 -0
  163. package/dist/response-headers-BqA57S_X.mjs.map +1 -0
  164. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  165. package/dist/route-cache-binding-CrLh8tB6.mjs +390 -0
  166. package/dist/route-cache-binding-CrLh8tB6.mjs.map +1 -0
  167. package/dist/route-metadata-QQhbed1i.mjs +17 -0
  168. package/dist/route-metadata-QQhbed1i.mjs.map +1 -0
  169. package/dist/{route-name-DGoBOfPg.mjs → route-name-BslSbmMP.mjs} +15 -11
  170. package/dist/route-name-BslSbmMP.mjs.map +1 -0
  171. package/dist/route-registration.service-COKBZTsn.mjs +1265 -0
  172. package/dist/route-registration.service-COKBZTsn.mjs.map +1 -0
  173. package/dist/{route-registry-BvLJisvK.mjs → route-registry-DFz9_-N6.mjs} +6 -6
  174. package/dist/{route-registry-BvLJisvK.mjs.map → route-registry-DFz9_-N6.mjs.map} +1 -1
  175. package/dist/router/index.d.mts +2 -2
  176. package/dist/router/index.mjs +16 -15
  177. package/dist/{router-resolver-sUV_jTrU.mjs → router-resolver-B-dMSMIG.mjs} +7 -3
  178. package/dist/router-resolver-B-dMSMIG.mjs.map +1 -0
  179. package/dist/{router-DwyqEXgf.mjs → router-wlsVkGkM.mjs} +5 -14
  180. package/dist/{router-DwyqEXgf.mjs.map → router-wlsVkGkM.mjs.map} +1 -1
  181. package/dist/seeder/index.d.mts +12 -13
  182. package/dist/seeder/index.d.mts.map +1 -1
  183. package/dist/seeder/index.mjs +4 -4
  184. package/dist/{seeder-BPGY5rUb.mjs → seeder-BrAk7XIj.mjs} +5 -6
  185. package/dist/{seeder-BPGY5rUb.mjs.map → seeder-BrAk7XIj.mjs.map} +1 -1
  186. package/dist/{seeder-registry-DEvCycsT.mjs → seeder-registry-Bo5BgLbC.mjs} +5 -6
  187. package/dist/{seeder-registry-DEvCycsT.mjs.map → seeder-registry-Bo5BgLbC.mjs.map} +1 -1
  188. package/dist/{seeder.module-CIwQbdN4.mjs → seeder.module-DOoVgTsK.mjs} +5 -5
  189. package/dist/{seeder.module-CIwQbdN4.mjs.map → seeder.module-DOoVgTsK.mjs.map} +1 -1
  190. package/dist/signed-url-DIU0sK_6.mjs.map +1 -1
  191. package/dist/storage/index.d.mts +63 -13
  192. package/dist/storage/index.d.mts.map +1 -1
  193. package/dist/storage/index.mjs +2 -2
  194. package/dist/storage/providers/index.d.mts +18 -16
  195. package/dist/storage/providers/index.d.mts.map +1 -1
  196. package/dist/storage/providers/index.mjs +1 -1
  197. package/dist/{storage-C30X81CS.mjs → storage-DBWVYMnn.mjs} +167 -49
  198. package/dist/storage-DBWVYMnn.mjs.map +1 -0
  199. package/dist/storage-provider.interface-CinHpjl1.d.mts +315 -0
  200. package/dist/storage-provider.interface-CinHpjl1.d.mts.map +1 -0
  201. package/dist/storage.error-Ao38Qdjx.mjs +7 -0
  202. package/dist/storage.error-Ao38Qdjx.mjs.map +1 -0
  203. package/dist/{stratal-D5j_I14G.d.mts → stratal-Bs1_E8GQ.d.mts} +13 -3
  204. package/dist/stratal-Bs1_E8GQ.d.mts.map +1 -0
  205. package/dist/{stratal-BL6FKUM_.mjs → stratal-CiwNpWy2.mjs} +56 -23
  206. package/dist/stratal-CiwNpWy2.mjs.map +1 -0
  207. package/dist/{tiered-cache.service-Dv3BhxxE.d.mts → tiered-cache.service-Bz8bbvyb.d.mts} +16 -3
  208. package/dist/tiered-cache.service-Bz8bbvyb.d.mts.map +1 -0
  209. package/dist/trailing-slash-2SctvePW.mjs.map +1 -1
  210. package/dist/types-CmV_9xBD.d.mts.map +1 -1
  211. package/dist/{uri-iwofWJ_T.mjs → uri-BrOq148R.mjs} +13 -9
  212. package/dist/{uri-iwofWJ_T.mjs.map → uri-BrOq148R.mjs.map} +1 -1
  213. package/dist/{usage-generator-DAWYasuP.mjs → usage-generator-BW7EcO-C.mjs} +3 -3
  214. package/dist/{usage-generator-DAWYasuP.mjs.map → usage-generator-BW7EcO-C.mjs.map} +1 -1
  215. package/dist/{zod-eKqqhZ5_.mjs → validation-CZ_B0aXY.mjs} +38 -17
  216. package/dist/validation-CZ_B0aXY.mjs.map +1 -0
  217. package/dist/{validation.context-CRvmrhq7.mjs → validation.context-CdbwQWIr.mjs} +2 -2
  218. package/dist/{validation.context-CRvmrhq7.mjs.map → validation.context-CdbwQWIr.mjs.map} +1 -1
  219. package/dist/{versioning.service-CCa2oYMJ.mjs → versioning.service-DnF_4Lnd.mjs} +5 -5
  220. package/dist/{versioning.service-CCa2oYMJ.mjs.map → versioning.service-DnF_4Lnd.mjs.map} +1 -1
  221. package/dist/websocket/index.d.mts +12 -13
  222. package/dist/websocket/index.d.mts.map +1 -1
  223. package/dist/websocket/index.mjs +1 -1
  224. package/dist/workers/index.d.mts +70 -7
  225. package/dist/workers/index.d.mts.map +1 -1
  226. package/dist/workers/index.mjs +72 -3
  227. package/dist/workers/index.mjs.map +1 -1
  228. package/dist/{zod-wecrEVAs.d.mts → zod-BGisqLs3.d.mts} +9 -16
  229. package/dist/zod-BGisqLs3.d.mts.map +1 -0
  230. package/package.json +33 -25
  231. package/dist/cache.service-uElmBtdS.d.mts.map +0 -1
  232. package/dist/chunk-BBjsoOtd.mjs +0 -27
  233. package/dist/command-BvmUAPPQ.mjs.map +0 -1
  234. package/dist/command-DoBD2Cwl.d.mts.map +0 -1
  235. package/dist/consumer-registry-D3iMTSdy.d.mts.map +0 -1
  236. package/dist/container-storage-BmOJ4_Na.mjs.map +0 -1
  237. package/dist/controller.decorator-YSTPQntu.mjs.map +0 -1
  238. package/dist/cron-job-NesZRk8F.d.mts.map +0 -1
  239. package/dist/di-D7qmrAir.mjs.map +0 -1
  240. package/dist/errors-C01O2T-n.mjs.map +0 -1
  241. package/dist/events-BhEQuT1X.mjs.map +0 -1
  242. package/dist/exception-context-D-kvney-.mjs.map +0 -1
  243. package/dist/guards-DALPXy3_.mjs.map +0 -1
  244. package/dist/hono-app-COAgmutc.mjs +0 -168
  245. package/dist/hono-app-COAgmutc.mjs.map +0 -1
  246. package/dist/http-method.decorator-BljM8BDj.mjs.map +0 -1
  247. package/dist/i18n.module-B2DvWUPa.mjs.map +0 -1
  248. package/dist/index-CNuFQSNj.d.mts.map +0 -1
  249. package/dist/index-DtBNIFuP.d.mts +0 -42
  250. package/dist/index-DtBNIFuP.d.mts.map +0 -1
  251. package/dist/index-HgOLNruQ.d.mts +0 -203
  252. package/dist/index-HgOLNruQ.d.mts.map +0 -1
  253. package/dist/index-uybm0bhQ.d.mts.map +0 -1
  254. package/dist/is-seeder-Gvh_AM71.mjs.map +0 -1
  255. package/dist/lazy-module-loader-M6YKudNL.d.mts.map +0 -1
  256. package/dist/locale-path.service-CH0CaxwH.mjs +0 -165
  257. package/dist/locale-path.service-CH0CaxwH.mjs.map +0 -1
  258. package/dist/metadata-DzzprcID.mjs +0 -39
  259. package/dist/metadata-DzzprcID.mjs.map +0 -1
  260. package/dist/module-registry-NxX5O0Qk.mjs.map +0 -1
  261. package/dist/openapi-CMwuCp31.mjs.map +0 -1
  262. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +0 -1
  263. package/dist/openapi.service-2rvJBCEg.d.mts +0 -50
  264. package/dist/openapi.service-2rvJBCEg.d.mts.map +0 -1
  265. package/dist/quarry-registry-DRnV-DDa.d.mts.map +0 -1
  266. package/dist/quarry.module-CcGxU2dJ.mjs.map +0 -1
  267. package/dist/queue.module-CEs4_kEM.mjs.map +0 -1
  268. package/dist/r2-storage.provider-BoZmR6Ut.mjs.map +0 -1
  269. package/dist/route-name-DGoBOfPg.mjs.map +0 -1
  270. package/dist/route-registration.service-CDPQKpm4.mjs +0 -918
  271. package/dist/route-registration.service-CDPQKpm4.mjs.map +0 -1
  272. package/dist/router-resolver-sUV_jTrU.mjs.map +0 -1
  273. package/dist/storage-C30X81CS.mjs.map +0 -1
  274. package/dist/storage-provider.interface-ClUwxz4S.d.mts +0 -201
  275. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +0 -1
  276. package/dist/storage.error-BStXPmO4.mjs +0 -8
  277. package/dist/storage.error-BStXPmO4.mjs.map +0 -1
  278. package/dist/stratal-BL6FKUM_.mjs.map +0 -1
  279. package/dist/stratal-D5j_I14G.d.mts.map +0 -1
  280. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +0 -1
  281. package/dist/validation-CpOjviyT.mjs +0 -49
  282. package/dist/validation-CpOjviyT.mjs.map +0 -1
  283. package/dist/zod-eKqqhZ5_.mjs.map +0 -1
  284. package/dist/zod-wecrEVAs.d.mts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-registration.service-COKBZTsn.mjs","names":[],"sources":["../src/router/errors/schema-validation.error.ts","../src/router/errors/index.ts","../src/router/middleware/domain.middleware.ts","../src/router/middleware/middleware-chain.ts","../src/router/decorators/route.decorator.ts","../src/router/services/capture-payload.ts","../src/router/validation/create-validator.ts","../src/router/validation/route-validators.ts","../src/router/services/route-registration.service.ts"],"sourcesContent":["import type { $ZodError, $ZodIssue } from 'zod/v4/core'\nimport { HttpException } from '../../errors'\n\nexport class SchemaValidationError extends HttpException {\n public readonly issues: { path: string; message: string; code: string }[]\n\n constructor(zodError: $ZodError) {\n super(400, 'Schema validation failed')\n this.issues = zodError.issues.map((err: $ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n }\n\n override reportContext(): Record<string, unknown> {\n return { issues: this.issues }\n }\n}\n","import type { $ZodError, $ZodIssue } from 'zod/v4/core';\nimport { HttpException } from '../../errors';\n\n/**\n * Error thrown when a signed URL has an invalid or expired signature.\n *\n * HTTP Status: 403 Forbidden\n */\nexport class InvalidSignatureError extends HttpException {\n constructor() {\n super(403, 'Invalid or expired signature')\n }\n}\n\n/**\n * ResponseValidationError\n *\n * Thrown when a controller's response body does not match the declared Zod response schema.\n * Indicates a server-side schema mismatch — the controller is returning data that\n * violates its own API contract.\n */\nexport class ResponseValidationError extends HttpException {\n public readonly issues: { path: string; message: string; code: string }[]\n\n constructor(zodError: $ZodError) {\n super(500, 'Response validation failed')\n this.issues = zodError.issues.map((err: $ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n }\n}\n\nexport { RouteNotFoundError } from './route-not-found.error';\n\nexport { SchemaValidationError } from './schema-validation.error';\n","import type { Context, MiddlewareHandler } from 'hono';\nimport { abort } from '../../errors';\nimport type { RouterEnv } from '../types';\n\n/**\n * Parse a domain pattern into a regex and extract parameter names.\n *\n * @example\n * parseDomainPattern('{tenant}.example.com')\n * // => { regex: /^([^.]+)\\.example\\.com$/, paramNames: ['tenant'] }\n *\n * parseDomainPattern('{region}.{tenant}.example.com')\n * // => { regex: /^([^.]+)\\.([^.]+)\\.example\\.com$/, paramNames: ['region', 'tenant'] }\n */\nexport function parseDomainPattern(pattern: string): { regex: RegExp; paramNames: string[] } {\n const paramNames: string[] = []\n\n const regexStr = pattern.replace(\n /\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g,\n (_match, paramName: string) => {\n paramNames.push(paramName)\n return '([^.]+)'\n }\n )\n\n // Escape dots in the remaining static parts\n const escaped = regexStr.replace(/\\./g, '\\\\.')\n return { regex: new RegExp(`^${escaped}$`), paramNames }\n}\n\n/**\n * Strip port number from a host header value.\n * 'example.com:8787' => 'example.com'\n */\nfunction stripPort(host: string): string {\n const colonIdx = host.lastIndexOf(':')\n if (colonIdx === -1) return host\n // Check if it's actually a port (digits after the colon)\n const afterColon = host.slice(colonIdx + 1)\n return /^\\d+$/.test(afterColon) ? host.slice(0, colonIdx) : host\n}\n\n/**\n * Create a Hono middleware that matches the request host against a domain pattern.\n *\n * When the host matches, domain parameters are extracted and stored in context\n * variables accessible via `ctx.domain(key)`.\n *\n * When the host does NOT match, aborts with 404.\n *\n * @param pattern - Domain pattern with `{param}` placeholders (e.g., '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * // Applied automatically by RouteRegistrationService for controllers with domain config\n * @Controller('/dashboard', { domain: '{tenant}.myapp.com' })\n * export class DashboardController {\n * async index(ctx: RouterContext) {\n * const tenant = ctx.domain('tenant')\n * }\n * }\n * ```\n */\nexport function createDomainMiddleware(pattern: string): MiddlewareHandler<RouterEnv> {\n const { regex, paramNames } = parseDomainPattern(pattern)\n\n return async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const host = stripPort(c.req.header('host') ?? '')\n const match = regex.exec(host)\n\n if (!match) {\n abort(404, 'Domain mismatch')\n }\n\n // Store domain params as context variables\n for (let i = 0; i < paramNames.length; i++) {\n c.set(`domain:${paramNames[i]}`, match[i + 1])\n }\n\n await next()\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport type { Constructor } from '../../types'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\nimport { RouterError } from '../router.error'\nimport type { Middleware, Next } from '../middleware.interface'\nimport { RouterContext } from '../router-context'\nimport type { RouterEnv } from '../types'\n\n/**\n * Create a Hono middleware handler that executes a chain of Stratal middleware classes.\n *\n * Each middleware is resolved from the request-scoped container per request,\n * then executed in order (first registered = outermost in the chain).\n *\n * @param classes - Middleware classes to chain\n * @returns Hono middleware handler\n */\nexport function createMiddlewareChain(\n classes: Constructor<Middleware>[]\n): MiddlewareHandler<RouterEnv> {\n return async (c: Context<RouterEnv>, next: () => Promise<Response | void>) => {\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n const ctx = new RouterContext(c)\n\n // Build chain from end to start\n let current = next\n for (let i = classes.length - 1; i >= 0; i--) {\n const prevNext = current\n const middlewareClass = classes[i]\n current = async () => {\n const middleware = requestContainer.resolve<Middleware>(middlewareClass)\n let called = false\n const guardedNext: Next = () => {\n if (called) {\n return Promise.reject(\n new RouterError(`Middleware \"${middlewareClass.name ?? 'anonymous'}\" called next() multiple times`)\n )\n }\n called = true\n return prevNext()\n }\n\n const result = await middleware.handle(ctx, guardedNext)\n\n // A middleware that returns a Response is short-circuiting the request.\n // Finalize it on the Hono context at this boundary so it survives even\n // when an *outer* middleware forwards control with `await next()`\n // instead of `return next()` and drops the returned value — which would\n // otherwise leave the context unfinalized and make Hono throw\n // \"Context is not finalized\". Outer middlewares that don't short-circuit\n // return void, so `result instanceof Response` is false and they never\n // reach this branch to override an inner middleware's already-set\n // response. (A forwarding middleware that `return next()`s re-sets the\n // very same Response object, which is harmless.)\n if (result instanceof Response) {\n c.res = result\n }\n\n return result\n }\n }\n\n const result = await current()\n\n if (result instanceof Response) {\n return result // return to Hono\n }\n }\n}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../constants'\nimport type { ConventionRouteMetadata, RouteConfig, RouteMetadata } from '../types'\n\n/**\n * Decorator to add OpenAPI metadata to a controller method using convention-based routing.\n *\n * **Cannot be mixed with HTTP method decorators** (`@Get`, `@Post`, `@Put`, `@Patch`,\n * `@Delete`, `@All`) in the same controller. Use one pattern or the other.\n *\n * Stores route configuration (schemas, response, tags, security) in metadata.\n * HTTP method, path, and success status code are auto-derived from the method name:\n * - index() → GET /base-path → 200\n * - show() → GET /base-path/:id → 200\n * - create() → POST /base-path → 201\n * - update() → PUT /base-path/:id → 200\n * - patch() → PATCH /base-path/:id → 200\n * - destroy() → DELETE /base-path/:id → 200\n *\n * @param config - Route configuration (schemas, response, tags, security)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/notes', {\n * tags: ['Notes'],\n * security: ['bearerAuth']\n * })\n * export class NotesController implements Controller {\n * @Route({\n * body: createNoteSchema,\n * response: noteSchema, // 201 auto-derived from 'create' method\n * tags: ['Mutations'],\n * description: 'Create a new note'\n * })\n * async create(ctx: RouterContext): Promise<Response> {\n * // POST /api/v1/notes (auto-derived from method name)\n * // Body schema: createNoteSchema (auto-validated)\n * // Response: 201 → noteSchema (status auto-derived)\n * // Tags: ['Notes', 'Mutations'] (merged with controller)\n * // Security: ['bearerAuth'] (inherited from controller)\n * const body = ctx.body()\n * const note = await this.notesService.create(body)\n * return ctx.json(note, 201)\n * }\n *\n * @Route({\n * query: paginationSchema,\n * response: array(noteSchema) // 200 auto-derived from 'index' method\n * })\n * async index(ctx: RouterContext): Promise<Response> {\n * // GET /api/v1/notes (auto-derived)\n * // Query params auto-validated\n * const notes = await this.notesService.list()\n * return ctx.json(notes)\n * }\n *\n * @Route({\n * params: object({ id: uuid() }),\n * response: {\n * schema: noteSchema,\n * description: 'Note details'\n * },\n * security: [] // Override to make public\n * })\n * async show(ctx: RouterContext): Promise<Response> {\n * // GET /api/v1/notes/:id (auto-derived)\n * // URL params auto-validated\n * // Response: 200 → noteSchema (status auto-derived)\n * // Security: [] (public route, override controller security)\n * const id = ctx.param('id')\n * const note = await this.notesService.findById(id)\n * return ctx.json(note)\n * }\n * }\n * ```\n */\nexport function Route(config: Omit<RouteConfig, 'statusCode'>) {\n return function (\n target: object,\n propertyKey: string,\n descriptor: PropertyDescriptor\n ) {\n const metadata: ConventionRouteMetadata = {\n type: 'convention',\n config,\n }\n\n defineMetadata(\n ROUTE_METADATA_KEYS.ROUTE_CONFIG,\n metadata,\n target,\n propertyKey\n )\n\n // Track this method as decorated on the prototype\n const existing: string[] =\n getMetadata<string[]>(ROUTE_METADATA_KEYS.DECORATED_METHODS, target) ?? []\n existing.push(propertyKey)\n defineMetadata(ROUTE_METADATA_KEYS.DECORATED_METHODS, existing, target)\n\n return descriptor\n }\n}\n\n/**\n * Get the route metadata from a controller method\n *\n * @param target - Controller instance or prototype\n * @param methodName - Name of the method\n * @returns Route metadata or undefined if not decorated\n */\nexport function getRouteMetadata(target: object, methodName: string): RouteMetadata | undefined {\n return getMetadata<RouteMetadata>(ROUTE_METADATA_KEYS.ROUTE_CONFIG, target, methodName)\n}\n\n/**\n * Get all methods with route decorators (@Route, @Get, @Post, etc.) from a controller\n *\n * @param ControllerClass - Controller class\n * @returns Array of method names that have route metadata\n */\nexport function getRouteDecoratedMethods(ControllerClass: new (...args: unknown[]) => object): string[] {\n const methods = new Set<string>()\n let proto: object | null = ControllerClass.prototype as object\n\n while (proto && proto !== Object.prototype) {\n const own = getMetadata<string[]>(ROUTE_METADATA_KEYS.DECORATED_METHODS, proto)\n if (own) {\n for (const m of own) methods.add(m)\n }\n proto = Object.getPrototypeOf(proto) as object | null\n }\n\n return [...methods]\n}\n","import type { Context } from 'hono'\nimport type { CacheableOptions, PurgesCacheOptions } from '../../response-cache/types'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\n\n/** Does any declared tag template read the `{data.*}` scope? */\nfunction readsDataScope(tags: string[] | undefined): boolean {\n return (tags ?? []).some((tag) => tag.includes('{data.'))\n}\n\n/**\n * Whether this route needs its handler's JSON payload captured.\n *\n * Evaluated once at route registration, never per request: capturing\n * unconditionally would clone and re-parse every JSON response body in the\n * application, doubling parse cost on a hot path that has nothing to do with\n * caching.\n */\nexport function needsPayloadCapture(\n cacheable: CacheableOptions | undefined,\n purges: PurgesCacheOptions | undefined,\n): boolean {\n return readsDataScope(cacheable?.tags) || readsDataScope(purges?.tags)\n}\n\n/**\n * Matches the JSON family: `application/json` plus any `+json` structured\n * suffix (`application/problem+json`, `application/ld+json`,\n * `application/vnd.api+json`), with or without parameters.\n */\nconst JSON_CONTENT_TYPE = /^application\\/(?:[\\w.-]+\\+)?json\\s*(?:;|$)/i\n\n/**\n * Record the handler's structured payload so `{data.*}` cache tags can read\n * values the request itself never carried — a post's category ID on a publish\n * route.\n *\n * **This does not decide what is cacheable.** Every content type Workers\n * Caching stores — HTML, text, images, binary, streams — is cached exactly the\n * same way; `@Cacheable` is content-type agnostic. This function only decides\n * whether a tag can interpolate a value *out of the response body*, which\n * requires a body that parses into an object. Non-JSON routes still cache\n * normally and can still tag from `{param.*}` and `{query.*}` — never\n * `{body.*}`, which `bindRouteCache` rejects at registration because the\n * router never has a parsed request body available to populate it.\n * Inertia sets the payload directly when building its page response, so its\n * HTML documents support\n * `{data.*}` without any parsing here.\n *\n * Clones before reading: consuming the returned Response's body would leave\n * nothing to send.\n */\nexport async function capturePayload(\n c: Context,\n response: Response,\n): Promise<void> {\n if (c.get(ROUTER_CONTEXT_KEYS.RESPONSE_PAYLOAD)) return\n if (!JSON_CONTENT_TYPE.test(response.headers.get('Content-Type') ?? '')) return\n\n try {\n c.set(ROUTER_CONTEXT_KEYS.RESPONSE_PAYLOAD, await response.clone().json())\n } catch {\n // A malformed body on a JSON content type is not worth failing a request\n // over — `{data.*}` will report the value as missing and throw there.\n }\n}\n","import type { MiddlewareHandler } from 'hono'\nimport { validator } from 'hono/validator'\nimport type { ZodType } from '../../i18n/validation/zod'\nimport { SchemaValidationError } from '../errors'\nimport type { RouterEnv } from '../types'\n\n/**\n * Hono validation targets Stratal validates against. Body content types map to\n * `json` or `form`; path/query/header validate the corresponding request part.\n */\nexport type ValidatorTarget = 'json' | 'form' | 'query' | 'param' | 'header'\n\n/**\n * Build a Hono validator middleware that runs a Zod schema against one request\n * part and populates `c.req.valid(target)` with the parsed (coerced) output.\n *\n * This is the plain-Hono replacement for `@hono/zod-openapi`'s `app.openapi()`\n * validator composition. It carries **no runtime `zod` import** — it only calls\n * `safeParseAsync` on the caller-supplied schema instance and references\n * `ZodType`/`ZodError` as erased types — so a route without a declared schema\n * attaches no validator and pulls in no `zod`.\n *\n * Parsing is async so a schema may carry an async refinement — one that reaches\n * a database, a cache or a service binding to decide whether a value is\n * acceptable. Zod's synchronous `safeParse` throws `$ZodAsyncError` rather than\n * returning a failure when it meets one, which would surface as a 500 instead\n * of a 400. A fully synchronous schema resolves on the same tick.\n *\n * On failure it throws {@link SchemaValidationError}, which the global exception\n * handler renders as a 400 with i18n-translated issues (the Zod error map is\n * installed globally by the I18n module, so messages stay localized).\n *\n * `omit` drops framework-injected request keys (e.g. the `locale` path segment\n * on localized routes) before parsing, so they never reach a user's schema —\n * keeping a `.strict()` schema from rejecting them and keeping `c.req.valid()`\n * limited to the keys the schema actually declares.\n */\nexport function createValidator(\n target: ValidatorTarget,\n schema: ZodType,\n omit?: readonly string[],\n): MiddlewareHandler<RouterEnv> {\n return validator(target, async (value) => {\n const record = value as Record<string, unknown>\n const input = omit?.length ? omitKeys(record, omit) : record\n const result = await schema.safeParseAsync(input)\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n return result.data\n })\n}\n\nfunction omitKeys(value: Record<string, unknown>, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const key in value) {\n if (!keys.includes(key)) out[key] = value[key]\n }\n return out\n}\n","import type { MiddlewareHandler } from 'hono'\nimport type { ZodType } from '../../i18n/validation/zod'\nimport type { RouterEnv } from '../types'\nimport { createValidator, type ValidatorTarget } from './create-validator'\n\n/** The framework-injected path key on localized routes; never part of a user schema. */\nconst LOCALE_PARAM_KEY = 'locale'\n\n/**\n * The request schemas a route declares. Each is optional — a route that\n * declares none attaches no validators and therefore pulls in no `zod`.\n */\nexport interface RouteValidatorSchemas {\n params?: ZodType\n query?: ZodType\n body?: { schema: ZodType; contentType: string }\n /**\n * True when the route is a locale-prefixed variant. The `locale` path segment\n * is enforced by the route pattern constraint (`/:locale{en|fr}`) and read via\n * `ctx.getLocale()`, so it is stripped before param validation rather than\n * validated with a (zod-requiring) enum.\n */\n isLocaleVariant?: boolean\n}\n\n/** Map a body content type to the Hono validation target. */\nfunction bodyTarget(contentType: string): ValidatorTarget {\n return contentType.includes('json') ? 'json' : 'form'\n}\n\n/**\n * Assemble the ordered validator middlewares for a route from its declared\n * schemas. Order matches Hono's expectation (param → query → body) and only\n * includes validators for parts the route actually declares.\n */\nexport function buildRouteValidators(schemas: RouteValidatorSchemas): MiddlewareHandler<RouterEnv>[] {\n const validators: MiddlewareHandler<RouterEnv>[] = []\n\n if (schemas.params) {\n validators.push(\n createValidator('param', schemas.params, schemas.isLocaleVariant ? [LOCALE_PARAM_KEY] : undefined),\n )\n }\n if (schemas.query) {\n validators.push(createValidator('query', schemas.query))\n }\n if (schemas.body) {\n validators.push(createValidator(bodyTarget(schemas.body.contentType), schemas.body.schema))\n }\n\n return validators\n}\n","import type { Context, MiddlewareHandler } from 'hono';\nimport type { UpgradeWebSocket, WSContext, WSEvents } from 'hono/ws';\nimport { type Container, getMethodInjections, inject } from '../../di';\nimport { Singleton } from '../../di/decorators';\nimport { DI_TOKENS } from '../../di/tokens';\nimport {\n type Guard,\n GuardExecutionService,\n getControllerGuards,\n getMethodGuards,\n} from '../../guards';\nimport { object } from 'zod/mini';\nimport type { ZodObject, ZodType } from '../../i18n/validation/zod';\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger';\nimport type { ModuleRegistry } from '../../module/module-registry';\nimport { getRateLimits } from '../../rate-limiter/decorators/rate-limit.decorator';\nimport { createThrottleMiddleware } from '../../rate-limiter/throttle.middleware';\nimport { getCacheable, getPurgesCache } from '../../response-cache/decorators';\nimport { cachingUnavailableReason } from '../../response-cache/boot-check';\nimport { CachePurgeError, ResponseCacheConfigError } from '../../response-cache/errors';\nimport { RESPONSE_CACHE_TOKENS } from '../../response-cache/response-cache.tokens';\nimport { bindRouteCache, type RouteCacheBinding } from '../../response-cache/services/route-cache-binding';\nimport { createLoopbackPurgeTarget } from '../../response-cache/gateway-binding';\nimport { isGatewayMode } from '../../response-cache/gateway-mode';\nimport type { GatewayRouteTable } from '../../response-cache/services/gateway-route-table';\nimport type { PartitionResolverService } from '../../response-cache/services/partition-resolver.service';\nimport type { CacheabilityService } from '../../response-cache/services/cacheability.service';\nimport type { PurgeSpec, ResponseCacheService, WorkersCache } from '../../response-cache/services/response-cache.service';\nimport type { TagScopes } from '../../response-cache/tag-template';\nimport type { CacheableOptions, ResponseCacheModuleOptions } from '../../response-cache/types';\nimport type { Constructor } from '../../types';\nimport { getWsOnCloseMethod, getWsOnErrorMethod, getWsOnMessageMethod, isGateway } from '../../websocket/decorators';\nimport { GatewayContext } from '../../websocket/gateway-context';\nimport { DEFAULT_CONTENT_TYPE, HTTP_METHODS, METHOD_STATUS_CODES, ROUTER_CONTEXT_KEYS, SECURITY_SCHEMES } from '../constants';\nimport type { IController } from '../controller';\nimport {\n getControllerOptions,\n getControllerRoute,\n getRouteDecoratedMethods,\n getRouteMetadata,\n} from '../decorators';\nimport {\n ResponseValidationError,\n} from '../errors';\nimport type { HonoApp } from '../hono-app';\nimport type { Middleware } from '../middleware.interface';\nimport { createDomainMiddleware } from '../middleware/domain.middleware';\nimport { createMiddlewareChain } from '../middleware/middleware-chain';\nimport { type RegisteredRoute, type RouteRegistry } from '../route-registry';\nimport { RouterContext } from '../router-context';\nimport type { RouterResolver } from '../router-resolver';\nimport type { RouteMetadataRegistry, RouteResponseMeta, RouteSchemaMeta } from '../route-metadata';\nimport { RouterError } from '../router.error';\nimport { ROUTER_TOKENS } from '../router.tokens';\nimport { capturePayload, needsPayloadCapture } from './capture-payload';\nimport type {\n ControllerOptions,\n HttpMethod,\n RouteBodyObject,\n RouteConfig,\n RouteMetadata,\n RouteResponseObject,\n RouterEnv,\n SecuritySchemeRecord,\n} from '../types';\nimport { buildRouteValidators } from '../validation/route-validators';\nimport { extractPathParams, toOpenAPIPath } from '../utils/path';\nimport { generateConventionRouteName } from '../utils/route-name';\nimport type { LocalePathService } from './locale-path.service';\n\nconst invokeHandler = async (instance: Record<string, (...args: unknown[]) => unknown>, method: string, ...args: unknown[]): Promise<unknown> => {\n return await instance[method](...args)\n}\n\n/**\n * The Cloudflare Workers Caching surface on `ExecutionContext` that Hono's\n * own `Context.executionCtx` type doesn't declare. See `executionCache`.\n */\ninterface CacheCapableExecutionContext {\n cache?: WorkersCache\n /**\n * The `ctx.props` this invocation was called with. Wholly part of the\n * Workers Caching key — see `partitionsResolved`, which verifies the\n * executing route's declared partitions are actually present here rather\n * than trusting the caller to have supplied them.\n */\n props?: Record<string, unknown>\n}\n\n/** True for anything with a callable `.then` — a `Promise`, or a thenable. */\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return typeof value === 'object' && value !== null && typeof (value as { then?: unknown }).then === 'function'\n}\n\n/**\n * Route registration service\n * Manages controller and route registration with OpenAPI support\n *\n * Responsibilities:\n * - Register RESTful controllers with OpenAPI metadata\n * - Auto-derive HTTP methods/paths from controller method names\n * - Build OpenAPI route configurations with guard execution\n * - Validate all controllers have access decorators (strict mode)\n * - Create controller handlers with DI resolution\n *\n * Two-pass strategy:\n * 1. Collect: iterate controllers, register in RouteRegistry, store Hono actions\n * 2. Register: iterate registry.all() (sorted), execute stored actions in Hono\n */\n@Singleton()\nexport class RouteRegistrationService {\n private controllerClasses = new Map<string, Constructor>()\n private upgradeWebSocketFn: UpgradeWebSocket | null = null\n private cacheableRouteCount = 0\n /**\n * Whether Workers Caching is usable, answered once per entrypoint.\n *\n * Keyed on whether the request arrived through the gateway, because that is\n * the scope the answer actually has: a gateway topology runs two entrypoints\n * — `cache.enabled` false on the gateway, true on the cached one — over a\n * single isolate and therefore a single instance of this service. A verdict\n * reached on one says nothing about the other, so holding one for the\n * isolate lets whichever entrypoint happens to serve the first request\n * decide for both, and a `cache.enabled` that is false *by design* on the\n * gateway reads as the app being misconfigured.\n *\n * Memoized rather than recomputed because `cache.enabled` is a static\n * Wrangler setting: within one entrypoint the answer cannot change.\n */\n private cachingAvailability = new Map<boolean, boolean>()\n\n constructor(\n @inject(LOGGER_TOKENS.LoggerService) private logger: LoggerService,\n @inject(ROUTER_TOKENS.RouteRegistry) private registry: RouteRegistry,\n @inject(ROUTER_TOKENS.RouterResolver, { isOptional: true }) private routerResolver: RouterResolver | null,\n @inject(ROUTER_TOKENS.LocalePathService) private localePathService: LocalePathService,\n @inject(ROUTER_TOKENS.HonoApp) private app: HonoApp,\n @inject(DI_TOKENS.ModuleRegistry) private moduleRegistry: ModuleRegistry,\n @inject(ROUTER_TOKENS.RouteMetadataRegistry) private metadataRegistry: RouteMetadataRegistry,\n // The three dependencies below are only registered when the app imports\n // `ResponseCacheModule` — it is opt-in. Resolving them optionally (rather\n // than throwing at DI construction time) lets every other app keep\n // working unmodified; `collectRoutes` is what turns \"used @Cacheable\n // without importing the module\" into a boot-time error instead of a\n // request-time `null` dereference.\n @inject(RESPONSE_CACHE_TOKENS.CacheabilityService, { isOptional: true }) private cacheability?: CacheabilityService,\n @inject(RESPONSE_CACHE_TOKENS.ResponseCacheService, { isOptional: true }) private responseCache?: ResponseCacheService,\n @inject(RESPONSE_CACHE_TOKENS.Options, { isOptional: true }) private responseCacheOptions?: ResponseCacheModuleOptions,\n @inject(RESPONSE_CACHE_TOKENS.GatewayRouteTable, { isOptional: true }) private gatewayRouteTable?: GatewayRouteTable,\n @inject(RESPONSE_CACHE_TOKENS.PartitionResolverService, { isOptional: true }) private partitionResolver?: PartitionResolverService,\n ) { }\n\n /**\n * The cached entrypoint named by `forRoot({ gateway: { entrypoint } })`, or\n * `undefined` when no gateway is configured.\n *\n * A `Promise` (the `forRootAsync` trap) reads as \"no gateway\" here rather\n * than throwing: `responseCacheDefaults()` raises that as its own boot error\n * with a message about the real problem, and it is called first on every\n * path that consults this.\n */\n private gatewayEntrypoint(): string | undefined {\n const options = this.responseCacheOptions\n if (isThenable(options)) return undefined\n return options?.gateway?.entrypoint\n }\n\n /** `gateway.keyBy`, read under the same `forRootAsync` caveat as the entrypoint. */\n private gatewayKeyBy(): readonly string[] {\n const options = this.responseCacheOptions\n if (isThenable(options)) return []\n return options?.gateway?.keyBy ?? []\n }\n\n /**\n * `ResponseCacheModule.forRoot({ defaults })`, resolved once at\n * construction (constructor injection is memoized on this singleton\n * instance) and falling back to `{}` when the module was never imported —\n * mirrors `OpenAPIConfigStore.getBaseConfig()`.\n *\n * `forRootAsync({ useFactory })` is a trap here: `ModuleRegistry` registers\n * the factory verbatim (`registerFactory`), and `Container.resolve()` never\n * awaits a factory's return value — so an async `useFactory` resolves this\n * token to a **Promise**, not the options object. Left unchecked, `?.defaults`\n * on a Promise is `undefined`, silently falling back to `{}` — including\n * silently dropping a `partitionBy` the author thought was enforced, the\n * exact per-user data leak this feature exists to prevent. Detected and\n * thrown here, once, at boot, rather than trusted per route.\n */\n private responseCacheDefaults(): Omit<CacheableOptions, 'tags'> {\n const options = this.responseCacheOptions\n\n if (isThenable(options)) {\n throw new ResponseCacheConfigError(\n 'ResponseCacheModule.forRootAsync() options resolved to a Promise, not the awaited value. ' +\n 'Route registration reads `defaults` synchronously — an async `useFactory` is never ' +\n 'awaited before routes register, so `defaults` (and any `partitionBy` inside it) would be ' +\n 'silently dropped instead of enforced, and every `@Cacheable` route would register as if no ' +\n 'defaults were set. Use a synchronous `useFactory`, or resolve the options yourself and ' +\n 'register them with `useValue` once the async work has settled.',\n )\n }\n\n return options?.defaults ?? {}\n }\n\n /**\n * Configure router with controllers and global middleware.\n * Resolves controllers from ModuleRegistry and global middleware from RouterResolver.\n */\n async configure(): Promise<void> {\n const controllers = this.moduleRegistry.getAllControllers()\n const globalMiddleware = this.routerResolver?.getGlobalMiddleware() ?? []\n\n // Before any route registers, so the dispatch middleware never observes a\n // table that is populated but not yet pointed at an entrypoint.\n this.gatewayRouteTable?.configure(this.gatewayEntrypoint(), this.gatewayKeyBy())\n\n this.logger.info('Registering controllers', {\n controllerCount: controllers.length,\n })\n\n // Global middleware from Router.use() (applies to ALL routes)\n if (globalMiddleware.length > 0) {\n this.app.use('*', createMiddlewareChain(globalMiddleware))\n }\n\n // Eagerly load upgradeWebSocket once if any gateway exists\n if (controllers.some(isGateway)) {\n const { upgradeWebSocket } = await import('hono/cloudflare-workers')\n this.upgradeWebSocketFn = upgradeWebSocket\n }\n\n // Pass 1: Collect routes into registry + store Hono registration actions\n const actions = new WeakMap<RegisteredRoute, () => void>()\n for (const ControllerClass of controllers) {\n this.collectRoutes(ControllerClass, actions)\n }\n\n // Pass 2: Register in Hono in specificity order from registry\n for (const route of this.registry.all()) {\n actions.get(route)?.()\n }\n\n this.logger.info('Controller registration complete')\n }\n\n /**\n * Pass 1: Collect routes from a controller into RouteRegistry and store Hono actions.\n * Versioning and locale expansion are handled by RouteRegistry.register().\n */\n private collectRoutes(\n ControllerClass: Constructor,\n actions: WeakMap<RegisteredRoute, () => void>,\n ): void {\n const isWsGateway = isGateway(ControllerClass)\n const controllerRoute = getControllerRoute(ControllerClass)\n\n if (!controllerRoute) {\n throw new RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: ${isWsGateway\n ? 'Missing @Gateway decorator or route metadata'\n : 'Missing @Controller decorator or route metadata'}`\n )\n }\n\n const controllerOpts = getControllerOptions(ControllerClass)\n const controllerGuards = getControllerGuards(ControllerClass)?.guards ?? []\n\n // Resolve Router config for this controller (prefix, domain, name, middleware, version, hideFromDocs)\n const routerConfig = this.routerResolver?.resolveForController(ControllerClass) ?? { middleware: [] }\n\n // Class-level @RateLimit decorators — same for every method on this controller.\n // Throttle middleware classes are memoized by name in createThrottleMiddleware,\n // so two `@RateLimit('a')` decorators yield the same class — Set dedupes them.\n const classThrottleMiddleware = Array.from(\n new Set(getRateLimits(ControllerClass).map(createThrottleMiddleware)),\n )\n\n // Apply Router prefix to controller base path\n const basePath = routerConfig.prefix\n ? this.joinPaths(routerConfig.prefix, controllerRoute)\n : controllerRoute\n\n // Version resolution: controller version > Router version\n const effectiveVersion = controllerOpts?.version ?? routerConfig.version\n\n // Apply domain middleware if controller or router has a domain pattern\n const effectiveDomain = controllerOpts?.domain ?? routerConfig.domain\n\n // WebSocket gateway\n if (isWsGateway) {\n // Class-level @RateLimit applies; methods on a gateway aren't decorated routes.\n const wsMiddleware = [...routerConfig.middleware, ...classThrottleMiddleware]\n const expandedRoutes = this.registry.register({\n method: 'ws',\n basePath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: ControllerClass.name,\n action: 'ws',\n hidden: routerConfig.hideFromDocs ?? false,\n middleware: wsMiddleware.map(m => m.name),\n })\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n // Apply scoped middleware at the exact route path so it runs\n // for this specific route (including the root of the group) —\n // not via a `/*` sub-path wildcard, which would miss the exact\n // path match.\n if (wsMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(wsMiddleware))\n }\n // Apply domain middleware\n if (effectiveDomain) {\n const domainHandler = createDomainMiddleware(effectiveDomain)\n this.app.use(route.path, domainHandler)\n this.app.use(`${route.path}/*`, domainHandler)\n }\n this.registerGatewayForPath(ControllerClass, route.path, controllerGuards)\n })\n }\n return\n }\n\n const className = ControllerClass.name\n this.controllerClasses.set(className, ControllerClass)\n\n const prototype = ControllerClass.prototype as IController\n\n // Wildcard routes (non-RESTful controllers with handle())\n if (prototype.handle) {\n // `handle()` never goes through the per-method loop below — the only\n // place `bindRouteCache` runs — so a decorator here would silently\n // never fire and never warn: the exact class of silent failure this\n // task exists to eliminate. Throwing is simpler than computing a\n // binding for a single handler that serves arbitrary sub-paths (its\n // `{param.*}`/tags would need per-request path params a once-resolved\n // binding can't express), and it can be relaxed into real support\n // later without breaking anyone, since today it's a hard boot error.\n if (getCacheable(prototype, 'handle') || getPurgesCache(prototype, 'handle')) {\n throw new ResponseCacheConfigError(\n `${className}.handle: @Cacheable/@PurgesCache is not supported on wildcard controllers ` +\n '(those implementing `handle()`) yet — the decorator would be silently ignored, never ' +\n 'firing and never warning, because wildcard routes do not go through per-method cache ' +\n 'binding. Remove the decorator, or restructure this route as a decorated method.',\n )\n }\n\n // No method-level @RateLimit on wildcard handle() — only class-level applies.\n const wildcardMiddleware = [...routerConfig.middleware, ...classThrottleMiddleware]\n const expandedRoutes = this.registry.register({\n method: 'all',\n basePath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: className,\n action: 'handle',\n hidden: routerConfig.hideFromDocs ?? false,\n middleware: wildcardMiddleware.map(m => m.name),\n })\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n if (wildcardMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(wildcardMiddleware))\n }\n this.registerWildcardRoute(ControllerClass, route.path)\n })\n }\n return\n }\n\n // Standard HTTP routes — validate decorated methods\n const decoratedMethods = getRouteDecoratedMethods(ControllerClass)\n\n if (decoratedMethods.length === 0) {\n throw new RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: No route decorators found. Use @Route() or HTTP method decorators (@Get, @Post, etc.) on controller methods.`\n )\n }\n\n // Pre-cache metadata for all decorated methods (avoids double getRouteMetadata lookup)\n const methodMetadata: { method: string; meta: RouteMetadata }[] = []\n let hasConvention = false\n let hasExplicit = false\n for (const m of decoratedMethods) {\n const meta = getRouteMetadata(prototype, m)\n if (!meta) continue\n methodMetadata.push({ method: m, meta })\n if (meta.type === 'convention') hasConvention = true\n else if (meta.type === 'explicit') hasExplicit = true\n }\n\n // Enforce mutual exclusivity: no mixing @Route() with @Get/@Post/etc.\n if (hasConvention && hasExplicit) {\n throw new RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: Cannot mix @Route() with HTTP method decorators (@Get, @Post, etc.) in the same controller. Use one pattern or the other.`\n )\n }\n\n const routerHidden = routerConfig.hideFromDocs\n const controllerHidden = controllerOpts?.hideFromDocs ?? false\n\n // Resolve effective name prefix: router-level name (module + group merged by\n // RouterResolver) concatenates with the controller-level name, mirroring how\n // prefixes compose. A controller's `{ name: 'dashboard.' }` inside a module\n // that calls `router.name('admin.')` becomes `admin.dashboard.*` — not\n // `dashboard.*`.\n const routerName = routerConfig.name\n const controllerName = controllerOpts?.name\n const effectiveNamePrefix =\n routerName && controllerName\n ? `${routerName}${controllerName}`\n : (routerName ?? controllerName)\n\n for (const { method: methodName, meta } of methodMetadata) {\n const resolved = this.resolveMethodAndPath(meta, methodName, basePath, className)\n if (!resolved) continue\n\n // Compose per-method middleware: scope (router.throttle/.middleware)\n // → class-level @RateLimit → method-level @RateLimit. Throttle classes\n // are memoized by name, so duplicates across class + method (e.g.\n // `@RateLimit('api')` on both) collapse to a single middleware.\n const methodThrottleMiddleware = getRateLimits(prototype, methodName).map(createThrottleMiddleware)\n const effectiveMiddleware = Array.from(\n new Set([...routerConfig.middleware, ...classThrottleMiddleware, ...methodThrottleMiddleware]),\n )\n const middlewareNames = effectiveMiddleware.map(m => m.name)\n\n const { httpMethod, fullPath, routeConfig: rawRouteConfig, statusCodeOverride } = resolved\n\n // Compose prefix params with route-level params WITHOUT mutating the\n // route's metadata — `meta.config` lives on the controller prototype\n // and is shared across every Application/RouteRegistry instance that\n // resolves this controller. Mutating it leaks state across test runs\n // (and any other multi-app setup), causing later registrations to\n // re-extend an already-injected prefix from a previous run.\n let mergedParams = rawRouteConfig.params\n if (routerConfig.params) {\n const prefixShape = (routerConfig.params as ZodObject).shape\n mergedParams = mergedParams\n ? object({ ...(mergedParams as ZodObject).shape, ...prefixShape })\n : routerConfig.params\n }\n const routeConfig: RouteConfig = mergedParams === rawRouteConfig.params\n ? rawRouteConfig\n : { ...rawRouteConfig, params: mergedParams }\n\n const hideFromDocs = routeConfig.hideFromDocs ?? (routerHidden ?? controllerHidden)\n\n // Compute route name\n let routeName: string | undefined\n if (routeConfig.name) {\n routeName = effectiveNamePrefix ? `${effectiveNamePrefix}${routeConfig.name}` : routeConfig.name\n } else if (meta.type === 'convention') {\n const autoName = generateConventionRouteName(basePath, methodName)\n routeName = effectiveNamePrefix ? `${effectiveNamePrefix}${autoName}` : autoName\n }\n\n // Register in RouteRegistry (handles versioning + locale expansion)\n const expandedRoutes = this.registry.register({\n name: routeName,\n method: httpMethod,\n basePath: fullPath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: className,\n action: methodName,\n hidden: hideFromDocs,\n middleware: middlewareNames,\n })\n\n // Collect guards — avoid spread when no method-level guards (common case)\n const methodGuards = getMethodGuards(prototype, methodName)?.guards ?? []\n const allGuards: Guard[] = methodGuards.length > 0\n ? [...controllerGuards, ...methodGuards]\n : controllerGuards\n\n const responseSchema = httpMethod !== 'all'\n ? this.extractResponseSchema(routeConfig)\n : null\n\n const cacheableOptions = getCacheable(prototype, methodName)\n const purgesCacheOptions = getPurgesCache(prototype, methodName)\n\n const capturesPayload = needsPayloadCapture(cacheableOptions, purgesCacheOptions)\n\n // Resolved once per route, at registration — never per request. Throws\n // at boot for a non-empty `partitionBy` when no gateway entrypoint is\n // configured to honor it; see `bindRouteCache`.\n const cacheBinding = bindRouteCache(\n cacheableOptions,\n purgesCacheOptions,\n this.responseCacheDefaults(),\n {\n controller: className,\n method: methodName,\n guarded: allGuards.length > 0,\n routeParams: extractPathParams(fullPath),\n gatewayConfigured: this.gatewayEntrypoint() !== undefined,\n },\n )\n\n // `@Cacheable`/`@PurgesCache` read as configured intent even when\n // `ResponseCacheModule` was never imported — decorator metadata doesn't\n // require it. Catching that mismatch here, at boot, is the same\n // \"silence is not safe\" reasoning as the no-store stamp below: better a\n // clear startup error than a route that resolves `cacheBinding` and\n // then finds `this.cacheability`/`this.responseCache` are `undefined`\n // on the very first request.\n if (cacheBinding && (!this.cacheability || !this.responseCache)) {\n throw new ResponseCacheConfigError(\n `${className}.${methodName}: @Cacheable/@PurgesCache requires ResponseCacheModule to be ` +\n 'imported. Without it, the decorator would be silently dropped — the route would ' +\n 'register and run normally, just never cache or purge anything, with no warning at ' +\n 'boot or at request time. Add `ResponseCacheModule.forRoot({ defaults: { ttl } })` to ' +\n 'your app\\'s `imports`.',\n )\n }\n\n // Track routes that need ctx.cache for boot-time validation.\n // Both @Cacheable and @PurgesCache routes require it: @Cacheable to apply\n // cache headers, @PurgesCache to purge on successful mutations. An app with\n // only @PurgesCache routes and no cache binding boots cleanly but then 500s\n // on every successful mutation — precisely the silent-until-hit failure this\n // check prevents.\n if (cacheBinding?.cacheable || cacheBinding?.purges) {\n this.cacheableRouteCount++\n }\n\n // A declared partition with no registered resolver would fail closed at\n // request time — correct, but silently uncached forever. Catch the typo\n // at boot instead, where the author still sees it.\n const partitionBy = cacheBinding?.cacheable?.partitionBy ?? []\n if (partitionBy.length > 0) {\n this.partitionResolver?.assertKnown(partitionBy, `${className}.${methodName}`)\n }\n\n const handler = this.createControllerHandler(ControllerClass, methodName, responseSchema, capturesPayload, cacheBinding)\n\n for (const route of expandedRoutes) {\n // Recorded per *expanded* route, so each version/locale variant is\n // keyed under the pattern Hono actually matched. `@All` routes are\n // registered under Hono's `ALL`, which no request method equals — but\n // only GET/HEAD ever loop back, so recording those two is exhaustive.\n if (partitionBy.length > 0) {\n const methods = httpMethod === 'all' ? ['GET', 'HEAD'] : [httpMethod]\n for (const method of methods) {\n this.gatewayRouteTable?.record(method, route.path, partitionBy)\n }\n }\n\n actions.set(route, () => {\n // Apply domain middleware\n if (effectiveDomain) {\n const domainHandler = createDomainMiddleware(effectiveDomain)\n this.app.use(route.path, domainHandler)\n this.app.use(`${route.path}/*`, domainHandler)\n }\n\n if (allGuards.length > 0) {\n this.logger.info(`Route guards`, {\n controller: className,\n method: httpMethod.toUpperCase(),\n path: route.path,\n methodName,\n guardCount: allGuards.length,\n })\n }\n\n // @All routes can't use OpenAPI — register directly with\n // scoped middleware (if any) + guard middleware + handler.\n if (httpMethod === 'all') {\n this.logger.info(`Registering @All route`, {\n controller: className,\n path: route.path,\n methodName,\n })\n\n if (effectiveMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(effectiveMiddleware))\n }\n if (allGuards.length > 0) {\n this.app.use(route.path, this.createGuardMiddleware(allGuards))\n }\n this.app.all(route.path, handler)\n return\n }\n\n // Build per-route validators from declared schemas. A route with no\n // params/query/body declares none, so it attaches no validator and\n // pulls in no zod at all.\n const isLocaleVariant = route.isLocaleVariant ?? false\n const body = this.resolveBody(routeConfig)\n const validators = buildRouteValidators({\n params: routeConfig.params as ZodType | undefined,\n query: routeConfig.query as ZodType | undefined,\n body,\n isLocaleVariant,\n })\n\n // Wrap the controller handler so scoped middleware and guards run\n // AFTER the request validators (which populate `c.req.valid(...)`).\n // Final order: global app.use → request validators → scoped\n // middleware → guards → controller handler.\n const wrappedHandler = this.wrapHandlerWithChain(handler, effectiveMiddleware, allGuards)\n\n this.logger.info(`Registering route`, {\n controller: className,\n method: httpMethod.toUpperCase(),\n path: route.path,\n methodName,\n hidden: route.hidden,\n })\n\n // Path passed as a single-element array to match Hono's variadic\n // `on(method, paths, ...handlers)` overload (validators are a\n // variable-length list, so the fixed-arity overloads don't apply).\n this.app.on(httpMethod.toUpperCase(), [route.path], ...validators, wrappedHandler)\n\n // Collect schema metadata for lazy OpenAPI document generation.\n const metadata = this.mergeMetadata(controllerOpts, routeConfig, ControllerClass, methodName)\n this.metadataRegistry.add(this.buildRouteMetadata({\n method: httpMethod,\n path: route.path,\n routeConfig,\n metadata,\n body,\n methodName: meta.type === 'convention' ? methodName : undefined,\n statusCodeOverride,\n isLocaleVariant,\n hidden: route.hidden,\n }))\n })\n }\n }\n }\n\n\n /**\n * Register a single WebSocket gateway route\n */\n private registerGatewayForPath(\n GatewayClass: Constructor,\n fullPath: string,\n guards: Guard[],\n ): void {\n // Route already registered in RouteRegistry during collectRoutes()\n // Cache WS metadata once at registration time (not per-connection)\n const onMsgMethod = getWsOnMessageMethod(GatewayClass)\n const onCloseMethod = getWsOnCloseMethod(GatewayClass)\n const onErrMethod = getWsOnErrorMethod(GatewayClass)\n\n const wsHandler: MiddlewareHandler<RouterEnv> = this.upgradeWebSocketFn!((c) => {\n const routerCtx = new RouterContext(c as Context<RouterEnv>)\n const container = routerCtx.getContainer()\n const gateway = container.resolve(GatewayClass)\n\n // Cloudflare Workers doesn't support the `onOpen` WebSocket event;\n // the upgrade callback itself serves as the open context.\n const events: Omit<WSEvents, 'onOpen'> = {}\n\n const bindWsHandler = (\n method: string,\n onCatch?: (err: unknown, ws: WSContext) => void\n ) => {\n return (evt: MessageEvent | CloseEvent | Event, ws: WSContext) => {\n const ctx = new GatewayContext(c as Context<RouterEnv>, ws)\n invokeHandler(gateway as Record<string, (...args: unknown[]) => unknown>, method, evt, ctx).catch((err: unknown) => {\n this.logger.error(`WebSocket ${method} handler error`, err as Error, {\n gateway: GatewayClass.name,\n })\n onCatch?.(err, ws)\n })\n }\n }\n\n if (onMsgMethod) {\n events.onMessage = bindWsHandler(onMsgMethod, (_err, ws) => ws.close(1011, 'Internal Error'))\n }\n if (onCloseMethod) {\n events.onClose = bindWsHandler(onCloseMethod)\n } else {\n // Cloudflare Workers (pre-2026-04-07 compat date) requires the server\n // to complete the WebSocket close handshake explicitly. Without a close\n // listener, Hono never calls server.addEventListener('close', ...),\n // leaving the Worker alive until the runtime kills it with\n // \"script will never generate a response\".\n events.onClose = (_evt: CloseEvent, ws: WSContext) => {\n ws.close()\n }\n }\n if (onErrMethod) {\n events.onError = bindWsHandler(onErrMethod)\n }\n\n return events\n }) as MiddlewareHandler<RouterEnv>\n\n this.nameHandler(wsHandler, GatewayClass.name, onMsgMethod ?? '[anonymous]', 'ws')\n\n this.logger.info('Registering WebSocket gateway', {\n gateway: GatewayClass.name,\n path: fullPath,\n })\n\n const handlers: MiddlewareHandler<RouterEnv>[] = []\n\n if (guards.length > 0) {\n this.logger.info('Gateway guards', {\n gateway: GatewayClass.name,\n path: fullPath,\n guardCount: guards.length,\n })\n handlers.push(this.createGuardMiddleware(guards))\n }\n\n handlers.push(wsHandler)\n\n // Type assertion needed because Hono's overloaded .get() signatures\n // don't accept a spread of MiddlewareHandler[] alongside upgradeWebSocket's output type\n this.app.get(fullPath, ...(handlers as [MiddlewareHandler<RouterEnv>]))\n }\n\n\n /**\n * Create a guard execution middleware\n *\n * This middleware executes all guards for a route before the handler.\n * Guards are executed in order; all must pass for the request to proceed.\n *\n * @param guards - Array of guards to execute\n * @returns Hono middleware function\n */\n private createGuardMiddleware(guards: Guard[]) {\n const guardService = new GuardExecutionService(this.logger)\n\n return async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const ctx = new RouterContext(c)\n const container = ctx.getContainer()\n\n // Execute all guards - throws on failure\n await guardService.executeGuards(guards, ctx, container)\n\n // All guards passed, continue to handler\n await next()\n }\n }\n\n /**\n * Wrap a controller handler with a `scopedMiddleware → guards → handler`\n * chain that runs *inside* the Hono route handler — after request\n * validators have populated `c.req.valid(...)`. This is the only place\n * we can run user middleware after `@hono/zod-openapi`'s validators in\n * the same pipeline.\n *\n * Returns a Hono handler with the same signature as the original so\n * `app.openapi(route, wrapped)` works transparently.\n */\n private wrapHandlerWithChain(\n handler: (c: Context<RouterEnv>) => Promise<Response>,\n scopedMiddleware: Constructor<Middleware>[],\n guards: Guard[],\n ) {\n if (scopedMiddleware.length === 0 && guards.length === 0) {\n return handler\n }\n\n const scopedChain = scopedMiddleware.length > 0\n ? createMiddlewareChain(scopedMiddleware)\n : null\n const guardChain = guards.length > 0\n ? this.createGuardMiddleware(guards)\n : null\n\n return async (c: Context<RouterEnv, string>): Promise<Response> => {\n let captured: Response | undefined\n\n const runHandler = async () => {\n captured = await handler(c)\n }\n const runGuards = guardChain\n ? () => guardChain(c, runHandler)\n : runHandler\n const runScoped = scopedChain\n ? () => scopedChain(c, runGuards)\n : runGuards\n\n const result = await runScoped()\n // A middleware (scoped or guard) may short-circuit by returning a\n // Response from its createMiddlewareChain — surface that. Otherwise\n // the handler always sets `captured`.\n if (result instanceof Response) return result\n return captured!\n }\n }\n\n /**\n * Register wildcard route for non-RESTful controllers\n */\n private registerWildcardRoute(\n ControllerClass: Constructor,\n route: string\n ): void {\n this.logger.info(`Registering wildcard route`, {\n controller: ControllerClass.name,\n route: `${route}/:path{.+}`,\n method: 'ALL',\n })\n\n const handler = this.createControllerHandler(ControllerClass, 'handle')\n // Match base route exactly\n this.app.all(route, handler)\n // Match all sub-paths using named regex wildcard\n this.app.all(`${route}/:path{.+}`, handler)\n }\n\n\n /**\n * Resolve HTTP method, path, route config, and status code from route metadata.\n */\n private resolveMethodAndPath(\n meta: RouteMetadata,\n methodName: string,\n basePath: string,\n className: string\n ): { httpMethod: HttpMethod; fullPath: string; routeConfig: RouteConfig; statusCodeOverride?: number } | null {\n if (meta.type === 'convention') {\n const derived = this.deriveHttpMethodAndPath(methodName, basePath)\n if (!derived) {\n throw new RouterError(\n `Cannot derive HTTP method/path for convention-based route \"${className}.${methodName}\". ` +\n `Ensure the method name follows the naming convention (e.g., index, create, show).`\n )\n }\n return { httpMethod: derived.method, fullPath: derived.path, routeConfig: meta.config, statusCodeOverride: meta.config.statusCode }\n }\n\n return {\n httpMethod: meta.method,\n fullPath: this.joinPaths(basePath, meta.path),\n routeConfig: meta.config,\n statusCodeOverride: meta.config.statusCode,\n }\n }\n\n /**\n * Join a base path and a route path, normalizing slashes\n */\n private joinPaths(basePath: string, routePath: string): string {\n if (basePath.endsWith('/')) basePath = basePath.slice(0, -1)\n if (routePath === '/' || routePath === '') return basePath || '/'\n if (!routePath.startsWith('/')) routePath = '/' + routePath\n return basePath + routePath\n }\n\n\n /**\n * Auto-derive HTTP method and path from controller method name\n * Uses HTTP_METHODS constant for RESTful convention mapping\n */\n private deriveHttpMethodAndPath(methodName: string, basePath: string): { method: Exclude<HttpMethod, 'all'>; path: string } | null {\n if (!(methodName in HTTP_METHODS)) return null\n const mapping = HTTP_METHODS[methodName as keyof typeof HTTP_METHODS]\n\n return {\n method: mapping.method as Exclude<HttpMethod, 'all'>,\n path: basePath + mapping.path,\n }\n }\n\n /**\n * Merge controller-level and route-level metadata\n * Tags are merged (appended), security is merged (union)\n * Guards automatically add sessionCookie security if present\n */\n private mergeMetadata(\n controllerOpts: ControllerOptions | undefined,\n routeConfig: RouteConfig,\n ControllerClass: Constructor,\n methodName: string\n ): { tags: string[]; security: SecuritySchemeRecord[]; groups: string[] } {\n const tags = [...(controllerOpts?.tags ?? []), ...(routeConfig.tags ?? [])]\n const groups = [...(controllerOpts?.groups ?? []), ...(routeConfig.groups ?? [])]\n\n // Check if guards are present (indicates authentication is required)\n const prototype = ControllerClass.prototype as IController\n const hasMethodGuards = (getMethodGuards(prototype, methodName)?.guards.length ?? 0) > 0\n const hasControllerGuards = (getControllerGuards(ControllerClass)?.guards.length ?? 0) > 0\n const requiresAuth = hasMethodGuards || hasControllerGuards\n\n // Merge security: if route explicitly sets security (even empty array), use it\n // Otherwise inherit from controller\n let security: string[] = []\n if (routeConfig.security !== undefined) {\n // Route has explicit security (could be empty for public routes)\n security = [...(controllerOpts?.security ?? []), ...routeConfig.security]\n } else if (controllerOpts?.security) {\n // Inherit controller security\n security = controllerOpts.security\n }\n\n // Auto-add sessionCookie security if guards are present\n if (requiresAuth && !security.includes(SECURITY_SCHEMES.SESSION_COOKIE)) {\n security.push(SECURITY_SCHEMES.SESSION_COOKIE)\n }\n\n // Convert security array to OpenAPI security format\n const securityArray: SecuritySchemeRecord[] =\n security.length > 0\n ? (security.map<SecuritySchemeRecord>((scheme) => ({ [scheme]: [] }) as unknown as SecuritySchemeRecord))\n : ([] as SecuritySchemeRecord[])\n\n return { tags, security: securityArray, groups }\n }\n\n /**\n * Resolve a route's request body into its schema + content type, normalizing\n * the bare-schema and `{ schema, contentType }` forms. Returns `undefined`\n * when no body is declared. Shared by validator construction and metadata.\n */\n private resolveBody(routeConfig: RouteConfig): { schema: ZodType; contentType: string } | undefined {\n if (!routeConfig.body) return undefined\n const schema = (this.isRouteBodyObject(routeConfig.body) ? routeConfig.body.schema : routeConfig.body)\n const contentType = this.isRouteBodyObject(routeConfig.body)\n ? routeConfig.body.contentType ?? DEFAULT_CONTENT_TYPE\n : DEFAULT_CONTENT_TYPE\n return { schema, contentType }\n }\n\n /**\n * Build the schema metadata entry for a route. Consumed lazily by the OpenAPI\n * generator — common error responses are added there, not here, so\n * `common.schemas` (and the schemas it references) never reach the routing\n * path. The `locale` path param of a localized route is recorded as plain\n * metadata (enforced by the route pattern, read via `getLocale()`), so no zod\n * enum is constructed at registration.\n */\n private buildRouteMetadata(input: {\n method: Exclude<HttpMethod, 'all'>\n path: string\n routeConfig: RouteConfig\n metadata: { tags: string[]; security: SecuritySchemeRecord[]; groups: string[] }\n body?: { schema: ZodType; contentType: string }\n methodName?: string\n statusCodeOverride?: number\n isLocaleVariant?: boolean\n hidden?: boolean\n }): RouteSchemaMeta {\n const { routeConfig, metadata } = input\n const successStatus: number = input.statusCodeOverride\n ?? (input.methodName ? METHOD_STATUS_CODES[input.methodName as keyof typeof METHOD_STATUS_CODES] : undefined)\n ?? 200\n\n const responses: RouteResponseMeta[] = []\n const responseDef = routeConfig.response\n if (responseDef && this.isRouteResponseObject(responseDef)) {\n responses.push({\n status: successStatus,\n schema: responseDef.schema,\n contentType: responseDef.contentType ?? DEFAULT_CONTENT_TYPE,\n description: responseDef.description ?? `Response ${successStatus}`,\n })\n } else {\n responses.push({\n status: successStatus,\n schema: responseDef,\n contentType: DEFAULT_CONTENT_TYPE,\n description: `Response ${successStatus}`,\n })\n }\n\n const localeConfig = this.localePathService.localePathConfig\n const localeParam = input.isLocaleVariant && localeConfig\n ? { name: 'locale', values: localeConfig.prefixedLocales }\n : undefined\n\n const entry: RouteSchemaMeta = {\n method: input.method,\n path: toOpenAPIPath(input.path),\n hidden: input.hidden ?? false,\n tags: metadata.tags,\n security: metadata.security,\n request: {\n params: routeConfig.params as ZodType | undefined,\n query: routeConfig.query as ZodType | undefined,\n body: input.body,\n },\n responses,\n localeParam,\n }\n if (routeConfig.summary) entry.summary = routeConfig.summary\n if (routeConfig.description) entry.description = routeConfig.description\n if (metadata.groups.length > 0) entry.groups = metadata.groups\n return entry\n }\n\n /**\n * Check if a body definition is a RouteBodyObject (has schema key) vs bare ZodType\n */\n private isRouteBodyObject(body: RouteConfig['body']): body is RouteBodyObject {\n return typeof body === 'object' && 'schema' in body\n }\n\n /**\n * Resolve method parameter injections from the container\n *\n * @param prototype - Controller prototype\n * @param methodName - Method name to get injections for\n * @param container - Request-scoped container\n * @returns Array of resolved dependencies in parameter order\n */\n private resolveMethodInjections(\n prototype: object,\n methodName: string,\n container: Container\n ): unknown[] {\n const injections = getMethodInjections(prototype, methodName)\n if (!injections.length) return []\n\n return injections.map((inj): unknown => container.resolve(inj.token))\n }\n\n /**\n * Name a handler function so Hono's inspectRoutes() can identify it.\n * Format: `{type}:{Controller}.{method}` (e.g. `http:UsersController.create`)\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- intentionally accepting any function to set its name\n private nameHandler(fn: Function, controller: string, method: string, type: 'http' | 'ws' = 'http'): void {\n Object.defineProperty(fn, 'name', { value: `${type}:${controller}.${method}` })\n }\n\n /**\n * Create controller handler that resolves controller from request-scoped container\n * This ensures each request gets a fresh controller with request-scoped context\n */\n private createControllerHandler(\n ControllerClass: new (...args: unknown[]) => IController,\n methodName: string,\n responseSchema: ZodType | null = null,\n capturesPayload = false,\n cacheBinding?: RouteCacheBinding,\n ): (c: Context<RouterEnv>) => Promise<Response> {\n const handler = async (c: Context<RouterEnv>) => {\n // Precognition short-circuit: HandlePrecognitiveRequests middleware\n // sets `validationSuccessResponse` for `Precognition: true` requests.\n // If we reach here, every request validator has passed — return the\n // 204 without invoking the controller body. Not stamped here — the\n // outermost `createNoStoreFallbackMiddleware` catches every response\n // that reaches Hono without a `Cache-Control`, this one included.\n const override = c.get('validationSuccessResponse')\n if (override) return override\n\n const ctx = new RouterContext(c)\n const requestContainer = ctx.getContainer()\n const controller = requestContainer.resolve<IController>(ControllerClass)\n\n const method = controller[methodName as keyof IController]\n if (typeof method === 'function') {\n const injectedArgs = this.resolveMethodInjections(ControllerClass.prototype as object, methodName, requestContainer)\n const response = await (method as (...args: unknown[]) => Promise<Response>).apply(controller, [ctx, ...injectedArgs])\n\n if (capturesPayload) await capturePayload(c, response)\n\n const validated = responseSchema && c.env.ENVIRONMENT !== 'production'\n ? await this.validateResponse(response, responseSchema)\n : response\n\n return this.applyCacheDecision(c, validated, cacheBinding, {\n controller: ControllerClass.name,\n method: methodName,\n })\n }\n\n throw new RouterError(`Method \"${methodName}\" not found on controller \"${ControllerClass.name}\"`)\n }\n\n this.nameHandler(handler, ControllerClass.name, methodName)\n return handler\n }\n\n /**\n * Apply this route's `@Cacheable`/`@PurgesCache` decision, if it has one.\n *\n * Deliberately does **not** stamp `no-store` for the \"nothing to do\" case\n * (`!cacheBinding`, or `cacheBinding.cacheable` absent) — the outermost\n * `createNoStoreFallbackMiddleware` (registered in `HonoApp`) catches every\n * response that reaches Hono without a `Cache-Control`, this one included,\n * so every response still gets an explicit decision without every call\n * site needing to know that. This function only needs to handle the\n * positive cases: computing `@Cacheable` headers, and firing `@PurgesCache`.\n *\n * `@PurgesCache` fires independently of `@Cacheable` — the common case is\n * a mutation route (create/update/destroy) that isn't itself cacheable but\n * must invalidate a GET route's cached entries on success. Gating the\n * purge on `cacheBinding.cacheable` would silently skip that purge.\n *\n * **Headers stamped here are not the last word.** This runs *inside* the\n * Hono route handler, so any outbound middleware — anything doing work\n * after its own `await next()` — sees the response afterwards and can\n * overwrite `Vary`, `Cache-Control`, or `Set-Cookie` with a plain\n * `c.header(name, value)`, which replaces rather than appends. That is\n * silent: the route still looks cached, but (for `Vary`) every variant\n * collapses onto one entry. Middleware that contributes to any of these\n * three headers must **merge** with what is already on the response, never\n * set it outright — see `InertiaMiddleware`'s `Vary: X-Inertia` handling\n * for the shape that fix takes.\n */\n private async applyCacheDecision(\n c: Context<RouterEnv>,\n response: Response,\n cacheBinding: RouteCacheBinding | undefined,\n routeContext: { controller: string; method: string },\n ): Promise<Response> {\n if (!cacheBinding) return response\n\n let scopes: TagScopes | undefined\n let result = response\n\n if (cacheBinding.cacheable && this.cachingAvailable(c)) {\n // Not \"guaranteed non-null and defensively re-checked\" — an actual\n // invariant. `collectRoutes` throws at registration if a route\n // resolves a `cacheBinding` while `ResponseCacheModule` was never\n // imported, so reaching here without `cacheability` set means that\n // guard itself is broken. Throwing surfaces that immediately; quietly\n // falling through to \"not cacheable\" would mask the exact gap this\n // task closed.\n if (!this.cacheability) {\n throw new ResponseCacheConfigError(\n 'internal error: a route resolved a `@Cacheable` binding but CacheabilityService is ' +\n 'unavailable. This should have been caught at registration — please file a bug.',\n )\n }\n\n scopes = this.buildTagScopes(c)\n result = this.cacheability.apply(result, cacheBinding.cacheable, scopes, {\n partitionsResolved: this.partitionsResolved(c, cacheBinding.cacheable.partitionBy),\n // Only ever populated when `@stratal/inertia` rendered this response\n // (`InertiaService.render()` sets it) — `undefined` on every other\n // route, which `CacheabilityService.rejectionReason` treats as \"no\n // Inertia-specific reason to reject\".\n inertia: c.get('inertiaCacheSignals'),\n })\n }\n\n if (cacheBinding.purges && result.status >= 200 && result.status < 400) {\n if (!this.responseCache) {\n throw new ResponseCacheConfigError(\n 'internal error: a route resolved a `@PurgesCache` binding but ResponseCacheService is ' +\n 'unavailable. This should have been caught at registration — please file a bug.',\n )\n }\n\n scopes ??= this.buildTagScopes(c)\n const cache = this.executionCache(c)\n\n // Nothing to invalidate: a purge names entries this entrypoint stored,\n // and an entrypoint with no cache stored none. The mutation itself has\n // already committed, so failing here would report a write that\n // succeeded as an error, to undo work that does not exist. The reason\n // caching is unavailable is reported once by `cachingAvailable`.\n if (!cache) return result\n\n let spec: PurgeSpec\n try {\n spec = this.responseCache.buildPurgeSpec(cacheBinding.purges, scopes)\n } catch (error) {\n // `buildPurgeSpec` renders this route's `@PurgesCache` tags, which\n // throws `InvalidCacheTagError` when a referenced value is missing —\n // `{query.tenant}` on a request with no `?tenant=`, `{data.categoryId}`\n // when the handler's own payload lacks that key. It is evaluated\n // *before* `this.responseCache.purge(...)` is ever entered, so\n // `purge`'s own try/catch (and its `logger.error`) never runs — left\n // unlogged, this would 500 with no signal anywhere, after the\n // mutation already committed. Log it here, at the only place that\n // still has the request's context, then rethrow as `CachePurgeError`\n // — the contract every other purge failure already uses — so a\n // caller catching purge failures only ever has one type to handle.\n const detail = error instanceof Error ? error.message : String(error)\n this.logger.error('[stratal:response-cache] Failed to render @PurgesCache tags', {\n controller: routeContext.controller,\n action: routeContext.method,\n path: c.req.routePath,\n error: detail,\n })\n throw new CachePurgeError(detail, error)\n }\n\n await this.responseCache.purge(spec, cache)\n }\n\n return result\n }\n\n /**\n * Whether this request's declared partitions are actually in the cache key.\n *\n * Reaching a controller **inline while running as the gateway** is, for a\n * route with a non-empty `partitionBy`, proof that they are not: the\n * dispatch middleware forwards every such `GET`/`HEAD` whose partitions it\n * could resolve, so the only way one arrives here is that it declined —\n * an unresolved resolver, a resolver that threw, or a primer that\n * short-circuited. Reporting `true` there would stamp\n * `Cache-Control: public, max-age=…` on a response the author declared\n * per-caller, and while the gateway's own Workers cache is disabled, that\n * header still travels to the client and to every intermediary between\n * them. One user's dashboard in a shared proxy cache is exactly the leak\n * `partitionBy` exists to prevent, so it fails closed instead.\n *\n * Inside the cached entrypoint the partitions normally *are* in the key,\n * because the gateway chose `ctx.props` before forwarding. But that is the\n * caller's claim, not a fact, and this entrypoint is reachable by anything\n * that can name it — another Worker's service binding, a misrouted export,\n * or our own gateway having selected an overlapping route's binding. So it\n * is checked rather than trusted: every partition this route declared must\n * be present in `ctx.props`. A caller that supplies none, or only some, gets\n * `private, no-store` instead of a shared entry.\n *\n * With **no execution context at all** — `hono.fetch(request, env)`, which\n * `quarry api` and `mcp serve` both do — there is no way to tell those cases\n * apart, so unknown means uncacheable.\n *\n * An app with no gateway configured can never have a non-empty\n * `partitionBy` (`bindRouteCache` rejects it at boot), so this returns\n * `true` on the first line for every app that doesn't use the feature.\n */\n private partitionsResolved(c: Context<RouterEnv>, partitionBy: string[]): boolean {\n if (partitionBy.length === 0) return true\n\n let ctx: CacheCapableExecutionContext\n try {\n ctx = c.executionCtx\n } catch {\n return false\n }\n\n if (isGatewayMode(ctx)) return false\n\n const props = ctx.props\n return partitionBy.every((name) => props?.[name] !== undefined)\n }\n\n /**\n * `c.executionCtx` is a Hono getter that throws when the context wasn't\n * constructed with one (e.g. a bare `app.fetch(request)` in a unit test) —\n * unlike a plain optional property, there's no way to read it without a\n * `try`/`catch` when it might be absent. `cache` itself is optional even\n * when `executionCtx` exists: Wrangler only attaches it when `cache.enabled\n * = true` is configured.\n *\n * The cast is necessary despite `@cloudflare/workers-types` declaring\n * `cache?: CacheContext` on the *runtime* `ExecutionContext` — Hono's\n * `Context.executionCtx` getter is typed against Hono's own narrower\n * `ExecutionContext` interface (`waitUntil`/`passThroughOnException`/`props`\n * only), not Cloudflare's, so TypeScript doesn't know `.cache` exists on\n * what it returns even though the object handed to it at runtime does.\n *\n * **In gateway mode with a gateway configured, this is deliberately not\n * `ctx.cache`.** Only partitioned `GET`/`HEAD` requests are forwarded to the\n * cached entrypoint; every mutation — and so every `@PurgesCache` — runs\n * inline in the gateway, whose Wrangler config sets `cache: { enabled:\n * false }`. Purges are scoped to the entrypoint that issues them, so an\n * inline purge would either find no `ctx.cache` at all (and 500 a mutation\n * that already committed) or, if caching were left on for the gateway, purge\n * the gateway's own cache — reporting success while invalidating nothing and\n * leaving every cached read stale until its TTL ran out. Routing it over RPC\n * to the cached entrypoint puts the purge where the entries actually live.\n */\n /**\n * Whether the entrypoint serving this request can cache.\n *\n * Reported once per entrypoint, at error level, because an app that declares\n * `@Cacheable` and gets no caching is misconfigured somewhere — in a\n * deployment that omitted `cache.enabled`, or in a local runtime that has no\n * Workers Caching to offer. Either way its routes then serve uncached and\n * say so in the response, rather than advertising a freshness nothing keeps.\n */\n private cachingAvailable(c: Context<RouterEnv>): boolean {\n const gateway = this.isGatewayRequest(c)\n const known = this.cachingAvailability.get(gateway)\n if (known !== undefined) return known\n\n const reason = cachingUnavailableReason(this.cacheableRouteCount, this.executionCache(c))\n this.cachingAvailability.set(gateway, reason === undefined)\n\n if (reason !== undefined) this.logger.error(`[stratal:response-cache] ${reason}`)\n\n return reason === undefined\n }\n\n /**\n * Whether this request came in through the gateway rather than the cached\n * entrypoint. Both run the same Hono app over the same isolate, and only the\n * execution context tells them apart.\n */\n private isGatewayRequest(c: Context<RouterEnv>): boolean {\n try {\n return isGatewayMode(c.executionCtx)\n } catch {\n return false\n }\n }\n\n private executionCache(c: Context<RouterEnv>): WorkersCache | undefined {\n let ctx: CacheCapableExecutionContext\n try {\n ctx = c.executionCtx\n } catch {\n return undefined\n }\n\n const entrypoint = this.gatewayEntrypoint()\n if (entrypoint !== undefined && isGatewayMode(ctx)) {\n return createLoopbackPurgeTarget(ctx, entrypoint)\n }\n\n return ctx.cache\n }\n\n /**\n * Values available to `{scope.path}` cache tag templates for this request.\n *\n * `body` is deliberately `undefined`: the parsed request body isn't cheaply\n * available at this point in the pipeline, and re-parsing it here would add\n * a second parse to every request on the hot path just to support a rarely\n * used tag scope. A `{body.*}` tag can therefore never resolve — but that's\n * never discovered here, or at request time at all: `bindRouteCache`\n * rejects any `@Cacheable`/`@PurgesCache` tag using the `body` scope at\n * route registration, so a route that reaches this method never has one to\n * render. (It was never true that both services \"fail closed\" on this —\n * `CacheabilityService` does, but `@PurgesCache`'s `renderTags` call has no\n * surrounding try/catch, so letting a `{body.*}` tag through would 500 the\n * request after its mutation already committed, which is exactly why the\n * boot-time check exists.)\n */\n private buildTagScopes(c: Context<RouterEnv>): TagScopes {\n return {\n param: c.req.param(),\n query: c.req.query(),\n body: undefined,\n data: c.get(ROUTER_CONTEXT_KEYS.RESPONSE_PAYLOAD),\n partition: this.partitionValues(c),\n }\n }\n\n /**\n * The partition values Cloudflare is keying this response on.\n *\n * Read from `ctx.props`, which is where the gateway put them and what the\n * cache key is actually built from — so a `{partition.x}` tag names the same\n * value the entry is stored under, on every variant of it.\n *\n * Empty when there is no execution context, or when running as the gateway\n * (whose own responses are never stored). A tag naming a partition that is\n * absent then fails to render, which fails the response closed — the right\n * outcome, since the partition it claimed to be keyed by is not in the key.\n */\n private partitionValues(c: Context<RouterEnv>): Record<string, string> {\n let ctx: CacheCapableExecutionContext\n try {\n ctx = c.executionCtx\n } catch {\n return {}\n }\n\n if (isGatewayMode(ctx)) return {}\n\n const values: Record<string, string> = {}\n for (const [name, value] of Object.entries(ctx.props ?? {})) {\n if (typeof value === 'string') values[name] = value\n }\n return values\n }\n\n /**\n * Extract the Zod schema from a RouteResponse definition.\n * Returns null for non-JSON content types or when no response is defined.\n */\n private extractResponseSchema(routeConfig: RouteConfig): ZodType | null {\n const responseDef = routeConfig.response\n if (!responseDef) return null\n\n if (this.isRouteResponseObject(responseDef)) {\n const contentType = responseDef.contentType ?? DEFAULT_CONTENT_TYPE\n if (!contentType.includes('application/json')) return null\n return responseDef.schema\n }\n\n return responseDef\n }\n\n /**\n * Check if a response definition is a RouteResponseObject (has schema key) vs bare ZodType\n */\n private isRouteResponseObject(response: RouteConfig['response']): response is RouteResponseObject {\n return typeof response === 'object' && 'schema' in response\n }\n\n /**\n * Validate a Response body against its declared Zod schema.\n *\n * Skips validation for:\n * - Non-JSON content types\n * - Empty bodies (204 No Content, 304 Not Modified)\n *\n * Clones the response to read the body without consuming the original stream.\n */\n private async validateResponse(response: Response, schema: ZodType): Promise<Response> {\n const contentType = response.headers.get('content-type')\n if (!contentType || !contentType.includes('application/json')) {\n return response\n }\n\n if (response.status === 204 || response.status === 304) {\n return response\n }\n\n const cloned = response.clone()\n\n let body: unknown\n try {\n body = await cloned.json()\n } catch {\n return response\n }\n\n const result = await schema.safeParseAsync(body)\n if (!result.success) {\n throw new ResponseValidationError(result.error)\n }\n\n return response\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
- import { b as ROUTER_TOKENS, l as Singleton, p as inject } from "./di-D7qmrAir.mjs";
3
- import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
4
- import { o as RouterError } from "./module-registry-NxX5O0Qk.mjs";
5
- import { a as sortRoutesBySpecificity, n as extractParamNames, t as extractDomainParamNames } from "./route-name-DGoBOfPg.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { C as ROUTER_TOKENS, l as Singleton, p as inject } from "./di-DQ3xbjgf.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-C79yt3Wt.mjs";
4
+ import { o as RouterError } from "./module-registry-lkQPDuQe.mjs";
5
+ import { n as extractParamNames, o as sortRoutesBySpecificity, t as extractDomainParamNames } from "./route-name-BslSbmMP.mjs";
6
6
  //#region src/router/route-registry.ts
7
7
  var route_registry_exports = /* @__PURE__ */ __exportAll({ RouteRegistry: () => RouteRegistry });
8
8
  const CONCRETE_HTTP_METHODS = [
@@ -120,4 +120,4 @@ RouteRegistry = __decorate([
120
120
  //#endregion
121
121
  export { route_registry_exports as n, RouteRegistry as t };
122
122
 
123
- //# sourceMappingURL=route-registry-BvLJisvK.mjs.map
123
+ //# sourceMappingURL=route-registry-DFz9_-N6.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-registry-BvLJisvK.mjs","names":[],"sources":["../src/router/route-registry.ts"],"sourcesContent":["import { inject } from '../di'\nimport { Singleton } from '../di/decorators'\nimport { type VERSION_NEUTRAL } from './constants'\nimport { RouterError } from './router.error'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { LocalePathService } from './services/locale-path.service'\nimport type { VersioningService } from './services/versioning.service'\nimport type { HttpMethod } from './types'\nimport { sortRoutesBySpecificity } from './utils/path'\nimport { extractDomainParamNames, extractParamNames } from './utils/route-name'\n\nconst CONCRETE_HTTP_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'] as const\n\n/**\n * A single registered route in the application.\n * Tracks both named and unnamed routes, HTTP and WebSocket.\n */\nexport interface RegisteredRoute {\n /** Route name for URL generation (undefined = unnamed, still tracked) */\n name?: string\n /** HTTP method or 'ws' for WebSocket gateways */\n method: HttpMethod | 'ws'\n /** Primary path in Hono-style :param format */\n path: string\n /** Locale-prefixed path variants (e.g., '/:locale/users/:id') */\n localePaths?: string[]\n /** Parameter names extracted from path */\n paramNames: string[]\n /** Domain pattern (e.g., '{tenant}.example.com') */\n domain?: string\n /** Parameter names extracted from domain */\n domainParamNames: string[]\n /** Controller class name */\n controller: string\n /** Controller method name */\n action: string\n /** Whether the route is hidden from OpenAPI docs */\n hidden: boolean\n /** Middleware class names applied to this route */\n middleware: string[]\n /** Whether this is a locale-prefixed variant */\n isLocaleVariant?: boolean\n}\n\n/**\n * Input for registering a route. The registry auto-extracts param names\n * and expands versioned/locale paths via injected services.\n */\nexport type RouteRegistrationInput = Omit<RegisteredRoute, 'paramNames' | 'domainParamNames' | 'path' | 'localePaths' | 'isLocaleVariant'> & {\n /** Base path before versioning/locale expansion */\n basePath: string\n /** Version from controller/router config (used by VersioningService). Accepts VERSION_NEUTRAL symbol. */\n version?: string | string[] | typeof VERSION_NEUTRAL\n /** Pre-computed param names (optional, auto-extracted if omitted) */\n paramNames?: string[]\n /** Pre-computed domain param names (optional, auto-extracted if omitted) */\n domainParamNames?: string[]\n}\n\n/**\n * Central registry for all application routes.\n * Single source of truth — used by `route:list`, `route:types`, and URL generation.\n *\n * Routes are automatically expanded via VersioningService and LocalePathService\n * during registration, and sorted by specificity when retrieved via `all()`.\n *\n * Registered as a singleton in the container.\n */\n@Singleton()\nexport class RouteRegistry {\n private readonly routes: RegisteredRoute[] = []\n private readonly namedRoutes = new Map<string, RegisteredRoute>()\n private _sortedCache: RegisteredRoute[] | null = null\n private _routeToNameCache: Map<string, string> | null = null\n\n constructor(\n @inject(ROUTER_TOKENS.VersioningService) private readonly versioningService: VersioningService,\n @inject(ROUTER_TOKENS.LocalePathService) private readonly localePathService: LocalePathService,\n ) { }\n\n /**\n * Register a route. Expands via VersioningService + LocalePathService.\n * Named routes must have unique names.\n *\n * @returns Array of expanded RegisteredRoute entries (primary + locale variants)\n * @throws RouterError if a named route with the same name already exists\n */\n register(input: RouteRegistrationInput): RegisteredRoute[] {\n const domainParamNames = input.domainParamNames ?? (input.domain ? extractDomainParamNames(input.domain) : [])\n\n // Expand via VersioningService\n const versionedPaths = this.versioningService.resolve(input.basePath, input.version)\n\n const expandedRoutes: RegisteredRoute[] = []\n const localeEnabled = this.localePathService.enabled\n\n for (const versionedPath of versionedPaths) {\n // Expand via LocalePathService\n const resolvedPaths = this.localePathService.resolve(versionedPath)\n\n // Collect locale variant paths only when locale paths are enabled\n let localeVariantPaths: string[] | undefined\n if (localeEnabled) {\n const variants = resolvedPaths.filter(p => p.isLocaleVariant)\n localeVariantPaths = variants.length > 0 ? variants.map(p => p.path) : undefined\n }\n\n for (const resolved of resolvedPaths) {\n const route: RegisteredRoute = {\n name: resolved.isLocaleVariant ? undefined : input.name,\n method: input.method,\n path: resolved.path,\n localePaths: resolved.isLocaleVariant ? undefined : localeVariantPaths,\n paramNames: extractParamNames(resolved.path),\n domain: input.domain,\n domainParamNames,\n controller: input.controller,\n action: input.action,\n hidden: input.hidden,\n middleware: input.middleware,\n isLocaleVariant: resolved.isLocaleVariant || undefined,\n }\n\n // Register name only for primary routes (not locale variants)\n if (route.name) {\n if (this.namedRoutes.has(route.name)) {\n const existing = this.namedRoutes.get(route.name)!\n throw new RouterError(\n `Duplicate route name \"${route.name}\": already registered by ${existing.controller}.${existing.action}, cannot register ${route.controller}.${route.action}`,\n )\n }\n this.namedRoutes.set(route.name, route)\n }\n\n this.routes.push(route)\n expandedRoutes.push(route)\n }\n }\n\n // Invalidate caches once per register() call, not per route\n this._sortedCache = null\n this._routeToNameCache = null\n\n return expandedRoutes\n }\n\n /** Get a named route by name */\n get(name: string): RegisteredRoute | undefined {\n return this.namedRoutes.get(name)\n }\n\n /** Check if a named route exists */\n has(name: string): boolean {\n return this.namedRoutes.has(name)\n }\n\n /**\n * Resolve a Hono-style route path pattern (e.g. as exposed by `c.req.routePath`)\n * back to its registered name, scoped to the request's HTTP method. Locale variant\n * paths resolve to the canonical primary route name. Method matching is\n * case-insensitive; routes registered with `'all'` resolve under any verb.\n */\n findNameByRoute(method: string, path: string): string | undefined {\n this._routeToNameCache ??= this.buildRouteToNameCache()\n return this._routeToNameCache.get(`${method.toLowerCase()}:${path}`)\n }\n\n private buildRouteToNameCache(): Map<string, string> {\n const cache = new Map<string, string>()\n for (const route of this.namedRoutes.values()) {\n const methods = route.method === 'all' ? CONCRETE_HTTP_METHODS : [route.method]\n const paths = route.localePaths ? [route.path, ...route.localePaths] : [route.path]\n for (const m of methods) {\n for (const p of paths) {\n cache.set(`${m}:${p}`, route.name!)\n }\n }\n }\n return cache\n }\n\n /** Get all routes sorted by specificity (static > param > wildcard, locale variant before its primary) */\n all(): RegisteredRoute[] {\n this._sortedCache ??= sortRoutesBySpecificity(this.routes);\n return this._sortedCache\n }\n\n /** Get only named routes */\n named(): RegisteredRoute[] {\n return [...this.namedRoutes.values()]\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"route-registry-DFz9_-N6.mjs","names":[],"sources":["../src/router/route-registry.ts"],"sourcesContent":["import { inject } from '../di'\nimport { Singleton } from '../di/decorators'\nimport { type VERSION_NEUTRAL } from './constants'\nimport { RouterError } from './router.error'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { LocalePathService } from './services/locale-path.service'\nimport type { VersioningService } from './services/versioning.service'\nimport type { HttpMethod } from './types'\nimport { sortRoutesBySpecificity } from './utils/path'\nimport { extractDomainParamNames, extractParamNames } from './utils/route-name'\n\nconst CONCRETE_HTTP_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'] as const\n\n/**\n * A single registered route in the application.\n * Tracks both named and unnamed routes, HTTP and WebSocket.\n */\nexport interface RegisteredRoute {\n /** Route name for URL generation (undefined = unnamed, still tracked) */\n name?: string\n /** HTTP method or 'ws' for WebSocket gateways */\n method: HttpMethod | 'ws'\n /** Primary path in Hono-style :param format */\n path: string\n /** Locale-prefixed path variants (e.g., '/:locale/users/:id') */\n localePaths?: string[]\n /** Parameter names extracted from path */\n paramNames: string[]\n /** Domain pattern (e.g., '{tenant}.example.com') */\n domain?: string\n /** Parameter names extracted from domain */\n domainParamNames: string[]\n /** Controller class name */\n controller: string\n /** Controller method name */\n action: string\n /** Whether the route is hidden from OpenAPI docs */\n hidden: boolean\n /** Middleware class names applied to this route */\n middleware: string[]\n /** Whether this is a locale-prefixed variant */\n isLocaleVariant?: boolean\n}\n\n/**\n * Input for registering a route. The registry auto-extracts param names\n * and expands versioned/locale paths via injected services.\n */\nexport type RouteRegistrationInput = Omit<RegisteredRoute, 'paramNames' | 'domainParamNames' | 'path' | 'localePaths' | 'isLocaleVariant'> & {\n /** Base path before versioning/locale expansion */\n basePath: string\n /** Version from controller/router config (used by VersioningService). Accepts VERSION_NEUTRAL symbol. */\n version?: string | string[] | typeof VERSION_NEUTRAL\n /** Pre-computed param names (optional, auto-extracted if omitted) */\n paramNames?: string[]\n /** Pre-computed domain param names (optional, auto-extracted if omitted) */\n domainParamNames?: string[]\n}\n\n/**\n * Central registry for all application routes.\n * Single source of truth — used by `route:list`, `route:types`, and URL generation.\n *\n * Routes are automatically expanded via VersioningService and LocalePathService\n * during registration, and sorted by specificity when retrieved via `all()`.\n *\n * Registered as a singleton in the container.\n */\n@Singleton()\nexport class RouteRegistry {\n private readonly routes: RegisteredRoute[] = []\n private readonly namedRoutes = new Map<string, RegisteredRoute>()\n private _sortedCache: RegisteredRoute[] | null = null\n private _routeToNameCache: Map<string, string> | null = null\n\n constructor(\n @inject(ROUTER_TOKENS.VersioningService) private readonly versioningService: VersioningService,\n @inject(ROUTER_TOKENS.LocalePathService) private readonly localePathService: LocalePathService,\n ) { }\n\n /**\n * Register a route. Expands via VersioningService + LocalePathService.\n * Named routes must have unique names.\n *\n * @returns Array of expanded RegisteredRoute entries (primary + locale variants)\n * @throws RouterError if a named route with the same name already exists\n */\n register(input: RouteRegistrationInput): RegisteredRoute[] {\n const domainParamNames = input.domainParamNames ?? (input.domain ? extractDomainParamNames(input.domain) : [])\n\n // Expand via VersioningService\n const versionedPaths = this.versioningService.resolve(input.basePath, input.version)\n\n const expandedRoutes: RegisteredRoute[] = []\n const localeEnabled = this.localePathService.enabled\n\n for (const versionedPath of versionedPaths) {\n // Expand via LocalePathService\n const resolvedPaths = this.localePathService.resolve(versionedPath)\n\n // Collect locale variant paths only when locale paths are enabled\n let localeVariantPaths: string[] | undefined\n if (localeEnabled) {\n const variants = resolvedPaths.filter(p => p.isLocaleVariant)\n localeVariantPaths = variants.length > 0 ? variants.map(p => p.path) : undefined\n }\n\n for (const resolved of resolvedPaths) {\n const route: RegisteredRoute = {\n name: resolved.isLocaleVariant ? undefined : input.name,\n method: input.method,\n path: resolved.path,\n localePaths: resolved.isLocaleVariant ? undefined : localeVariantPaths,\n paramNames: extractParamNames(resolved.path),\n domain: input.domain,\n domainParamNames,\n controller: input.controller,\n action: input.action,\n hidden: input.hidden,\n middleware: input.middleware,\n isLocaleVariant: resolved.isLocaleVariant || undefined,\n }\n\n // Register name only for primary routes (not locale variants)\n if (route.name) {\n if (this.namedRoutes.has(route.name)) {\n const existing = this.namedRoutes.get(route.name)!\n throw new RouterError(\n `Duplicate route name \"${route.name}\": already registered by ${existing.controller}.${existing.action}, cannot register ${route.controller}.${route.action}`,\n )\n }\n this.namedRoutes.set(route.name, route)\n }\n\n this.routes.push(route)\n expandedRoutes.push(route)\n }\n }\n\n // Invalidate caches once per register() call, not per route\n this._sortedCache = null\n this._routeToNameCache = null\n\n return expandedRoutes\n }\n\n /** Get a named route by name */\n get(name: string): RegisteredRoute | undefined {\n return this.namedRoutes.get(name)\n }\n\n /** Check if a named route exists */\n has(name: string): boolean {\n return this.namedRoutes.has(name)\n }\n\n /**\n * Resolve a Hono-style route path pattern (e.g. as exposed by `c.req.routePath`)\n * back to its registered name, scoped to the request's HTTP method. Locale variant\n * paths resolve to the canonical primary route name. Method matching is\n * case-insensitive; routes registered with `'all'` resolve under any verb.\n */\n findNameByRoute(method: string, path: string): string | undefined {\n this._routeToNameCache ??= this.buildRouteToNameCache()\n return this._routeToNameCache.get(`${method.toLowerCase()}:${path}`)\n }\n\n private buildRouteToNameCache(): Map<string, string> {\n const cache = new Map<string, string>()\n for (const route of this.namedRoutes.values()) {\n const methods = route.method === 'all' ? CONCRETE_HTTP_METHODS : [route.method]\n const paths = route.localePaths ? [route.path, ...route.localePaths] : [route.path]\n for (const m of methods) {\n for (const p of paths) {\n cache.set(`${m}:${p}`, route.name!)\n }\n }\n }\n return cache\n }\n\n /** Get all routes sorted by specificity (static > param > wildcard, locale variant before its primary) */\n all(): RegisteredRoute[] {\n this._sortedCache ??= sortRoutesBySpecificity(this.routes);\n return this._sortedCache\n }\n\n /** Get only named routes */\n named(): RegisteredRoute[] {\n return [...this.namedRoutes.values()]\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { $t as getPathSpecificityScore, Ar as SerializedRoute, At as errorResponseSchema, Bt as Delete, Cn as Middleware, Cr as SECURITY_SCHEMES, Ct as SignedUrlOptions, Dr as RouteName, Dt as createDomainMiddleware, Er as RouteMatcher, Et as VerifySignatureMiddleware, Ft as validationErrorResponseSchema, Gt as Controller, Ht as Patch, It as Route, Jt as getControllerVersion, Kt as getControllerOptions, Lt as getRouteDecoratedMethods, Mr as StratalRouteMap, Mt as paginationQuerySchema, Nt as successMessageSchema, Or as RouteParams, Ot as parseDomainPattern, Pt as uuidParamSchema, Qt as generateConventionRouteName, Rt as getRouteMetadata, Sn as HonoApp, Sr as ROUTE_METADATA_KEYS, St as RouterError, Tn as IController, Tr as CurrentRoute, Tt as verifySignedUrl, Ut as Post, Vt as Get, Wt as Put, Xt as extractDomainParamNames, Yt as createMiddlewareChain, Zt as extractParamNames, _n as Router, _r as TrailingSlashMode, _t as StreamingApi, an as applyLocalePrefix, ar as LocaleUrlConfig, bn as LocalePathService, br as HTTP_METHODS, bt as SchemaValidationError, cn as route, cr as RouteConfig, ct as SignedUriOptions, dn as RegisteredRoute, dr as RouteResponseObject, dt as buildRouteUrl, en as sortRoutesBySpecificity, fn as RouteRegistrationInput, fr as RouterEnv, gn as RouteConfigurable, gr as TrailingSlashExclude, gt as SSEStreamingApi, hr as TrailingSlashConfig, ht as SSEMessage, in as resolveTrailingSlash, ir as LocalePathConfig, jr as SerializedRoutes, jt as paginatedResponseSchema, kr as RoutePrefixes, kt as commonErrorSchemas, ln as ROUTER_TOKENS, lr as RouteMetadata, lt as Uri, mn as VersioningService, mr as SecurityScheme, nn as applyTrailingSlash, nr as ConventionRouteMetadata, on as shouldPrefixLocale, or as RouteBody, pn as RouteRegistry, pr as RouterVariables, qt as getControllerRoute, rn as isTrailingSlashExcluded, rr as ExplicitRouteMetadata, sn as stripLocalePrefix, sr as RouteBodyObject, st as RouterContext, tn as toOpenAPIPath, tr as ControllerOptions, un as RouteRegistrationService, ur as RouteResponse, ut as UriOptions, vn as RouterGroupConfig, vr as TrailingSlashOptions, vt as InvalidSignatureError, wn as Next, wr as VERSION_NEUTRAL, wt as signUrl, xn as ResolvedPath, xr as ROUTER_CONTEXT_KEYS, xt as RouteNotFoundError, yn as LocaleUrlService, yr as VersioningOptions, yt as ResponseValidationError, zt as All } from "../index-uybm0bhQ.mjs";
2
- export { All, Controller, type ControllerOptions, type ConventionRouteMetadata, type CurrentRoute, Delete, type ExplicitRouteMetadata, Get, HTTP_METHODS, HonoApp, type IController, InvalidSignatureError, type LocalePathConfig, LocalePathService, type LocaleUrlConfig, LocaleUrlService, type Middleware, type Next, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, type RegisteredRoute, type ResolvedPath, ResponseValidationError, Route, type RouteBody, type RouteBodyObject, type RouteConfig, type RouteConfigurable, type RouteMatcher, type RouteMetadata, type RouteName, RouteNotFoundError, type RouteParams, type RoutePrefixes, type RouteRegistrationInput, RouteRegistrationService, RouteRegistry, type RouteResponse, type RouteResponseObject, Router, RouterContext, type RouterEnv, RouterError, type RouterGroupConfig, type RouterVariables, SECURITY_SCHEMES, type SSEMessage, type SSEStreamingApi, SchemaValidationError, type SecurityScheme, type SerializedRoute, type SerializedRoutes, type SignedUriOptions, type SignedUrlOptions, type StratalRouteMap, type StreamingApi, type TrailingSlashConfig, type TrailingSlashExclude, type TrailingSlashMode, type TrailingSlashOptions, Uri, type UriOptions, VERSION_NEUTRAL, VerifySignatureMiddleware, type VersioningOptions, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, isTrailingSlashExcluded, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, resolveTrailingSlash, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
1
+ import { $r as RouteMatcher, $t as extractDomainParamNames, Ar as RouterVariables, At as parseDomainPattern, Bn as IController, Br as SECURITY_SCHEMES, Bt as getRouteMetadata, Cn as Router, Cr as RouteBody, Ct as SignedUrlOptions, Dn as ResolvedPath, Dr as RouteResponse, Dt as isNestedDispatch, En as LocalePathService, Er as RouteMetadata, Et as VerifySignatureMiddleware, Fr as TrailingSlashOptions, Ft as successMessageSchema, Gt as Post, Ht as Delete, Ir as VersioningOptions, It as uuidParamSchema, Jt as getControllerGroups, Kt as Put, Lr as HTTP_METHODS, Lt as validationErrorResponseSchema, Mr as TrailingSlashConfig, Mt as errorResponseSchema, Nr as TrailingSlashExclude, Nt as paginatedResponseSchema, Or as RouteResponseObject, Ot as markNestedDispatch, Pr as TrailingSlashMode, Pt as paginationQuerySchema, Qr as CurrentRoute, Qt as createMiddlewareChain, Rr as ROUTER_CONTEXT_KEYS, Rt as Route, Sn as RouteConfigurable, Sr as LocaleUrlConfig, St as RouterError, Tn as LocaleUrlService, Tr as RouteConfig, Tt as verifySignedUrl, Ut as Get, Vr as VERSION_NEUTRAL, Vt as All, Wt as Patch, Xr as Middleware, Xt as getControllerRoute, Yt as getControllerOptions, Zr as Next, Zt as getControllerVersion, _n as RouteRegistry, _t as StreamingApi, ai as StratalRouteMap, an as applyTrailingSlash, br as ExplicitRouteMetadata, bt as SchemaValidationError, cn as applyLocalePrefix, ct as SignedUriOptions, dn as route, dt as buildRouteUrl, ei as RouteName, en as extractParamNames, fn as ROUTER_TOKENS, gn as RouteRegistrationInput, gt as SSEStreamingApi, hn as RegisteredRoute, ht as SSEMessage, ii as SerializedRoutes, in as toOpenAPIPath, jr as SecurityScheme, jt as commonErrorSchemas, kr as RouterEnv, kt as createDomainMiddleware, ln as shouldPrefixLocale, lt as Uri, ni as RoutePrefixes, nn as getPathSpecificityScore, on as isTrailingSlashExcluded, pn as RouteRegistrationService, qt as Controller, ri as SerializedRoute, rn as sortRoutesBySpecificity, sn as resolveTrailingSlash, st as RouterContext, ti as RouteParams, tn as generateConventionRouteName, un as stripLocalePrefix, ut as UriOptions, vn as VersioningService, vr as ControllerOptions, vt as InvalidSignatureError, wn as RouterGroupConfig, wr as RouteBodyObject, wt as signUrl, xr as LocalePathConfig, xt as RouteNotFoundError, yr as ConventionRouteMetadata, yt as ResponseValidationError, zn as HonoApp, zr as ROUTE_METADATA_KEYS, zt as getRouteDecoratedMethods } from "../index-B2WtEagR.mjs";
2
+ export { All, Controller, type ControllerOptions, type ConventionRouteMetadata, type CurrentRoute, Delete, type ExplicitRouteMetadata, Get, HTTP_METHODS, HonoApp, type IController, InvalidSignatureError, type LocalePathConfig, LocalePathService, type LocaleUrlConfig, LocaleUrlService, type Middleware, type Next, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, type RegisteredRoute, type ResolvedPath, ResponseValidationError, Route, type RouteBody, type RouteBodyObject, type RouteConfig, type RouteConfigurable, type RouteMatcher, type RouteMetadata, type RouteName, RouteNotFoundError, type RouteParams, type RoutePrefixes, type RouteRegistrationInput, RouteRegistrationService, RouteRegistry, type RouteResponse, type RouteResponseObject, Router, RouterContext, type RouterEnv, RouterError, type RouterGroupConfig, type RouterVariables, SECURITY_SCHEMES, type SSEMessage, type SSEStreamingApi, SchemaValidationError, type SecurityScheme, type SerializedRoute, type SerializedRoutes, type SignedUriOptions, type SignedUrlOptions, type StratalRouteMap, type StreamingApi, type TrailingSlashConfig, type TrailingSlashExclude, type TrailingSlashMode, type TrailingSlashOptions, Uri, type UriOptions, VERSION_NEUTRAL, VerifySignatureMiddleware, type VersioningOptions, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerGroups, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, isNestedDispatch, isTrailingSlashExcluded, markNestedDispatch, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, resolveTrailingSlash, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
@@ -1,18 +1,19 @@
1
- import { b as ROUTER_TOKENS } from "../di-D7qmrAir.mjs";
2
- import { a as RouterContext, d as SECURITY_SCHEMES, f as VERSION_NEUTRAL, l as ROUTER_CONTEXT_KEYS, s as HTTP_METHODS, u as ROUTE_METADATA_KEYS } from "../exception-context-D-kvney-.mjs";
3
- import { n as Router, o as RouterError } from "../module-registry-NxX5O0Qk.mjs";
4
- import { i as getControllerVersion, n as getControllerOptions, r as getControllerRoute, t as Controller } from "../controller.decorator-YSTPQntu.mjs";
5
- import { a as Post, i as Patch, n as Delete, o as Put, r as Get, t as All } from "../http-method.decorator-BljM8BDj.mjs";
6
- import { _ as ResponseValidationError, a as paginatedResponseSchema, c as uuidParamSchema, d as getRouteDecoratedMethods, f as getRouteMetadata, g as InvalidSignatureError, h as parseDomainPattern, i as errorResponseSchema, l as validationErrorResponseSchema, m as createDomainMiddleware, o as paginationQuerySchema, p as createMiddlewareChain, r as commonErrorSchemas, s as successMessageSchema, t as RouteRegistrationService, u as Route, v as SchemaValidationError, y as RouteNotFoundError } from "../route-registration.service-CDPQKpm4.mjs";
7
- import { t as HonoApp } from "../hono-app-COAgmutc.mjs";
1
+ import { C as ROUTER_TOKENS } from "../di-DQ3xbjgf.mjs";
2
+ import { a as RouterContext, d as SECURITY_SCHEMES, f as VERSION_NEUTRAL, l as ROUTER_CONTEXT_KEYS, s as HTTP_METHODS, u as ROUTE_METADATA_KEYS } from "../exception-context-CdnGTQNF.mjs";
3
+ import { n as Router, o as RouterError } from "../module-registry-lkQPDuQe.mjs";
4
+ import { a as getControllerVersion, i as getControllerRoute, n as getControllerGroups, r as getControllerOptions, t as Controller } from "../controller.decorator-BB0JcwMg.mjs";
5
+ import { a as Post, i as Patch, n as Delete, o as Put, r as Get, t as All } from "../http-method.decorator-BDi9LTWj.mjs";
6
+ import { a as RouteNotFoundError, i as markNestedDispatch, r as isNestedDispatch, t as HonoApp } from "../hono-app-IhdqL0Fk.mjs";
7
+ import { a as getRouteMetadata, c as parseDomainPattern, d as SchemaValidationError, i as getRouteDecoratedMethods, l as InvalidSignatureError, o as createMiddlewareChain, r as Route, s as createDomainMiddleware, t as RouteRegistrationService, u as ResponseValidationError } from "../route-registration.service-COKBZTsn.mjs";
8
8
  import { n as shouldPrefixLocale, r as stripLocalePrefix, t as applyLocalePrefix } from "../locale-url-nZrZxqJP.mjs";
9
9
  import { n as isTrailingSlashExcluded, r as resolveTrailingSlash, t as applyTrailingSlash } from "../trailing-slash-2SctvePW.mjs";
10
- import { a as sortRoutesBySpecificity, i as getPathSpecificityScore, n as extractParamNames, o as toOpenAPIPath, r as generateConventionRouteName, t as extractDomainParamNames } from "../route-name-DGoBOfPg.mjs";
11
- import { t as LocalePathService } from "../locale-path.service-CH0CaxwH.mjs";
12
- import { t as LocaleUrlService } from "../locale-url.service-6bgia24_.mjs";
13
- import { t as VersioningService } from "../versioning.service-CCa2oYMJ.mjs";
14
- import { n as route, t as VerifySignatureMiddleware } from "../router-DwyqEXgf.mjs";
15
- import { t as RouteRegistry } from "../route-registry-BvLJisvK.mjs";
10
+ import { a as getPathSpecificityScore, n as extractParamNames, o as sortRoutesBySpecificity, r as generateConventionRouteName, s as toOpenAPIPath, t as extractDomainParamNames } from "../route-name-BslSbmMP.mjs";
11
+ import { t as LocalePathService } from "../locale-path.service-BqzDIrgy.mjs";
12
+ import { t as LocaleUrlService } from "../locale-url.service-H8PH6GGh.mjs";
13
+ import { t as VersioningService } from "../versioning.service-DnF_4Lnd.mjs";
14
+ import { t as RouteRegistry } from "../route-registry-DFz9_-N6.mjs";
15
+ import { n as route, t as VerifySignatureMiddleware } from "../router-wlsVkGkM.mjs";
16
16
  import { n as verifySignedUrl, t as signUrl } from "../signed-url-DIU0sK_6.mjs";
17
- import { n as buildRouteUrl, t as Uri } from "../uri-iwofWJ_T.mjs";
18
- export { All, Controller, Delete, Get, HTTP_METHODS, HonoApp, InvalidSignatureError, LocalePathService, LocaleUrlService, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, ResponseValidationError, Route, RouteNotFoundError, RouteRegistrationService, RouteRegistry, Router, RouterContext, RouterError, SECURITY_SCHEMES, SchemaValidationError, Uri, VERSION_NEUTRAL, VerifySignatureMiddleware, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, isTrailingSlashExcluded, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, resolveTrailingSlash, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
17
+ import { n as buildRouteUrl, t as Uri } from "../uri-BrOq148R.mjs";
18
+ import { a as paginationQuerySchema, c as validationErrorResponseSchema, i as paginatedResponseSchema, o as successMessageSchema, r as errorResponseSchema, s as uuidParamSchema, t as commonErrorSchemas } from "../common.schemas-BigQCwYB.mjs";
19
+ export { All, Controller, Delete, Get, HTTP_METHODS, HonoApp, InvalidSignatureError, LocalePathService, LocaleUrlService, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, ResponseValidationError, Route, RouteNotFoundError, RouteRegistrationService, RouteRegistry, Router, RouterContext, RouterError, SECURITY_SCHEMES, SchemaValidationError, Uri, VERSION_NEUTRAL, VerifySignatureMiddleware, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerGroups, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, isNestedDispatch, isTrailingSlashExcluded, markNestedDispatch, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, resolveTrailingSlash, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
@@ -1,4 +1,5 @@
1
- import { a as getGroups, i as getGlobalMiddleware, r as getDefaultEntry } from "./module-registry-NxX5O0Qk.mjs";
1
+ import { a as getGroups, i as getGlobalMiddleware, r as getDefaultEntry } from "./module-registry-lkQPDuQe.mjs";
2
+ import { object } from "zod/mini";
2
3
  //#region src/router/router-resolver.ts
3
4
  /**
4
5
  * Internal resolver that computes the effective Router config for each controller.
@@ -67,7 +68,10 @@ var RouterResolver = class {
67
68
  if (!parent && !child) return void 0;
68
69
  if (!parent) return child;
69
70
  if (!child) return parent;
70
- return parent.extend(child.shape);
71
+ return object({
72
+ ...parent.shape,
73
+ ...child.shape
74
+ });
71
75
  }
72
76
  concatPrefixes(parent, child) {
73
77
  if (!parent && !child) return void 0;
@@ -85,4 +89,4 @@ var RouterResolver = class {
85
89
  //#endregion
86
90
  export { RouterResolver };
87
91
 
88
- //# sourceMappingURL=router-resolver-sUV_jTrU.mjs.map
92
+ //# sourceMappingURL=router-resolver-B-dMSMIG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-resolver-B-dMSMIG.mjs","names":["internal.getGroups","internal.getDefaultEntry","internal.getGlobalMiddleware"],"sources":["../src/router/router-resolver.ts"],"sourcesContent":["import { object } from 'zod/mini'\nimport type { ZodObject } from '../i18n/validation/zod'\nimport type { Constructor } from '../types'\nimport type { Middleware } from './middleware.interface'\nimport type { Router, RouterEntry } from './router'\nimport * as internal from './router.internals'\n\n/**\n * Resolved configuration for a single controller.\n * Merges Router default entry, sub-group overrides, and inheritance rules.\n */\nexport interface ResolvedRouterConfig {\n prefix?: string\n domain?: string\n name?: string\n middleware: Constructor<Middleware>[]\n version?: string | string[]\n hideFromDocs?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n params?: ZodObject<any>\n}\n\n/**\n * Internal resolver that computes the effective Router config for each controller.\n *\n * Inheritance rules:\n * - `middleware`: parent middleware runs first, then child (concatenated)\n * - `prefix`: concatenated (parent + child)\n * - `name`: concatenated (parent + child)\n * - `domain`: child overrides parent\n * - `version`: child overrides parent\n * - `hideFromDocs`: child overrides parent\n *\n * @internal — not exported from stratal/router\n */\nexport class RouterResolver {\n private readonly routers: { router: Router; controllers: Constructor[] }[]\n\n constructor(routers: { router: Router; controllers: Constructor[] }[]) {\n this.routers = routers\n }\n\n /**\n * Resolve the effective config for a given controller class.\n * Searches through all module routers to find the one owning this controller.\n */\n resolveForController(controller: Constructor): ResolvedRouterConfig {\n for (const { router, controllers: moduleControllers } of this.routers) {\n if (!moduleControllers.includes(controller)) continue\n\n // Check if controller is in a sub-group\n for (const group of router[internal.getGroups]()) {\n if (group.controllers?.includes(controller)) {\n return this.mergeEntries(router[internal.getDefaultEntry](), group)\n }\n }\n\n // Controller is in the default scope (not in any sub-group)\n // But only if it's not claimed by any sub-group in this module\n const groupedControllers = new Set(\n router[internal.getGroups]().flatMap(g => g.controllers ?? [])\n )\n if (!groupedControllers.has(controller)) {\n return this.entryToConfig(router[internal.getDefaultEntry]())\n }\n }\n\n // Controller not found in any module's router — return empty config\n return { middleware: [] }\n }\n\n /**\n * Collect all global middleware registered via `router.use()` across all modules.\n */\n getGlobalMiddleware(): Constructor<Middleware>[] {\n const global: Constructor<Middleware>[] = []\n for (const { router } of this.routers) {\n global.push(...router[internal.getGlobalMiddleware]())\n }\n return global\n }\n\n /**\n * Merge parent default entry with child group entry following inheritance rules.\n */\n private mergeEntries(parent: RouterEntry, child: RouterEntry): ResolvedRouterConfig {\n return {\n // Concatenate: parent prefix + child prefix\n prefix: this.concatPrefixes(parent.prefix, child.prefix),\n // Override: child domain wins\n domain: child.domain ?? parent.domain,\n // Concatenate: parent name + child name\n name: this.concatNames(parent.name, child.name),\n // Concatenate: parent middleware first, then child\n middleware: [...parent.middleware, ...child.middleware],\n // Override: child version wins\n version: child.version ?? parent.version,\n // Override: child hideFromDocs wins\n hideFromDocs: child.hideFromDocs ?? parent.hideFromDocs,\n // Extend: parent params extended with child params\n params: this.mergeParams(parent.params, child.params),\n }\n }\n\n private entryToConfig(entry: RouterEntry): ResolvedRouterConfig {\n return {\n prefix: entry.prefix,\n domain: entry.domain,\n name: entry.name,\n middleware: [...entry.middleware],\n version: entry.version,\n hideFromDocs: entry.hideFromDocs,\n params: entry.params,\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n private mergeParams(parent?: ZodObject<any>, child?: ZodObject<any>): ZodObject<any> | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n // oxlint-disable-next-line typescript/no-explicit-any\n return object({ ...parent.shape, ...child.shape }) as ZodObject<any>\n }\n\n private concatPrefixes(parent?: string, child?: string): string | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n // Normalize: remove trailing slash from parent, ensure child starts with /\n const p = parent.endsWith('/') ? parent.slice(0, -1) : parent\n const c = child.startsWith('/') ? child : `/${child}`\n return `${p}${c}`\n }\n\n private concatNames(parent?: string, child?: string): string | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n return `${parent}${child}`\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmCA,IAAa,iBAAb,MAA4B;CAC1B;CAEA,YAAY,SAA2D;EACrE,KAAK,UAAU;CACjB;;;;;CAMA,qBAAqB,YAA+C;EAClE,KAAK,MAAM,EAAE,QAAQ,aAAa,uBAAuB,KAAK,SAAS;GACrE,IAAI,CAAC,kBAAkB,SAAS,UAAU,GAAG;GAG7C,KAAK,MAAM,SAAS,OAAOA,UAAmB,CAAC,GAC7C,IAAI,MAAM,aAAa,SAAS,UAAU,GACxC,OAAO,KAAK,aAAa,OAAOC,gBAAyB,CAAC,GAAG,KAAK;GAStE,IAAI,CAAC,IAH0B,IAC7B,OAAOD,UAAmB,CAAC,CAAC,CAAC,SAAQ,MAAK,EAAE,eAAe,CAAC,CAAC,CAEzC,CAAC,CAAC,IAAI,UAAU,GACpC,OAAO,KAAK,cAAc,OAAOC,gBAAyB,CAAC,CAAC;EAEhE;EAGA,OAAO,EAAE,YAAY,CAAC,EAAE;CAC1B;;;;CAKA,sBAAiD;EAC/C,MAAM,SAAoC,CAAC;EAC3C,KAAK,MAAM,EAAE,YAAY,KAAK,SAC5B,OAAO,KAAK,GAAG,OAAOC,oBAA6B,CAAC,CAAC;EAEvD,OAAO;CACT;;;;CAKA,aAAqB,QAAqB,OAA0C;EAClF,OAAO;GAEL,QAAQ,KAAK,eAAe,OAAO,QAAQ,MAAM,MAAM;GAEvD,QAAQ,MAAM,UAAU,OAAO;GAE/B,MAAM,KAAK,YAAY,OAAO,MAAM,MAAM,IAAI;GAE9C,YAAY,CAAC,GAAG,OAAO,YAAY,GAAG,MAAM,UAAU;GAEtD,SAAS,MAAM,WAAW,OAAO;GAEjC,cAAc,MAAM,gBAAgB,OAAO;GAE3C,QAAQ,KAAK,YAAY,OAAO,QAAQ,MAAM,MAAM;EACtD;CACF;CAEA,cAAsB,OAA0C;EAC9D,OAAO;GACL,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,MAAM,MAAM;GACZ,YAAY,CAAC,GAAG,MAAM,UAAU;GAChC,SAAS,MAAM;GACf,cAAc,MAAM;GACpB,QAAQ,MAAM;EAChB;CACF;CAGA,YAAoB,QAAyB,OAAoD;EAC/F,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EAEnB,OAAO,OAAO;GAAE,GAAG,OAAO;GAAO,GAAG,MAAM;EAAM,CAAC;CACnD;CAEA,eAAuB,QAAiB,OAAoC;EAC1E,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EAInB,OAAO,GAFG,OAAO,SAAS,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,SAC7C,MAAM,WAAW,GAAG,IAAI,QAAQ,IAAI;CAEhD;CAEA,YAAoB,QAAiB,OAAoC;EACvE,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EACnB,OAAO,GAAG,SAAS;CACrB;AACF"}
@@ -1,17 +1,8 @@
1
- import { b as ROUTER_TOKENS } from "./di-D7qmrAir.mjs";
2
- import { n as getContainer } from "./container-storage-BmOJ4_Na.mjs";
3
- import "./exception-context-D-kvney-.mjs";
4
- import { o as RouterError } from "./module-registry-NxX5O0Qk.mjs";
5
- import "./controller.decorator-YSTPQntu.mjs";
6
- import "./http-method.decorator-BljM8BDj.mjs";
7
- import { g as InvalidSignatureError } from "./route-registration.service-CDPQKpm4.mjs";
8
- import "./hono-app-COAgmutc.mjs";
9
- import "./locale-path.service-CH0CaxwH.mjs";
10
- import "./locale-url.service-6bgia24_.mjs";
11
- import "./versioning.service-CCa2oYMJ.mjs";
12
- import "./route-registry-BvLJisvK.mjs";
1
+ import { C as ROUTER_TOKENS } from "./di-DQ3xbjgf.mjs";
2
+ import { n as getContainer } from "./container-storage-DfF7SXdV.mjs";
3
+ import { o as RouterError } from "./module-registry-lkQPDuQe.mjs";
4
+ import { l as InvalidSignatureError } from "./route-registration.service-COKBZTsn.mjs";
13
5
  import { n as verifySignedUrl } from "./signed-url-DIU0sK_6.mjs";
14
- import "./uri-iwofWJ_T.mjs";
15
6
  //#region src/router/route-url.ts
16
7
  /**
17
8
  * Generate a URL from a named route.
@@ -75,4 +66,4 @@ var VerifySignatureMiddleware = class {
75
66
  //#endregion
76
67
  export { route as n, VerifySignatureMiddleware as t };
77
68
 
78
- //# sourceMappingURL=router-DwyqEXgf.mjs.map
69
+ //# sourceMappingURL=router-wlsVkGkM.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"router-DwyqEXgf.mjs","names":[],"sources":["../src/router/route-url.ts","../src/router/middleware/verify-signature.middleware.ts"],"sourcesContent":["import { getContainer } from '../di/container-storage';\nimport type { RouteName, RouteParams } from './route-map';\nimport { ROUTER_TOKENS } from './router.tokens';\nimport { type Uri, type UriOptions } from './uri';\n\n/**\n * Generate a URL from a named route.\n *\n * Keys in `params` matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are also consumed from `params`.\n * Extra keys become query string parameters.\n *\n * Resolves RouteRegistry from the application container via AsyncLocalStorage.\n * Available after `Application.initialize()` has been called.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @returns Generated URL string\n *\n * @example\n * ```typescript\n * // In a controller (preferred):\n * ctx.route('users.show', { id: '1' })\n *\n * // Outside controllers (standalone function):\n * import { route } from 'stratal/router'\n *\n * route('users.show', { id: '1' })\n * ```\n */\nexport function route<N extends RouteName>(\n name: N,\n params?: RouteParams<N>,\n options?: UriOptions\n): string {\n const container = getContainer()\n const uri = container.resolve<Uri>(ROUTER_TOKENS.Uri)\n\n return uri.route(name, params, options)\n}\n","import { InvalidSignatureError } from '../errors'\nimport { RouterError } from '../router.error'\nimport type { Middleware, Next } from '../middleware.interface'\nimport type { RouterContext } from '../router-context'\nimport { verifySignedUrl } from '../signed-url'\n\n/**\n * Middleware that verifies signed URLs.\n *\n * Checks the `signature` (and optionally `expires`) query params against the\n * request URL using HMAC-SHA256 via `crypto.subtle.verify()`.\n *\n * Requires `APP_SECRET` in the Cloudflare Workers environment bindings.\n *\n * @throws InvalidSignatureError (403) if signature is missing, invalid, or expired\n *\n * @example\n * ```typescript\n * @Module({ controllers: [UnsubscribeController], providers: [VerifySignatureMiddleware] })\n * export class EmailModule implements RouteConfigurable {\n * configureRoutes(router: Router): void {\n * router.middleware(VerifySignatureMiddleware)\n * }\n * }\n * ```\n */\nexport class VerifySignatureMiddleware implements Middleware {\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const url = ctx.c.req.url\n const env = ctx.c.env\n const secret = (env as unknown as Record<string, string>).APP_SECRET\n\n if (!secret) {\n throw new RouterError('Missing required environment variable \"APP_SECRET\"')\n }\n\n const isValid = await verifySignedUrl(url, secret)\n if (!isValid) {\n throw new InvalidSignatureError()\n }\n\n await next()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,MACd,MACA,QACA,SACQ;CAIR,OAHkB,aACE,EAAE,QAAa,cAAc,GAExC,EAAE,MAAM,MAAM,QAAQ,OAAO;AACxC;;;;;;;;;;;;;;;;;;;;;;;ACbA,IAAa,4BAAb,MAA6D;CAC3D,MAAM,OAAO,KAAoB,MAA2B;EAC1D,MAAM,MAAM,IAAI,EAAE,IAAI;EAEtB,MAAM,SADM,IAAI,EAAE,IACwC;EAE1D,IAAI,CAAC,QACH,MAAM,IAAI,YAAY,sDAAoD;EAI5E,IAAI,CAAC,MADiB,gBAAgB,KAAK,MAAM,GAE/C,MAAM,IAAI,sBAAsB;EAGlC,MAAM,KAAK;CACb;AACF"}
1
+ {"version":3,"file":"router-wlsVkGkM.mjs","names":[],"sources":["../src/router/route-url.ts","../src/router/middleware/verify-signature.middleware.ts"],"sourcesContent":["import { getContainer } from '../di/container-storage';\nimport type { RouteName, RouteParams } from './route-map';\nimport { ROUTER_TOKENS } from './router.tokens';\nimport { type Uri, type UriOptions } from './uri';\n\n/**\n * Generate a URL from a named route.\n *\n * Keys in `params` matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are also consumed from `params`.\n * Extra keys become query string parameters.\n *\n * Resolves RouteRegistry from the application container via AsyncLocalStorage.\n * Available after `Application.initialize()` has been called.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @returns Generated URL string\n *\n * @example\n * ```typescript\n * // In a controller (preferred):\n * ctx.route('users.show', { id: '1' })\n *\n * // Outside controllers (standalone function):\n * import { route } from 'stratal/router'\n *\n * route('users.show', { id: '1' })\n * ```\n */\nexport function route<N extends RouteName>(\n name: N,\n params?: RouteParams<N>,\n options?: UriOptions\n): string {\n const container = getContainer()\n const uri = container.resolve<Uri>(ROUTER_TOKENS.Uri)\n\n return uri.route(name, params, options)\n}\n","import { InvalidSignatureError } from '../errors'\nimport { RouterError } from '../router.error'\nimport type { Middleware, Next } from '../middleware.interface'\nimport type { RouterContext } from '../router-context'\nimport { verifySignedUrl } from '../signed-url'\n\n/**\n * Middleware that verifies signed URLs.\n *\n * Checks the `signature` (and optionally `expires`) query params against the\n * request URL using HMAC-SHA256 via `crypto.subtle.verify()`.\n *\n * Requires `APP_SECRET` in the Cloudflare Workers environment bindings.\n *\n * @throws InvalidSignatureError (403) if signature is missing, invalid, or expired\n *\n * @example\n * ```typescript\n * @Module({ controllers: [UnsubscribeController], providers: [VerifySignatureMiddleware] })\n * export class EmailModule implements RouteConfigurable {\n * configureRoutes(router: Router): void {\n * router.middleware(VerifySignatureMiddleware)\n * }\n * }\n * ```\n */\nexport class VerifySignatureMiddleware implements Middleware {\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const url = ctx.c.req.url\n const env = ctx.c.env\n const secret = (env as unknown as Record<string, string>).APP_SECRET\n\n if (!secret) {\n throw new RouterError('Missing required environment variable \"APP_SECRET\"')\n }\n\n const isValid = await verifySignedUrl(url, secret)\n if (!isValid) {\n throw new InvalidSignatureError()\n }\n\n await next()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,MACd,MACA,QACA,SACQ;CAIR,OAHkB,aACE,CAAC,CAAC,QAAa,cAAc,GAExC,CAAC,CAAC,MAAM,MAAM,QAAQ,OAAO;AACxC;;;;;;;;;;;;;;;;;;;;;;;ACbA,IAAa,4BAAb,MAA6D;CAC3D,MAAM,OAAO,KAAoB,MAA2B;EAC1D,MAAM,MAAM,IAAI,EAAE,IAAI;EAEtB,MAAM,SADM,IAAI,EAAE,IACwC;EAE1D,IAAI,CAAC,QACH,MAAM,IAAI,YAAY,sDAAoD;EAI5E,IAAI,CAAC,MADiB,gBAAgB,KAAK,MAAM,GAE/C,MAAM,IAAI,sBAAsB;EAGlC,MAAM,KAAK;CACb;AACF"}
@@ -1,14 +1,13 @@
1
- import { $ as Container, Ir as ApplicationError, ft as Application } from "../index-uybm0bhQ.mjs";
1
+ import { $ as Container, ft as Application, li as ApplicationError } from "../index-B2WtEagR.mjs";
2
2
  import { t as Constructor } from "../types-CmV_9xBD.mjs";
3
- import { t as Command } from "../command-DoBD2Cwl.mjs";
4
-
3
+ import { t as Command } from "../command-BXMccV_9.mjs";
5
4
  //#region src/seeder/seeder.d.ts
6
- declare const SEEDER_INTERNALS: unique symbol;
5
+ export declare const SEEDER_INTERNALS: unique symbol;
7
6
  interface SeederContext {
8
7
  run(SeederClass: Constructor<Seeder>): Promise<void>;
9
8
  container: Container | null;
10
9
  }
11
- declare abstract class Seeder {
10
+ export declare abstract class Seeder {
12
11
  [SEEDER_INTERNALS]: SeederContext;
13
12
  abstract run(): Promise<void>;
14
13
  /** Call another seeder (like Laravel's $this->call()) */
@@ -16,10 +15,10 @@ declare abstract class Seeder {
16
15
  }
17
16
  //#endregion
18
17
  //#region src/seeder/seeder-registry.d.ts
19
- declare const SEEDER_TOKENS: {
18
+ export declare const SEEDER_TOKENS: {
20
19
  readonly SeederRegistry: symbol;
21
20
  };
22
- declare class SeederRegistry {
21
+ export declare class SeederRegistry {
23
22
  private app;
24
23
  private seeders;
25
24
  private nameIndex;
@@ -39,7 +38,7 @@ declare class SeederRegistry {
39
38
  }
40
39
  //#endregion
41
40
  //#region src/seeder/commands/db-seed-list.command.d.ts
42
- declare class DbSeedListCommand extends Command {
41
+ export declare class DbSeedListCommand extends Command {
43
42
  private seeders;
44
43
  static command: string;
45
44
  static description: string;
@@ -48,7 +47,7 @@ declare class DbSeedListCommand extends Command {
48
47
  }
49
48
  //#endregion
50
49
  //#region src/seeder/commands/db-seed.command.d.ts
51
- declare class DbSeedCommand extends Command {
50
+ export declare class DbSeedCommand extends Command {
52
51
  private seeders;
53
52
  static command: string;
54
53
  static description: string;
@@ -57,7 +56,7 @@ declare class DbSeedCommand extends Command {
57
56
  }
58
57
  //#endregion
59
58
  //#region src/seeder/seeder.error.d.ts
60
- declare class SeederError extends ApplicationError {}
59
+ export declare class SeederError extends ApplicationError {}
61
60
  //#endregion
62
61
  //#region src/seeder/is-seeder.d.ts
63
62
  /**
@@ -65,7 +64,7 @@ declare class SeederError extends ApplicationError {}
65
64
  *
66
65
  * Used by ModuleRegistry for auto-discovery from providers.
67
66
  */
68
- declare function isSeeder(target: Constructor): boolean;
67
+ export declare function isSeeder(target: Constructor): boolean;
69
68
  //#endregion
70
69
  //#region src/seeder/seeder.module.d.ts
71
70
  /**
@@ -75,7 +74,7 @@ declare function isSeeder(target: Constructor): boolean;
75
74
  * test harness (`@stratal/testing`), so it cannot be lazily loaded.
76
75
  * {@link SeederRegistry} injects the `Application` via `DI_TOKENS.Application`.
77
76
  */
78
- declare class SeederModule {}
77
+ export declare class SeederModule {}
79
78
  //#endregion
80
- export { DbSeedCommand, DbSeedListCommand, SEEDER_INTERNALS, SEEDER_TOKENS, Seeder, type SeederContext, SeederError, SeederModule, SeederRegistry, isSeeder };
79
+ export type { SeederContext };
81
80
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/seeder/seeder.ts","../../src/seeder/seeder-registry.ts","../../src/seeder/commands/db-seed-list.command.ts","../../src/seeder/commands/db-seed.command.ts","../../src/seeder/seeder.error.ts","../../src/seeder/is-seeder.ts","../../src/seeder/seeder.module.ts"],"mappings":";;;;;cAGa,gBAAA;AAAA,UAEI,aAAA;EACf,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA,IAAU,OAAA;EACvC,SAAA,EAAW,SAAA;AAAA;AAAA,uBAGS,MAAA;EAAA,CACnB,gBAAA,GAAmB,aAAA;EAAA,SAKX,GAAA,IAAO,OAAA;EAXD;EAAA,UAcC,IAAA,CAAK,WAAA,EAAa,WAAA,CAAY,MAAA,IAAU,OAAA;AAAA;;;cCX7C,aAAA;EAAA,SAEH,cAAA;AAAA;AAAA,cAGG,cAAA;EAAA,QAIwC,GAAA;EAAA,QAH3C,OAAA;EAAA,QACA,SAAA;cAE2C,GAAA,EAAK,WAAA;EAExD,QAAA,CAAS,WAAA,EAAa,WAAA,CAAY,MAAA;EAS5B,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA,GAAS,OAAA;IAAY,SAAA,GAAY,SAAA;EAAA,IAAc,OAAA;EAsB5E,MAAA,CAAO,OAAA;IAAY,SAAA,GAAY,SAAA;EAAA,IAAc,OAAA;EAMnD,IAAA,CAAK,IAAA,WAAe,WAAA,CAAY,MAAA;EAIhC,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA;EAI7B,IAAA;IAAU,SAAA;EAAA;AAAA;;;cC5DC,iBAAA,SAA0B,OAAO;EAAA,QAIc,OAAA;EAAA,OAHnD,OAAA;EAAA,OACA,WAAA;cAEmD,OAAA,EAAS,cAAA;EAInE,MAAA;AAAA;;;cCRW,aAAA,SAAsB,OAAA;EAAA,QAIyB,OAAA;EAAA,OAHnD,OAAA;EAAA,OACA,WAAA;cAEmD,OAAA,EAAS,cAAA;EAI7D,MAAA,IAAU,OAAA;AAAA;;;cCVL,WAAA,SAAoB,gBAAgB;;;;;;;AJCjD;iBKKgB,QAAA,CAAS,MAAmB,EAAX,WAAW;;;;;;;;ALL5C;;cMYa,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/seeder/seeder.ts","../../src/seeder/seeder-registry.ts","../../src/seeder/commands/db-seed-list.command.ts","../../src/seeder/commands/db-seed.command.ts","../../src/seeder/seeder.error.ts","../../src/seeder/is-seeder.ts","../../src/seeder/seeder.module.ts"],"mappings":";;;;qBAGa;UAEI;EACf,IAAI,aAAa,YAAY,UAAU;EACvC,WAAW;;8BAGS;GACnB,mBAAmB;WAKX,OAAO;;YAGA,KAAK,aAAa,YAAY,UAAU;;;;qBCX7C;WACX;;qBAIW;UAIwC;UAH3C;UACA;EAER,YAAmD,KAAK;EAExD,SAAS,aAAa,YAAY;EAS5B,IAAI,aAAa,YAAY,SAAS;IAAY,YAAY;MAAc;EAsB5E,OAAO;IAAY,YAAY;MAAc;EAMnD,KAAK,eAAe,YAAY;EAIhC,IAAI,aAAa,YAAY;EAI7B;IAAU;;;;;qBC5DC,0BAA0B;UAIqB;SAHnD;SACA;EAEP,YAA0D,SAAS;EAInE;;;;qBCRW,sBAAsB;UAIyB;SAHnD;SACA;EAEP,YAA0D,SAAS;EAI7D,UAAU;;;;qBCVL,oBAAoB;;;;;;;;wBCMjB,SAAS,QAAQ;;;;;;;;;;qBCOpB"}
@@ -1,5 +1,5 @@
1
- import { n as SEEDER_INTERNALS, r as Seeder, t as isSeeder } from "../is-seeder-Gvh_AM71.mjs";
2
- import { n as SeederRegistry, r as SeederError, t as SEEDER_TOKENS } from "../seeder-registry-DEvCycsT.mjs";
3
- import { n as DbSeedListCommand, t as DbSeedCommand } from "../seeder-BPGY5rUb.mjs";
4
- import { t as SeederModule } from "../seeder.module-CIwQbdN4.mjs";
1
+ import { n as SEEDER_INTERNALS, r as Seeder, t as isSeeder } from "../is-seeder-gLgXYbqC.mjs";
2
+ import { n as SeederRegistry, r as SeederError, t as SEEDER_TOKENS } from "../seeder-registry-Bo5BgLbC.mjs";
3
+ import { n as DbSeedListCommand, t as DbSeedCommand } from "../seeder-BrAk7XIj.mjs";
4
+ import { t as SeederModule } from "../seeder.module-DOoVgTsK.mjs";
5
5
  export { DbSeedCommand, DbSeedListCommand, SEEDER_INTERNALS, SEEDER_TOKENS, Seeder, SeederError, SeederModule, SeederRegistry, isSeeder };