stratal 0.0.22 → 0.0.24

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 (270) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/cloudflare-workers-loader.mjs +80 -7
  3. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  4. package/dist/bin/quarry.mjs +41 -54
  5. package/dist/bin/quarry.mjs.map +1 -1
  6. package/dist/cache/index.d.mts +5 -3
  7. package/dist/cache/index.d.mts.map +1 -1
  8. package/dist/cache/index.mjs +123 -39
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/{cache.service-e34gV6tz.d.mts → cache.service-uElmBtdS.d.mts} +24 -34
  11. package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
  12. package/dist/{command-BU4ApTo5.mjs → command-BvmUAPPQ.mjs} +15 -3
  13. package/dist/command-BvmUAPPQ.mjs.map +1 -0
  14. package/dist/{command-wXfvHbBZ.d.mts → command-CPhFHjG3.d.mts} +2 -2
  15. package/dist/command-CPhFHjG3.d.mts.map +1 -0
  16. package/dist/command-not-found.error-ONAZ2Bpk.mjs +14 -0
  17. package/dist/command-not-found.error-ONAZ2Bpk.mjs.map +1 -0
  18. package/dist/config/index.d.mts +3 -3
  19. package/dist/config/index.d.mts.map +1 -1
  20. package/dist/config/index.mjs +7 -6
  21. package/dist/config/index.mjs.map +1 -1
  22. package/dist/{consumer-registry-DHQtypr1.d.mts → consumer-registry-D3iMTSdy.d.mts} +54 -22
  23. package/dist/consumer-registry-D3iMTSdy.d.mts.map +1 -0
  24. package/dist/{container-storage-GpNNz79X.mjs → container-storage-BmOJ4_Na.mjs} +1 -1
  25. package/dist/{container-storage-GpNNz79X.mjs.map → container-storage-BmOJ4_Na.mjs.map} +1 -1
  26. package/dist/{controller.decorator-DIUazNU7.mjs → controller.decorator-C5UVeJS3.mjs} +4 -4
  27. package/dist/{controller.decorator-DIUazNU7.mjs.map → controller.decorator-C5UVeJS3.mjs.map} +1 -1
  28. package/dist/cron/index.d.mts +79 -4
  29. package/dist/cron/index.d.mts.map +1 -1
  30. package/dist/cron/index.mjs +2 -2
  31. package/dist/cron-job-NesZRk8F.d.mts +58 -0
  32. package/dist/cron-job-NesZRk8F.d.mts.map +1 -0
  33. package/dist/{cron-manager-9bpN9bu4.mjs → cron.module-Bgzq5hiT.mjs} +17 -7
  34. package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
  35. package/dist/{decorate-HgTKAYK8.mjs → decorate-CuAoSZvs.mjs} +2 -2
  36. package/dist/{deep-merge-C8NgcXw4.mjs → deep-merge-ByiAOZ3r.mjs} +1 -1
  37. package/dist/{deep-merge-C8NgcXw4.mjs.map → deep-merge-ByiAOZ3r.mjs.map} +1 -1
  38. package/dist/di/index.d.mts +2 -2
  39. package/dist/di/index.mjs +3 -3
  40. package/dist/{di-BO1QIb5H.mjs → di-DseMn-z9.mjs} +244 -135
  41. package/dist/di-DseMn-z9.mjs.map +1 -0
  42. package/dist/email/index.d.mts +33 -40
  43. package/dist/email/index.d.mts.map +1 -1
  44. package/dist/email/index.mjs +456 -41
  45. package/dist/email/index.mjs.map +1 -1
  46. package/dist/{en-BPP6h6y5.mjs → en-CDZBMcc1.mjs} +2 -2
  47. package/dist/{en-BPP6h6y5.mjs.map → en-CDZBMcc1.mjs.map} +1 -1
  48. package/dist/{env-DKSbuBi5.d.mts → env-ug22bJj7.d.mts} +1 -1
  49. package/dist/env-ug22bJj7.d.mts.map +1 -0
  50. package/dist/errors/index.d.mts +1 -1
  51. package/dist/errors/index.mjs +3 -3
  52. package/dist/{errors-BBZTnjdq.mjs → errors-mXYxG0XB.mjs} +5 -5
  53. package/dist/{errors-BBZTnjdq.mjs.map → errors-mXYxG0XB.mjs.map} +1 -1
  54. package/dist/events/index.d.mts +14 -3
  55. package/dist/events/index.d.mts.map +1 -1
  56. package/dist/events/index.mjs +2 -2
  57. package/dist/{events-D1KdDaiP.mjs → events-BXJGZjpG.mjs} +16 -6
  58. package/dist/events-BXJGZjpG.mjs.map +1 -0
  59. package/dist/{exception-context-B4kM-M53.mjs → exception-context-kEoMFwze.mjs} +3 -3
  60. package/dist/{exception-context-B4kM-M53.mjs.map → exception-context-kEoMFwze.mjs.map} +1 -1
  61. package/dist/{gateway-context-CFe6a9gz.mjs → gateway-context-TMu_AlJt.mjs} +25 -6
  62. package/dist/{gateway-context-CFe6a9gz.mjs.map → gateway-context-TMu_AlJt.mjs.map} +1 -1
  63. package/dist/guards/index.d.mts +3 -3
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +1 -1
  66. package/dist/{guards-Ced-uNIF.mjs → guards-DALPXy3_.mjs} +2 -2
  67. package/dist/{guards-Ced-uNIF.mjs.map → guards-DALPXy3_.mjs.map} +1 -1
  68. package/dist/hono-app-CvV3hOfT.mjs +161 -0
  69. package/dist/hono-app-CvV3hOfT.mjs.map +1 -0
  70. package/dist/{http-method.decorator-CdjKFJZZ.mjs → http-method.decorator-ByWZb9DO.mjs} +4 -4
  71. package/dist/{http-method.decorator-CdjKFJZZ.mjs.map → http-method.decorator-ByWZb9DO.mjs.map} +1 -1
  72. package/dist/i18n/index.d.mts +4 -4
  73. package/dist/i18n/index.d.mts.map +1 -1
  74. package/dist/i18n/index.mjs +5 -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.mjs +1 -1
  79. package/dist/i18n/validation/index.d.mts +3 -3
  80. package/dist/i18n/validation/index.mjs +3 -3
  81. package/dist/{i18n.module-BlXrtAlV.mjs → i18n.module-DRQAZoSZ.mjs} +14 -11
  82. package/dist/{i18n.module-BlXrtAlV.mjs.map → i18n.module-DRQAZoSZ.mjs.map} +1 -1
  83. package/dist/{i18n.tokens-hwRpmjRq.mjs → i18n.tokens-CZ_v8oyS.mjs} +1 -1
  84. package/dist/{i18n.tokens-hwRpmjRq.mjs.map → i18n.tokens-CZ_v8oyS.mjs.map} +1 -1
  85. package/dist/{index-B4UBK-2T.d.mts → index-0ItCjaqw.d.mts} +1 -1
  86. package/dist/index-0ItCjaqw.d.mts.map +1 -0
  87. package/dist/{index-CW1YHSft.d.mts → index-B5JBRcWD.d.mts} +249 -103
  88. package/dist/index-B5JBRcWD.d.mts.map +1 -0
  89. package/dist/{index-BtlE9RuO.d.mts → index-BUt92sAE.d.mts} +1 -1
  90. package/dist/index-BUt92sAE.d.mts.map +1 -0
  91. package/dist/{index-DEncMcC6.d.mts → index-B_JoEl3V.d.mts} +221 -16
  92. package/dist/index-B_JoEl3V.d.mts.map +1 -0
  93. package/dist/{index-Dj5IMwtr.d.mts → index-DtBNIFuP.d.mts} +4 -6
  94. package/dist/index-DtBNIFuP.d.mts.map +1 -0
  95. package/dist/{index-KMgSCSM7.d.mts → index-HgOLNruQ.d.mts} +1 -1
  96. package/dist/{index-KMgSCSM7.d.mts.map → index-HgOLNruQ.d.mts.map} +1 -1
  97. package/dist/index.d.mts +6 -5
  98. package/dist/index.mjs +3 -2
  99. package/dist/{is-command-CX5rAfZW.mjs → is-command-CEPO9n8c.mjs} +2 -2
  100. package/dist/{is-command-CX5rAfZW.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
  101. package/dist/{is-seeder-CYCtELlm.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
  102. package/dist/{is-seeder-CYCtELlm.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
  103. package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
  104. package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
  105. package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
  106. package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
  107. package/dist/locale-url-nZrZxqJP.mjs +44 -0
  108. package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
  109. package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
  110. package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
  111. package/dist/logger/index.d.mts +1 -1
  112. package/dist/logger/index.mjs +2 -2
  113. package/dist/logger/index.mjs.map +1 -1
  114. package/dist/macroable/index.d.mts +2 -2
  115. package/dist/macroable/index.mjs +1 -1
  116. package/dist/{macroable-DzlfzT50.mjs → macroable-cvDTFZ_A.mjs} +1 -1
  117. package/dist/{macroable-DzlfzT50.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
  118. package/dist/{metadata-BVkc4aUu.mjs → metadata-DzzprcID.mjs} +1 -1
  119. package/dist/{metadata-BVkc4aUu.mjs.map → metadata-DzzprcID.mjs.map} +1 -1
  120. package/dist/module/index.d.mts +4 -3
  121. package/dist/module/index.d.mts.map +1 -1
  122. package/dist/module/index.mjs +10 -2
  123. package/dist/module/index.mjs.map +1 -0
  124. package/dist/{module-xYoHba6B.mjs → module-registry-Dm-pqHd3.mjs} +189 -57
  125. package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
  126. package/dist/module.decorator-CYHY6pG5.mjs +19 -0
  127. package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
  128. package/dist/openapi/index.d.mts +44 -8
  129. package/dist/openapi/index.d.mts.map +1 -1
  130. package/dist/openapi/index.mjs +3 -2
  131. package/dist/{openapi-C6lm0RmV.mjs → openapi-CstuTM8S.mjs} +55 -229
  132. package/dist/openapi-CstuTM8S.mjs.map +1 -0
  133. package/dist/openapi-tools.service-BC5EC3R3.mjs +206 -0
  134. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
  135. package/dist/{openapi.service-CrLlsXAd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
  136. package/dist/{openapi.service-CrLlsXAd.d.mts.map → openapi.service-YhTiJ1bO.d.mts.map} +1 -1
  137. package/dist/quarry/index.d.mts +14 -5
  138. package/dist/quarry/index.d.mts.map +1 -1
  139. package/dist/quarry/index.mjs +6 -5
  140. package/dist/quarry/runner.d.mts +11 -11
  141. package/dist/quarry/runner.d.mts.map +1 -1
  142. package/dist/quarry/runner.mjs +192 -22
  143. package/dist/quarry/runner.mjs.map +1 -1
  144. package/dist/{quarry-registry-D4hIGScf.d.mts → quarry-registry-CXg0RFXq.d.mts} +4 -4
  145. package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
  146. package/dist/{quarry-registry-DkraZNwn.mjs → quarry.module-BuRPGMDm.mjs} +22 -21
  147. package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
  148. package/dist/queue/index.d.mts +3 -3
  149. package/dist/queue/index.mjs +42 -31
  150. package/dist/queue/index.mjs.map +1 -1
  151. package/dist/queue.module-nddvxzCB.mjs +613 -0
  152. package/dist/queue.module-nddvxzCB.mjs.map +1 -0
  153. package/dist/queue.tokens-DjHnFmre.mjs +11 -0
  154. package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
  155. package/dist/{r2-storage.provider-Hfm6LdZQ.mjs → r2-storage.provider-DCxQt9dD.mjs} +4 -4
  156. package/dist/{r2-storage.provider-Hfm6LdZQ.mjs.map → r2-storage.provider-DCxQt9dD.mjs.map} +1 -1
  157. package/dist/{rate-limit.decorator-D69zdZbp.mjs → rate-limit.decorator-BPAie_p3.mjs} +3 -3
  158. package/dist/{rate-limit.decorator-D69zdZbp.mjs.map → rate-limit.decorator-BPAie_p3.mjs.map} +1 -1
  159. package/dist/rate-limiter/index.d.mts +5 -5
  160. package/dist/rate-limiter/index.d.mts.map +1 -1
  161. package/dist/rate-limiter/index.mjs +26 -21
  162. package/dist/rate-limiter/index.mjs.map +1 -1
  163. package/dist/route-name-DGoBOfPg.mjs +171 -0
  164. package/dist/route-name-DGoBOfPg.mjs.map +1 -0
  165. package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
  166. package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
  167. package/dist/route-registry-CYqLp2Nj.mjs +123 -0
  168. package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
  169. package/dist/router/index.d.mts +2 -2
  170. package/dist/router/index.mjs +18 -8
  171. package/dist/router-CWGBD-Bg.mjs +78 -0
  172. package/dist/router-CWGBD-Bg.mjs.map +1 -0
  173. package/dist/router-resolver-D4YlPNlm.mjs +88 -0
  174. package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
  175. package/dist/seeder/index.d.mts +14 -4
  176. package/dist/seeder/index.d.mts.map +1 -1
  177. package/dist/seeder/index.mjs +5 -3
  178. package/dist/{seeder-BADTig4n.mjs → seeder-7ubkms-Y.mjs} +7 -56
  179. package/dist/seeder-7ubkms-Y.mjs.map +1 -0
  180. package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
  181. package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
  182. package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
  183. package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
  184. package/dist/{signed-url-BqUqt5dF.mjs → signed-url-DIU0sK_6.mjs} +1 -1
  185. package/dist/{signed-url-BqUqt5dF.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
  186. package/dist/storage/index.d.mts +3 -3
  187. package/dist/storage/index.d.mts.map +1 -1
  188. package/dist/storage/index.mjs +2 -2
  189. package/dist/storage/providers/index.d.mts +2 -2
  190. package/dist/storage/providers/index.d.mts.map +1 -1
  191. package/dist/storage/providers/index.mjs +1 -1
  192. package/dist/{storage-BA3ppVYM.mjs → storage-MDZypIE9.mjs} +12 -11
  193. package/dist/{storage-BA3ppVYM.mjs.map → storage-MDZypIE9.mjs.map} +1 -1
  194. package/dist/{storage-provider.interface-DQMtT42e.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -2
  195. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
  196. package/dist/storage.error-Dnib4VHc.mjs +8 -0
  197. package/dist/{storage.error-C6FY037a.mjs.map → storage.error-Dnib4VHc.mjs.map} +1 -1
  198. package/dist/{stratal-Bdq4IdB3.mjs → stratal-DL9M38_s.mjs} +142 -140
  199. package/dist/stratal-DL9M38_s.mjs.map +1 -0
  200. package/dist/{stratal-BsKmvP6J.d.mts → stratal-DwDJPY9N.d.mts} +3 -3
  201. package/dist/{stratal-BsKmvP6J.d.mts.map → stratal-DwDJPY9N.d.mts.map} +1 -1
  202. package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
  203. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
  204. package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
  205. package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
  206. package/dist/{types-BaeHi67f.d.mts → types-CmV_9xBD.d.mts} +1 -1
  207. package/dist/types-CmV_9xBD.d.mts.map +1 -0
  208. package/dist/uri-h7Q8Jug9.mjs +251 -0
  209. package/dist/uri-h7Q8Jug9.mjs.map +1 -0
  210. package/dist/{usage-generator-DTqaUMR9.mjs → usage-generator-DAWYasuP.mjs} +4 -4
  211. package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
  212. package/dist/{validation-DUzcjb8Q.mjs → validation-CpOjviyT.mjs} +6 -6
  213. package/dist/{validation-DUzcjb8Q.mjs.map → validation-CpOjviyT.mjs.map} +1 -1
  214. package/dist/{validation.context-XTysWJ3b.mjs → validation.context-CRvmrhq7.mjs} +3 -3
  215. package/dist/{validation.context-XTysWJ3b.mjs.map → validation.context-CRvmrhq7.mjs.map} +1 -1
  216. package/dist/versioning.service-C6aHky8-.mjs +36 -0
  217. package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
  218. package/dist/websocket/index.d.mts +11 -2
  219. package/dist/websocket/index.d.mts.map +1 -1
  220. package/dist/websocket/index.mjs +1 -1
  221. package/dist/workers/index.d.mts +2 -2
  222. package/dist/workers/index.d.mts.map +1 -1
  223. package/dist/workers/index.mjs +3 -3
  224. package/dist/workers/index.mjs.map +1 -1
  225. package/dist/{zod-hMa3rSHV.mjs → zod-eKqqhZ5_.mjs} +2 -2
  226. package/dist/{zod-hMa3rSHV.mjs.map → zod-eKqqhZ5_.mjs.map} +1 -1
  227. package/dist/{zod-DvWTfRpI.d.mts → zod-wecrEVAs.d.mts} +8 -3
  228. package/dist/zod-wecrEVAs.d.mts.map +1 -0
  229. package/package.json +19 -30
  230. package/dist/base-email.provider-BWZHIjt8.mjs +0 -42
  231. package/dist/base-email.provider-BWZHIjt8.mjs.map +0 -1
  232. package/dist/cache.service-e34gV6tz.d.mts.map +0 -1
  233. package/dist/cache.tokens-ovi_c52J.mjs +0 -6
  234. package/dist/cache.tokens-ovi_c52J.mjs.map +0 -1
  235. package/dist/colors-axmupKdp.mjs +0 -16
  236. package/dist/colors-axmupKdp.mjs.map +0 -1
  237. package/dist/command-BU4ApTo5.mjs.map +0 -1
  238. package/dist/command-wXfvHbBZ.d.mts.map +0 -1
  239. package/dist/consumer-registry-DHQtypr1.d.mts.map +0 -1
  240. package/dist/cron-manager-9bpN9bu4.mjs.map +0 -1
  241. package/dist/cron-manager-CSTIBPcM.d.mts +0 -124
  242. package/dist/cron-manager-CSTIBPcM.d.mts.map +0 -1
  243. package/dist/di-BO1QIb5H.mjs.map +0 -1
  244. package/dist/env-DKSbuBi5.d.mts.map +0 -1
  245. package/dist/events-D1KdDaiP.mjs.map +0 -1
  246. package/dist/index-B4UBK-2T.d.mts.map +0 -1
  247. package/dist/index-BtlE9RuO.d.mts.map +0 -1
  248. package/dist/index-CW1YHSft.d.mts.map +0 -1
  249. package/dist/index-DEncMcC6.d.mts.map +0 -1
  250. package/dist/index-Dj5IMwtr.d.mts.map +0 -1
  251. package/dist/module-xYoHba6B.mjs.map +0 -1
  252. package/dist/openapi-C6lm0RmV.mjs.map +0 -1
  253. package/dist/quarry-registry-D4hIGScf.d.mts.map +0 -1
  254. package/dist/quarry-registry-DkraZNwn.mjs.map +0 -1
  255. package/dist/queue.module-DeWJ0tQM.mjs +0 -355
  256. package/dist/queue.module-DeWJ0tQM.mjs.map +0 -1
  257. package/dist/resend.provider-Ur6tU7fK.mjs +0 -68
  258. package/dist/resend.provider-Ur6tU7fK.mjs.map +0 -1
  259. package/dist/router-Cy6DjkvP.mjs +0 -1852
  260. package/dist/router-Cy6DjkvP.mjs.map +0 -1
  261. package/dist/seeder-BADTig4n.mjs.map +0 -1
  262. package/dist/smtp.provider-C129sNBT.mjs +0 -76
  263. package/dist/smtp.provider-C129sNBT.mjs.map +0 -1
  264. package/dist/storage-provider.interface-DQMtT42e.d.mts.map +0 -1
  265. package/dist/storage.error-C6FY037a.mjs +0 -8
  266. package/dist/stratal-Bdq4IdB3.mjs.map +0 -1
  267. package/dist/types-BaeHi67f.d.mts.map +0 -1
  268. package/dist/usage-generator-DTqaUMR9.mjs.map +0 -1
  269. package/dist/zod-DvWTfRpI.d.mts.map +0 -1
  270. /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"router-Cy6DjkvP.mjs","names":[],"sources":["../src/router/errors/route-not-found.error.ts","../src/router/errors/schema-validation.error.ts","../src/router/errors/index.ts","../src/router/middleware/logger.middleware.ts","../src/router/middleware/domain.middleware.ts","../src/router/middleware/middleware-chain.ts","../src/router/trailing-slash.ts","../src/router/middleware/trailing-slash-redirect.ts","../src/router/decorators/route.decorator.ts","../src/router/schemas/common.schemas.ts","../src/router/utils/path.ts","../src/router/utils/route-name.ts","../src/router/services/route-registration.service.ts","../src/router/hono-app.ts","../src/i18n/i18n.options.ts","../src/router/services/locale-path.service.ts","../src/router/services/versioning.service.ts","../src/router/route-registry.ts","../src/router/route-url.ts","../src/router/uri.ts","../src/router/middleware/verify-signature.middleware.ts"],"sourcesContent":["import { HttpException } from '../../errors'\n\nexport class RouteNotFoundError extends HttpException {\n public readonly path: string\n public readonly method: string\n\n constructor(path: string, method: string) {\n super(404, `Route not found: ${method} ${path}`)\n this.path = path\n this.method = method\n }\n}\n","import { HttpException } from '../../errors'\nimport type { ZodError, z } from '../../i18n/validation/zod'\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: z.core.$ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n }\n}\n","import { HttpException } from '../../errors';\nimport type { z, ZodError } from '../../i18n/validation/zod';\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: z.core.$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 { MiddlewareHandler } from 'hono'\nimport type { LoggerService } from '../../logger'\n\n/**\n * Create a Hono middleware that logs HTTP requests using our Logger service\n *\n * Logs request method, path, status code, and duration in milliseconds.\n * Format: [HTTP] METHOD /path -> STATUS (duration ms)\n *\n * @param logger - Logger service instance\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n * app.use('*', createLoggerMiddleware(logger))\n * ```\n */\nexport function createLoggerMiddleware(logger: LoggerService): MiddlewareHandler {\n return async (c, next) => {\n const start = Date.now()\n const method = c.req.method\n const path = c.req.path\n\n await next()\n\n const duration = Date.now() - start\n const status = c.res.status\n\n logger.info(`[HTTP] ${method} ${path} -> ${status}`, {\n method,\n path,\n status,\n duration,\n })\n }\n}\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 = () => {\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() as Promise<void>\n }\n return middleware.handle(ctx, guardedNext) as Promise<void>\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 type { TrailingSlashMode } from './types'\n\n/**\n * Apply a trailing-slash mode to a URL or path.\n *\n * - `'ignore'` — return as-is.\n * - `'always'` — append `/` to the pathname unless it already has one.\n * Skipped when the last segment contains `.` (file-like paths) and for the\n * root `/` path.\n * - `'never'` — strip a trailing `/` from the pathname. Skipped for root.\n *\n * Preserves query string and hash. Handles both relative paths\n * (`/foo?x=1`) and absolute URLs (`https://host/foo?x=1`).\n *\n * Used by URL-generation helpers and the redirect middleware so canonical\n * form is computed in one place.\n */\nexport function applyTrailingSlash(url: string, mode: TrailingSlashMode): string {\n if (mode === 'ignore') return url\n\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const parsed = isAbsolute\n ? new URL(url)\n : new URL(url, 'http://placeholder.local')\n\n const path = parsed.pathname\n if (path === '/') return url\n\n const hasTrailing = path.endsWith('/')\n\n if (mode === 'always' && !hasTrailing) {\n const lastSegment = path.slice(path.lastIndexOf('/') + 1)\n if (lastSegment.includes('.')) return url\n parsed.pathname = `${path}/`\n } else if (mode === 'never' && hasTrailing) {\n parsed.pathname = path.slice(0, -1)\n } else {\n return url\n }\n\n return isAbsolute\n ? parsed.toString()\n : `${parsed.pathname}${parsed.search}${parsed.hash}`\n}\n","import type { MiddlewareHandler } from 'hono'\nimport { applyTrailingSlash } from '../trailing-slash'\nimport type { RouterEnv, TrailingSlashMode } from '../types'\n\nconst REDIRECT_STATUS = 308\n\n/**\n * Create a Hono middleware that canonicalises trailing slashes via 308 redirects.\n *\n * - `'ignore'` — returns `null`; routes match both `/foo` and `/foo/` natively\n * (Hono handles this when constructed with `strict: false`).\n * - `'always'` — non-trailing requests redirect to the trailing-slash form.\n * Paths whose last segment contains `.` (e.g. `/api/openapi.json`) are skipped.\n * - `'never'` — trailing requests redirect to the non-trailing form.\n *\n * Root (`/`) is always passed through unchanged.\n *\n * 308 is used so that POST/PUT/PATCH bodies survive the redirect.\n *\n * Location headers are emitted as path-relative URIs so the user agent\n * resolves them against the effective request URI — sidestepping scheme\n * mismatches behind HTTPS-terminating proxies that proxy HTTPS pages to an\n * HTTP-speaking backend (which would otherwise produce a mixed-content block).\n */\nexport function createTrailingSlashRedirect(\n mode: TrailingSlashMode,\n): MiddlewareHandler<RouterEnv> | null {\n if (mode === 'ignore') return null\n\n return async (c, next) => {\n const url = new URL(c.req.url)\n const canonicalPath = applyTrailingSlash(url.pathname, mode)\n if (canonicalPath === url.pathname) return next()\n return c.redirect(`${canonicalPath}${url.search}`, REDIRECT_STATUS)\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: z.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: z.object({ id: z.string().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 { z } from '../../i18n/validation/zod'\n\n/**\n * Common OpenAPI Schemas\n *\n * Reusable schema definitions for common API patterns:\n * - Error responses\n * - Pagination\n * - Common parameters\n */\n\n/**\n * Generic error response schema\n * Used for all error responses (4xx, 5xx)\n * Matches the ErrorResponse shape produced by ExceptionHandler\n */\nexport const errorResponseSchema = z.object({\n message: z.string().describe('Human-readable error message'),\n timestamp: z.string().datetime().describe('ISO timestamp when error occurred'),\n stack: z.string().optional().describe('Stack trace (development only)'),\n}).openapi('ErrorResponse')\n\n/**\n * Validation error response schema\n * Used for 400 Bad Request with validation failures\n * Matches the ErrorResponse shape produced by ExceptionHandler\n */\nexport const validationErrorResponseSchema = errorResponseSchema.openapi('ValidationErrorResponse')\n\n/**\n * Pagination query parameters schema\n * Used for list endpoints\n */\nexport const paginationQuerySchema = z.object({\n page: z.coerce.number().int().positive().default(1).describe('Page number (1-indexed)'),\n limit: z.coerce.number().int().positive().max(100).default(20).describe('Items per page (max 100)')\n}).openapi('PaginationQuery')\n\n/**\n * Paginated response wrapper schema\n * Generic wrapper for paginated list responses\n */\nexport const paginatedResponseSchema = <T extends z.ZodType>(itemSchema: T) =>\n z.object({\n data: z.array(itemSchema).describe('Array of items for current page'),\n pagination: z.object({\n page: z.number().int().positive().describe('Current page number'),\n limit: z.number().int().positive().describe('Items per page'),\n total: z.number().int().nonnegative().describe('Total number of items'),\n totalPages: z.number().int().nonnegative().describe('Total number of pages')\n })\n })\n\n/**\n * UUID parameter schema\n * Used for :id parameters in RESTful routes\n */\nexport const uuidParamSchema = z.object({\n id: z.string().uuid().describe('Resource UUID')\n}).openapi('UUIDParam')\n\n/**\n * Success message response schema\n * Used for operations that don't return data (e.g., DELETE)\n */\nexport const successMessageSchema = z.object({\n message: z.string().describe('Success message'),\n data: z.record(z.string(), z.unknown()).optional().describe('Optional additional data')\n}).openapi('SuccessMessage')\n\n/**\n * Common HTTP status error schemas\n * Pre-configured for standard error responses\n */\nexport const commonErrorSchemas = {\n 400: { schema: validationErrorResponseSchema, description: 'Validation error' },\n 401: { schema: errorResponseSchema, description: 'Unauthorized' },\n 403: { schema: errorResponseSchema, description: 'Forbidden' },\n 404: { schema: errorResponseSchema, description: 'Not found' },\n 409: { schema: errorResponseSchema, description: 'Conflict' },\n 500: { schema: errorResponseSchema, description: 'Internal server error' }\n} as const\n","/**\n * Path normalization and route ordering utilities.\n *\n * Users always write Hono-style `:param` paths (`:companyId`, `:id`).\n * OpenAPI requires `{param}` style — conversion happens only at registration time.\n */\n\n/**\n * Convert Hono-style `:param` path segments to OpenAPI-style `{param}`.\n * Strips regex constraints (e.g., `:locale{sw}` → `{locale}`).\n *\n * @example\n * toOpenAPIPath('/users/:id') // '/users/{id}'\n * toOpenAPIPath('/:companyId/users/:userId') // '/{companyId}/users/{userId}'\n * toOpenAPIPath('/users/:id/posts') // '/users/{id}/posts'\n * toOpenAPIPath('/:locale{en|fr}/users') // '/{locale}/users'\n */\nexport function toOpenAPIPath(path: string): string {\n return path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\\{[^}]*\\})?/g, '{$1}')\n}\n\n/**\n * Convert Hono-style `:param` path segments to OpenAPI-style `{param}`,\n * preserving regex constraints.\n *\n * Used for Hono route registration via `app.openapi()`. The non-greedy\n * regex in `@hono/zod-openapi` (`\\/{(.+?)}/g`) converts `{param}` back\n * to `:param` while leaving the constraint suffix intact.\n *\n * @example\n * toRoutingOpenAPIPath('/:locale{sw}/users/:id') // '/{locale}{sw}/users/{id}'\n * toRoutingOpenAPIPath('/users/:id') // '/users/{id}'\n */\nexport function toRoutingOpenAPIPath(path: string): string {\n return path.replace(\n /:([a-zA-Z_][a-zA-Z0-9_]*)(\\{[^}]*\\})?/g,\n (_, name: string, constraint?: string) => constraint ? `{${name}}${constraint}` : `{${name}}`,\n )\n}\n\n/**\n * Compute a packed specificity key for route ordering.\n * Encodes both score and segment count into a single number to avoid object allocation.\n *\n * Lower score = higher priority (registered first in Hono).\n * Scoring: static = 0, `:param{constraint}` = 5, `:param` = 10, wildcard `{.+}` / `{.*}` = 100.\n *\n * Packed as: score * 10000 - segmentCount (negative segment count so more segments = lower key = higher priority)\n *\n * Locale variants score against the path with the leading `/:locale{…}` segment\n * stripped — the variant's score therefore matches its primary, but its larger\n * segment count makes it sort just before the primary. Without this, a primary\n * catch-all (e.g. `/:slug{.+}`) gobbles locale-prefixed URLs because Hono picks\n * whichever matching route was registered first.\n */\nfunction getPathSpecificityKey(route: { path: string; isLocaleVariant?: boolean }): number {\n const segmentCount = countSegments(route.path)\n const scoringPath = route.isLocaleVariant\n ? (route.path.replace(/^\\/:locale\\{[^}]*\\}/, '') || '/')\n : route.path\n\n let score = 0\n let i = 0\n while (i < scoringPath.length) {\n if (scoringPath.charCodeAt(i) === 47 /* '/' */) { i++; continue }\n\n let end = scoringPath.indexOf('/', i)\n if (end === -1) end = scoringPath.length\n\n const segment = scoringPath.substring(i, end)\n\n if (segment.includes('{.+}') || segment.includes('{.*}')) {\n score += 100\n } else if (segment.charCodeAt(0) === 58 /* ':' */) {\n score += segment.includes('{') ? 5 : 10\n }\n\n i = end\n }\n\n return score * 10000 - segmentCount\n}\n\nfunction countSegments(path: string): number {\n let count = 0\n let i = 0\n while (i < path.length) {\n if (path.charCodeAt(i) === 47 /* '/' */) { i++; continue }\n let end = path.indexOf('/', i)\n if (end === -1) end = path.length\n count++\n i = end\n }\n return count\n}\n\n/**\n * Compute a specificity score for route ordering.\n * Lower score = higher priority (registered first in Hono).\n *\n * Scoring: static = 0, `:param{constraint}` = 5, `:param` = 10, wildcard `{.+}` / `{.*}` = 100.\n */\nexport function getPathSpecificityScore(path: string): number {\n const segments = path.split('/').filter(Boolean)\n let score = 0\n for (const segment of segments) {\n if (segment.includes('{.+}') || segment.includes('{.*}')) {\n score += 100\n } else if (segment.startsWith(':') && segment.includes('{')) {\n score += 5\n } else if (segment.startsWith(':')) {\n score += 10\n }\n }\n return score\n}\n\n/**\n * Sort routes by specificity so Hono registers them in the correct order.\n *\n * 1. Static paths before parameterized before wildcards\n * 2. More segments = more specific (tie-breaker)\n * 3. Locale-prefixed variants before their primary (so a locale-prefixed\n * request matches the variant first; a primary catch-all would otherwise\n * swallow the locale prefix into its param)\n */\nexport function sortRoutesBySpecificity<T extends { path: string; isLocaleVariant?: boolean }>(routes: T[]): T[] {\n // Pre-compute packed specificity keys (avoids object allocation per route)\n const keys = new Map<T, number>()\n for (const route of routes) {\n keys.set(route, getPathSpecificityKey(route))\n }\n\n const copy = routes.slice()\n copy.sort((a, b) => keys.get(a)! - keys.get(b)!)\n return copy\n}\n","/**\n * Route naming utilities.\n *\n * Extracts parameter names from paths and domains,\n * and generates convention-based route names.\n */\n\n/**\n * Extract parameter names from a Hono-style path.\n *\n * @example\n * extractParamNames('/users/:id') // ['id']\n * extractParamNames('/:companyId/users/:userId') // ['companyId', 'userId']\n * extractParamNames('/users') // []\n */\nexport function extractParamNames(path: string): string[] {\n if (!path.includes(':')) return []\n const matches = path.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)/g)\n return [...matches].map(m => m[1])\n}\n\n/**\n * Extract parameter names from a domain pattern.\n *\n * @example\n * extractDomainParamNames('{tenant}.example.com') // ['tenant']\n * extractDomainParamNames('{region}.{tenant}.example.com') // ['region', 'tenant']\n * extractDomainParamNames('example.com') // []\n */\nexport function extractDomainParamNames(domain: string): string[] {\n if (!domain.includes('{')) return []\n const matches = domain.matchAll(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g)\n return [...matches].map(m => m[1])\n}\n\n/**\n * Auto-generate a route name for convention-based `@Route` methods.\n *\n * Strips common prefixes (`/api/`, `/v{N}/`) and parameter segments,\n * then joins remaining static segments with dots and appends the method name.\n *\n * @example\n * generateConventionRouteName('/users', 'index') // 'users.index'\n * generateConventionRouteName('/users', 'show') // 'users.show'\n * generateConventionRouteName('/api/v1/users', 'create') // 'users.create'\n * generateConventionRouteName('/api/v1/users/:userId/notes', 'index') // 'users.notes.index'\n * generateConventionRouteName('/:companyId/users', 'index') // 'users.index'\n * generateConventionRouteName('/users/:userId/notes/:noteId/tags', 'index') // 'users.notes.tags.index'\n */\nexport function generateConventionRouteName(basePath: string, methodName: string): string {\n // Single-pass: split and filter in one loop (avoids 4 intermediate arrays)\n const parts = basePath.split('/')\n const segments: string[] = []\n for (const s of parts) {\n if (s && s !== 'api' && !s.startsWith(':') && !/^v\\d+$/.test(s)) {\n segments.push(s)\n }\n }\n\n if (segments.length === 0) {\n return methodName\n }\n\n return `${segments.join('.')}.${methodName}`\n}\n","import type { Context, MiddlewareHandler } from 'hono';\nimport type { UpgradeWebSocket, WSContext, WSEvents } from 'hono/ws';\nimport { inject } from '../../di';\nimport { type Container, getMethodInjections } 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 type { ZodType } from '../../i18n/validation/zod';\nimport { createRoute, z } 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 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, 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 { RouterError } from '../router.error';\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 { ROUTER_TOKENS } from '../router.tokens';\nimport { commonErrorSchemas } from '../schemas/common.schemas';\nimport type {\n ControllerOptions,\n HttpMethod,\n OpenAPIRouteConfig,\n RouteBodyObject,\n RouteConfig,\n RouteMetadata,\n RouteResponseObject,\n RouterEnv,\n SecuritySchemeRecord,\n} from '../types';\nimport { toOpenAPIPath, toRoutingOpenAPIPath } from '../utils/path';\nimport { generateConventionRouteName } from '../utils/route-name';\nimport type { LocalePathService } from './locale-path.service';\n\nconst invokeHandler = (instance: Record<string, (...args: unknown[]) => unknown>, method: string, ...args: unknown[]): Promise<unknown> => {\n try {\n return Promise.resolve(instance[method](...args))\n } catch (err: unknown) {\n return Promise.reject(err as Error)\n }\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\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 ) { }\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 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 // 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 z.ZodObject).shape\n mergedParams = mergedParams\n ? (mergedParams as z.ZodObject).extend(prefixShape)\n : (routerConfig.params as z.ZodObject).extend({})\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 handler = this.createControllerHandler(ControllerClass, methodName, responseSchema)\n\n for (const route of expandedRoutes) {\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 and register OpenAPI route\n const metadata = this.mergeMetadata(controllerOpts, routeConfig, ControllerClass, methodName)\n const openApiRoute = this.buildOpenAPIRoute(\n httpMethod,\n route.path,\n routeConfig,\n metadata,\n meta.type === 'convention' ? methodName : undefined,\n statusCodeOverride,\n route.isLocaleVariant ?? false,\n )\n\n this.logger.info(`Registering route`, {\n controller: className,\n method: httpMethod.toUpperCase(),\n path: route.path,\n methodName,\n tags: metadata.tags,\n hidden: route.hidden,\n })\n\n // Wrap the controller handler so scoped middleware and guards\n // run AFTER Hono's request validators. @hono/zod-openapi\n // composes a route as `...routeMiddleware, ...validators, handler`\n // (see node_modules/@hono/zod-openapi/dist/index.js), which means\n // anything attached via `route.middleware` runs *before*\n // validation — and therefore can't read `c.req.valid('param')`.\n // Wrapping the handler is the only place we can run middleware\n // after validators in this Hono pipeline.\n //\n // Final order: global app.use → request validators → scoped\n // middleware → guards → controller handler.\n const wrappedHandler = this.wrapHandlerWithChain(handler, effectiveMiddleware, allGuards)\n this.app.openapi(openApiRoute, wrappedHandler)\n\n // Register clean path in OpenAPI spec (strips regex constraints from params)\n if (!route.hidden) {\n const { hide: _, ...specRoute } = openApiRoute\n this.app.openAPIRegistry.registerPath({\n ...specRoute,\n path: toOpenAPIPath(route.path),\n })\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[] } {\n const tags = [...(controllerOpts?.tags ?? []), ...(routeConfig.tags ?? [])]\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 }\n }\n\n /**\n * Build OpenAPI route configuration from metadata\n * Creates a route definition compatible with @hono/zod-openapi.\n *\n * Scoped middleware and guards are NOT attached to `route.middleware`\n * here — they're composed into a wrapped handler in `collectRoutes` so\n * they run after Hono's request validators. See `wrapHandlerWithChain`.\n */\n private buildOpenAPIRoute(\n method: Exclude<HttpMethod, 'all'>,\n path: string,\n routeConfig: RouteConfig,\n metadata: { tags: string[]; security: Record<string, string[]>[] },\n methodName?: string,\n statusCodeOverride?: number,\n hasLocaleParam = false,\n ): OpenAPIRouteConfig {\n try {\n const route: Partial<OpenAPIRouteConfig> & { hide?: boolean } = {\n method,\n path: toRoutingOpenAPIPath(path),\n request: {},\n responses: {},\n // Always hide from OpenAPI registry — clean paths are registered separately via registerPath()\n hide: true,\n }\n\n // Add request body if defined\n if (routeConfig.body) {\n const bodySchema = this.isRouteBodyObject(routeConfig.body) ? routeConfig.body.schema : routeConfig.body\n const bodyContentType = this.isRouteBodyObject(routeConfig.body) ? routeConfig.body.contentType ?? DEFAULT_CONTENT_TYPE : DEFAULT_CONTENT_TYPE\n\n route.request = {\n ...route.request,\n body: {\n content: {\n [bodyContentType]: {\n schema: bodySchema,\n },\n },\n },\n }\n }\n\n // Add query parameters if defined\n if (routeConfig.query) {\n route.request = {\n ...route.request,\n query: routeConfig.query,\n }\n }\n\n // Add URL parameters if defined\n if (routeConfig.params) {\n route.request = {\n ...route.request,\n params: routeConfig.params,\n }\n }\n\n // Auto-inject locale path parameter for locale-prefixed routes\n const localeConfig = this.localePathService.localePathConfig\n if (hasLocaleParam && localeConfig) {\n const localeParam = z.object({\n locale: z.enum(localeConfig.prefixedLocales as [string, ...string[]]).openapi({\n param: {\n name: 'locale',\n in: 'path',\n },\n }).optional(),\n })\n\n route.request = {\n ...route.request,\n params: route.request!.params\n ? (route.request!.params as z.ZodObject).extend(localeParam.shape)\n : localeParam,\n }\n }\n\n // Derive success status code from method name or use override\n const successStatus = statusCodeOverride\n ?? (methodName && METHOD_STATUS_CODES[methodName as keyof typeof METHOD_STATUS_CODES])\n ?? 200\n\n // Build responses object with auto-derived status\n const responses: NonNullable<OpenAPIRouteConfig['responses']> = {}\n\n // Add success response with derived status code\n const responseDef = routeConfig.response\n if (responseDef) {\n if (typeof responseDef === 'object' && 'schema' in responseDef) {\n const responseContentType = responseDef.contentType ?? DEFAULT_CONTENT_TYPE\n responses[successStatus] = {\n content: {\n [responseContentType]: { schema: responseDef.schema },\n },\n description: responseDef.description ?? `Response ${successStatus}`,\n }\n } else {\n responses[successStatus] = {\n content: {\n [DEFAULT_CONTENT_TYPE]: { schema: responseDef },\n },\n description: `Response ${successStatus}`,\n }\n }\n }\n\n // Auto-merge common error schemas (400, 401, 403, 404, 409, 500)\n // Controllers only need to define success response; error responses are added automatically\n for (const [statusStr, schema] of Object.entries(commonErrorSchemas)) {\n const status = parseInt(statusStr)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive: avoid overwriting success response status\n responses[status] ??= schema\n }\n\n route.responses = responses\n\n // Add tags if provided\n if (metadata.tags.length > 0) {\n route.tags = metadata.tags\n }\n\n // Add security if provided\n if (metadata.security.length > 0) {\n route.security = metadata.security\n }\n\n // Add description and summary\n if (routeConfig.description) {\n route.description = routeConfig.description\n }\n if (routeConfig.summary) {\n route.summary = routeConfig.summary\n }\n\n return createRoute(route as OpenAPIRouteConfig)\n } catch (error) {\n throw new RouterError(`OpenAPI route registration failed for \"${path}\": ${error instanceof Error ? error.message : String(error)}`)\n }\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 ): (c: Context<RouterEnv>) => Promise<Response> {\n const handler = async (c: Context<RouterEnv>) => {\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 (responseSchema && c.env.ENVIRONMENT !== 'production') {\n return this.validateResponse(response, responseSchema)\n }\n\n return response\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 * 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 = schema.safeParse(body)\n if (!result.success) {\n throw new ResponseValidationError(result.error)\n }\n\n return response\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { inject } from '../di'\nimport type { Application } from '../application'\nimport type { Container } from '../di/container'\nimport { runWithContainer } from '../di/container-storage'\nimport { Singleton } from '../di/decorators'\nimport { CONTAINER_TOKEN, DI_TOKENS } from '../di/tokens'\nimport { createHttpExceptionContext } from '../errors/exception-context'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport { OpenAPIHono } from '../i18n/validation/zod'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { OPENAPI_TOKENS, type OpenAPIService } from '../openapi'\nimport type { Constructor } from '../types'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport { RouteNotFoundError, SchemaValidationError } from './errors'\nimport { RouterError } from './router.error'\nimport { createLoggerMiddleware, createMiddlewareChain, createTrailingSlashRedirect } from './middleware'\nimport type { Middleware } from './middleware.interface'\nimport { RouterContext } from './router-context'\nimport { RouteRegistrationService } from './services/route-registration.service'\nimport type { RouterEnv, TrailingSlashMode } from './types'\n\nconst isMiddlewareClass = (arg: unknown): arg is Constructor<Middleware> =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n typeof arg === 'function' && arg.prototype && 'handle' in arg.prototype\n\n\n/**\n * HonoApp — extends OpenAPIHono with Stratal-specific setup\n *\n * - Request scope middleware (child container per request)\n * - Global middleware (CORS, logging, error handling)\n * - defaultHook for validation errors\n * - `use()` overload for Stratal middleware classes\n * - `configure()` for OpenAPI, routes, and 404\n */\n@Singleton()\nexport class HonoApp extends OpenAPIHono<RouterEnv> {\n private configured = false\n private readonly _container: Container\n private readonly _logger: LoggerService\n\n /**\n * Reference to the original Hono `use` implementation.\n * Captured in constructor after super() sets it as an instance property.\n * Used by private methods to register middleware without going through the override.\n */\n private nativeUse!: typeof this.use\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(LOGGER_TOKENS.LoggerService) logger: LoggerService,\n @inject(DI_TOKENS.Application) application: Application,\n ) {\n const trailingSlash: TrailingSlashMode = application.config.trailingSlash ?? 'ignore'\n\n super({\n // Always non-strict: a registered `/foo` route matches both `/foo` and `/foo/`.\n // For the redirect modes, the trailing-slash middleware runs first and\n // canonicalises via 308 before matching reaches the registered route.\n strict: false,\n defaultHook: (result, c) => {\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n const override = c.get('validationSuccessResponse')\n if (override) return override\n },\n })\n\n this._container = container\n this._logger = logger\n\n // Capture Hono's original `use` (set by super() as an instance property)\n this.nativeUse = this.use\n\n // Override `use` to support Stratal middleware classes alongside Hono-native handlers\n this.use = ((...args: unknown[]) => {\n if (isMiddlewareClass(args[0])) {\n this.nativeUse('*', createMiddlewareChain(args as Constructor<Middleware>[]))\n return this\n }\n\n if (typeof args[0] === 'string' && args.length > 1 && isMiddlewareClass(args[1])) {\n this.nativeUse(args[0], createMiddlewareChain(args.slice(1) as Constructor<Middleware>[]))\n return this\n }\n\n return (this.nativeUse as (...a: unknown[]) => unknown)(...args)\n }) as typeof this.use\n\n // Trailing-slash redirect runs first so redirected requests skip request-scope\n // and logger overhead.\n const trailingSlashRedirect = createTrailingSlashRedirect(trailingSlash)\n if (trailingSlashRedirect) {\n this.nativeUse('*', trailingSlashRedirect)\n }\n\n // Internal setup — uses nativeUse to bypass the override\n this.setupRequestScope()\n this.applyGlobalMiddleware()\n }\n\n /**\n * Apply global middleware (logger + error handler).\n * Called by Application after locale middleware is applied by LocalePathService.\n */\n private applyGlobalMiddleware(): void {\n this.nativeUse('*', createLoggerMiddleware(this._logger) as MiddlewareHandler<RouterEnv>)\n this.onError((err, c) => this.handleException(c, err))\n }\n\n /**\n * Configure OpenAPI endpoints, controller routes, and 404 handler.\n * Called once by Application.initialize().\n */\n async configure(): Promise<void> {\n if (this.configured) throw new RouterError('HonoApp has already been configured')\n\n // OpenAPI endpoints\n const openAPIService = this._container.resolve<OpenAPIService>(OPENAPI_TOKENS.OpenAPIService)\n openAPIService.setupEndpoints(this, this._container)\n\n // Controller routes + global middleware\n const routeRegistrationService = this._container.resolve<RouteRegistrationService>(RouteRegistrationService)\n await routeRegistrationService.configure()\n\n // 404 handler (must be last)\n this.notFound((c) => { throw new RouteNotFoundError(c.req.path, c.req.method) })\n\n this.configured = true\n }\n\n private setupRequestScope(): void {\n this.nativeUse('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const routerContext = new RouterContext(c)\n const requestContainer = this._container.createRequestScope(routerContext)\n c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer)\n\n await runWithContainer(requestContainer, next)\n })\n }\n\n private handleException(c: Context<RouterEnv>, err: unknown) {\n // Fallback to global container if request scope setup failed before storing REQUEST_CONTAINER\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: REQUEST_CONTAINER may be unset if request scope middleware throws\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createHttpExceptionContext(c)\n return handler.handle(err, ctx)\n }\n}\n","/**\n * I18n Module Options\n *\n * Configuration options for the I18n dynamic module.\n * Use with I18nModule.forRoot() to configure locale settings.\n * Use I18nModule.registerMessages() to add translations.\n */\n\nimport type { DetectorOptions } from 'hono/language';\n\n/**\n * Detection strategy for locale resolution\n *\n * - `'cookie'` — reads from the `locale` cookie (default)\n * - `'header'` — reads from the `Accept-Language` header\n * - `'querystring'` — reads from the `?locale=` query parameter\n * - `'path'` — reads from the first URL path segment (e.g., `/en/api/users`)\n */\nexport type DetectionStrategy = 'cookie' | 'header' | 'querystring' | 'path'\n\ninterface BaseDetection {\n /** Set to false to disable language detection entirely. @default true */\n enabled?: boolean\n}\n\n/**\n * Language detection options (discriminated by strategy)\n *\n * @example Cookie detection (default)\n * ```typescript\n * { strategy: 'cookie' }\n * ```\n *\n * @example Header detection\n * ```typescript\n * { strategy: 'header' }\n * ```\n *\n * @example Path detection\n * ```typescript\n * { strategy: 'path' }\n * ```\n *\n * @example Disable detection\n * ```typescript\n * { enabled: false }\n * ```\n */\nexport type LanguageDetectionOptions =\n | (BaseDetection & { strategy?: 'cookie'; cookieOptions?: DetectorOptions['cookieOptions'] })\n | (BaseDetection & { strategy: 'header' })\n | (BaseDetection & { strategy: 'querystring' })\n | (BaseDetection & {\n strategy: 'path'\n /**\n * Controls whether the default locale gets a URL path prefix.\n *\n * - `false` (default) — The default locale has no prefix (`/users`), other locales\n * are prefixed (`/fr/users`). Requests to the prefixed default locale (`/en/users`) return 404.\n * - `'redirect'` — Same as `false`, but requests to the prefixed default locale\n * (`/en/users`) are 301-redirected to the unprefixed path (`/users`).\n * - `true` — All locales are prefixed (`/en/users`, `/fr/users`).\n *\n * @default false\n */\n prefixDefaultLocale?: false | true | 'redirect'\n })\n | { enabled: false }\n\n/**\n * Options for configuring the I18n module\n *\n * @example\n * ```typescript\n * I18nModule.forRoot({\n * defaultLocale: 'en',\n * fallbackLocale: 'en',\n * locales: ['en', 'fr'],\n * detection: { strategy: 'header' },\n * })\n * ```\n */\nexport interface I18nModuleOptions {\n /**\n * Default locale for the application\n * @default 'en'\n */\n defaultLocale?: string\n\n /**\n * Fallback locale when translation is missing\n * @default 'en'\n */\n fallbackLocale?: string\n\n /**\n * List of supported locales\n * Request locales not in this list will fall back to defaultLocale\n */\n locales?: string[]\n\n /**\n * Language detection configuration\n * Controls how the locale is extracted from incoming requests\n */\n detection?: LanguageDetectionOptions\n}\n\n/**\n * Resolved options with all defaults applied\n * Used internally by I18n services\n */\nexport interface ResolvedI18nOptions {\n defaultLocale: string\n fallbackLocale: string\n locales: string[]\n detection: {\n enabled: boolean\n strategy: DetectionStrategy\n /** Resolved value of the path detection `prefixDefaultLocale` option. Only meaningful when `strategy` is `'path'`. */\n prefixDefaultLocale: false | true | 'redirect'\n }\n}\n\n/**\n * Resolve I18n options with defaults\n */\nexport function resolveI18nOptions(options?: I18nModuleOptions): ResolvedI18nOptions {\n const detection = options?.detection\n const enabled = detection ? (detection.enabled !== false) : true\n const strategy: DetectionStrategy = (detection && 'strategy' in detection) ? detection.strategy ?? 'cookie' : 'cookie'\n const prefixDefaultLocale: false | true | 'redirect' =\n (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n return {\n defaultLocale: options?.defaultLocale ?? 'en',\n fallbackLocale: options?.fallbackLocale ?? 'en',\n locales: options?.locales ?? ['en'],\n detection: { enabled, strategy, prefixDefaultLocale },\n }\n}\n\n/**\n * Build Hono languageDetector options from I18n module options\n */\nexport function buildDetectorOptions(options?: I18nModuleOptions): Partial<DetectorOptions> {\n const resolved = resolveI18nOptions(options)\n const strategy = resolved.detection.strategy\n\n const detectorOptions: Partial<DetectorOptions> = {\n order: [strategy],\n fallbackLanguage: resolved.defaultLocale,\n supportedLanguages: resolved.locales,\n lookupCookie: 'locale',\n lookupQueryString: 'locale',\n lookupFromPathIndex: 0,\n ignoreCase: true,\n }\n\n if (strategy === 'cookie') {\n detectorOptions.caches = ['cookie']\n if (options?.detection && 'cookieOptions' in options.detection && options.detection.cookieOptions) {\n detectorOptions.cookieOptions = options.detection.cookieOptions\n }\n } else {\n detectorOptions.caches = false\n }\n\n return detectorOptions\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { languageDetector } from 'hono/language'\nimport { inject } from '../../di'\nimport type { Container } from '../../di/container'\nimport { Singleton } from '../../di/decorators'\nimport { CONTAINER_TOKEN } from '../../di/tokens'\nimport { buildDetectorOptions, type I18nModuleOptions } from '../../i18n/i18n.options'\nimport { I18N_TOKENS } from '../../i18n/i18n.tokens'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\nimport type { HonoApp } from '../hono-app'\nimport { ROUTER_TOKENS } from '../router.tokens'\nimport type { LocalePathConfig, RouterEnv } from '../types'\n\n/**\n * A resolved path with locale variant metadata.\n */\nexport interface ResolvedPath {\n /** The fully resolved path (may include /:locale prefix) */\n path: string\n /** Whether this path is a locale-prefixed variant */\n isLocaleVariant: boolean\n}\n\n/**\n * Resolves locale path variants for route paths.\n *\n * Computes `LocalePathConfig` from `I18nModuleOptions` and provides\n * path expansion for locale-prefixed route variants.\n *\n * Also applies language detection and default locale redirect middleware\n * to HonoApp when resolved from the container.\n *\n * Registered as a singleton in the container.\n */\n@Singleton()\nexport class LocalePathService {\n private readonly _config: LocalePathConfig | null\n private readonly _pathDetectionEnabled: boolean\n private readonly _prefixDefaultLocale: false | true | 'redirect'\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(ROUTER_TOKENS.HonoApp) private readonly honoApp: HonoApp,\n ) {\n const i18nOptions = container.isRegistered(I18N_TOKENS.Options)\n ? container.resolve<I18nModuleOptions>(I18N_TOKENS.Options)\n : undefined\n\n const detection = i18nOptions?.detection\n const detectionEnabled = detection ? detection.enabled !== false : true\n const strategy = (detection && 'strategy' in detection && detection.strategy) ?? 'cookie'\n\n this._pathDetectionEnabled = detectionEnabled && strategy === 'path'\n this._prefixDefaultLocale = (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n if (this._pathDetectionEnabled) {\n const allLocales = i18nOptions?.locales ?? ['en']\n const defaultLocale = i18nOptions?.defaultLocale ?? 'en'\n\n this._config = this._prefixDefaultLocale === true\n ? { allLocales, prefixedLocales: allLocales, defaultLocale: null }\n : { allLocales, prefixedLocales: allLocales.filter(l => l !== defaultLocale), defaultLocale }\n } else {\n this._config = null\n }\n\n // Apply locale middleware to HonoApp\n if (detectionEnabled) {\n this.setupLanguageDetection(i18nOptions)\n }\n if (this._config?.defaultLocale && this._prefixDefaultLocale === 'redirect') {\n this.setupDefaultLocaleRedirect(this._config.defaultLocale)\n }\n }\n\n /** Whether path-based locale detection is enabled */\n get enabled(): boolean {\n return this._pathDetectionEnabled\n }\n\n /** The computed locale path config, or null if path detection is disabled */\n get localePathConfig(): LocalePathConfig | null {\n return this._config\n }\n\n /** The prefixDefaultLocale setting (false, true, or 'redirect') */\n get prefixDefaultLocale(): false | true | 'redirect' {\n return this._prefixDefaultLocale\n }\n\n /**\n * Expand a path into primary + locale-prefixed variants.\n *\n * @param path - The base path to expand\n * @returns Array of resolved paths with locale metadata\n */\n resolve(path: string): ResolvedPath[] {\n if (!this._config) {\n return [{ path, isLocaleVariant: false }]\n }\n\n const constraint = this.buildLocaleConstraint()\n const suffix = path === '/' ? '' : path\n\n // All locales prefixed (prefixDefaultLocale: true)\n if (this._config.defaultLocale === null) {\n return [{ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true }]\n }\n\n // Default locale unprefixed, other locales prefixed\n const result: ResolvedPath[] = [{ path, isLocaleVariant: false }]\n\n // Only add /:locale route when there are non-default locales to match\n // (z.enum requires at least one value)\n if (this._config.prefixedLocales.length > 0) {\n result.push({ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true })\n }\n\n return result\n }\n\n /**\n * Build a Hono regex constraint from prefixed locales.\n * e.g., `{en|de|fr}` — restricts `:locale` to only match known values.\n */\n private buildLocaleConstraint(): string {\n const locales = this._config!.defaultLocale === null\n ? this._config!.allLocales\n : this._config!.prefixedLocales\n return `{${locales.join('|')}}`\n }\n\n /**\n * Apply Hono's languageDetector middleware and bridge the detected language\n * to Stratal's LOCALE context variable.\n */\n private setupLanguageDetection(i18nOptions?: I18nModuleOptions): void {\n const detectorOptions = buildDetectorOptions(i18nOptions)\n\n // Apply Hono's languageDetector\n this.honoApp.use('*', languageDetector(detectorOptions) as MiddlewareHandler<RouterEnv>)\n\n // Bridge: sync Hono's 'language' variable to Stratal's LOCALE context key\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const language = c.get('language')\n if (language) {\n c.set(ROUTER_CONTEXT_KEYS.LOCALE, language)\n }\n await next()\n })\n }\n\n /**\n * Redirect requests that include the default locale prefix to the unprefixed path.\n * For example, `/en/users` → 301 redirect to `/users`.\n *\n * Only active when `prefixDefaultLocale` is `'redirect'`.\n */\n private setupDefaultLocaleRedirect(defaultLocale: string): void {\n const prefix = `/${defaultLocale}`\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const path = new URL(c.req.url).pathname\n if (path === prefix || path.startsWith(`${prefix}/`)) {\n const stripped = path.slice(prefix.length) || '/'\n return c.redirect(stripped, 301)\n }\n await next()\n })\n }\n}\n","import { inject } from '../../di'\nimport { Singleton } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport type { Application } from '../../application'\nimport { VERSION_NEUTRAL } from '../constants'\nimport type { VersioningOptions } from '../types'\n\n/**\n * Resolves version prefixes for route paths.\n *\n * Handles VERSION_NEUTRAL, multi-version arrays, default version fallback,\n * and configurable prefix (default: 'v').\n *\n * Registered as a singleton in the container.\n */\n@Singleton()\nexport class VersioningService {\n private readonly options: VersioningOptions | null\n\n constructor(@inject(DI_TOKENS.Application) app: Application) {\n this.options = app.config.versioning ?? null\n }\n\n /** Whether versioning is enabled */\n get enabled(): boolean {\n return this.options !== null\n }\n\n /**\n * Resolve versioned paths for a base path.\n *\n * @param basePath - The base path (e.g., '/users')\n * @param version - Explicit version from controller/router config\n * @returns Array of versioned path strings (e.g., ['/v1/users', '/v2/users'])\n */\n resolve(basePath: string, version?: string | string[] | typeof VERSION_NEUTRAL): string[] {\n // Versioning disabled — return base path as-is\n if (!this.options) {\n return [basePath]\n }\n\n // VERSION_NEUTRAL — explicitly opt out of versioning\n if (version === VERSION_NEUTRAL) {\n return [basePath]\n }\n\n const prefix = this.options.prefix ?? 'v'\n\n // Explicit version(s) on the controller/router\n if (version !== undefined) {\n const versions = Array.isArray(version) ? version : [version]\n return versions.map(v => `/${prefix}${v}${basePath}`)\n }\n\n // No explicit version — apply defaultVersion if set\n if (this.options.defaultVersion !== undefined) {\n const defaults = Array.isArray(this.options.defaultVersion)\n ? this.options.defaultVersion\n : [this.options.defaultVersion]\n return defaults.map(v => `/${prefix}${v}${basePath}`)\n }\n\n // Versioning enabled but no version and no default — no prefix\n return [basePath]\n }\n}\n","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","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 { inject } from '../di';\nimport type { Application } from '../application';\nimport { Request } from '../di/decorators';\nimport { DI_TOKENS } from '../di/tokens';\nimport { RouterError } from './router.error';\nimport type { RouteName, RouteParams } from './route-map';\nimport type { RegisteredRoute, RouteRegistry } from './route-registry';\nimport type { RouterContext } from './router-context';\nimport { ROUTER_TOKENS } from './router.tokens';\nimport { signUrl, verifySignedUrl, type SignedUrlOptions } from './signed-url';\nimport { applyTrailingSlash } from './trailing-slash';\nimport type { TrailingSlashMode } from './types';\n\n/**\n * Options for URL generation methods.\n */\nexport interface UriOptions {\n /** Generate absolute URL (scheme + host). Defaults to false. */\n absolute?: boolean\n}\n\n/**\n * Options for signed URL generation methods.\n */\nexport interface SignedUriOptions extends UriOptions, SignedUrlOptions { }\n\n/**\n * Encode a value for use as a path parameter.\n *\n * Splits on `/` and encodes each segment with `encodeURIComponent`, so callers\n * can pass slash-containing values for catch-all params (e.g. `:slug{.+}`) and\n * still get a usable URL — `'auth/login'` becomes `'auth/login'`, not\n * `'auth%2Flogin'`. Single segments behave exactly like `encodeURIComponent`.\n */\nfunction encodePathParam(value: string): string {\n return value.split('/').map(encodeURIComponent).join('/')\n}\n\n/**\n * Build a URL from a registered route, filling path/domain params and appending extras as query string.\n *\n * Pure function — no request context needed. Used by both the `Uri` class and the standalone `route()` function.\n *\n * @param route - The registered route to build a URL for\n * @param name - Route name (used in error messages)\n * @param params - Path params, domain params, and extra query params\n * @returns Relative URL string (or absolute with domain prefix if route has a domain pattern)\n *\n * @throws RouterError if a required path or domain param is missing\n */\nexport function buildRouteUrl(\n route: RegisteredRoute,\n name: string,\n params?: Record<string, string>,\n): string {\n const allParams = { ...params }\n const consumedKeys = new Set<string>()\n let url = route.path\n\n // When locale is provided and route has locale variants, prepend locale segment\n if (allParams.locale && route.localePaths?.length) {\n url = `/${allParams.locale}${url === '/' ? '' : url}`\n consumedKeys.add('locale')\n }\n\n // Fill path :param placeholders (handles optional regex constraints like :locale{en|de|fr})\n for (const paramName of route.paramNames) {\n const value = allParams[paramName]\n if (value === undefined) {\n throw new RouterError(`Missing required route parameter \"${paramName}\" for route \"${name}\" (path: ${route.path})`)\n }\n url = url.replace(\n new RegExp(`:${paramName}(\\\\{[^}]*\\\\})?`),\n encodePathParam(value),\n )\n consumedKeys.add(paramName)\n }\n\n // Build domain if present\n let domain: string | undefined\n if (route.domain) {\n domain = route.domain\n for (const domainParam of route.domainParamNames) {\n const value = allParams[domainParam]\n if (value === undefined) {\n throw new RouterError(`Missing required domain parameter \"${domainParam}\" for route \"${name}\" (domain: ${route.domain})`)\n }\n domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value))\n consumedKeys.add(domainParam)\n }\n }\n\n // Remaining params (not consumed by path or domain) become query string\n const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key))\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .filter(([, value]) => Boolean(value))\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = `${url}${queryString.length ? `?${queryString}` : ''}`\n }\n\n // Prepend domain if present\n if (domain) {\n url = `https://${domain}${url}`\n }\n\n return url\n}\n\n/**\n * URL generation service for named routes, signed URLs, and request URL access.\n *\n * Registered as request-scoped in the container — has access to the current request\n * via RouterContext for features like `current()`, `full()`, and signed URLs.\n *\n * @example\n * ```typescript\n * // In a controller:\n * const uri = ctx.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n * uri.route('users.show', { id: '1' })\n * uri.current()\n * await uri.signedRoute('unsubscribe', { user: '1' }, { expiresIn: 3600 })\n *\n * // Set defaults (e.g., in middleware):\n * uri.defaults({ locale: 'en' })\n * uri.route('posts.index') // auto-fills :locale param\n * ```\n */\n@Request()\nexport class Uri {\n private _defaults: Record<string, string> = {}\n private readonly trailingSlash: TrailingSlashMode\n\n constructor(\n @inject(ROUTER_TOKENS.RouteRegistry) private readonly registry: RouteRegistry,\n @inject(ROUTER_TOKENS.RouterContext) private readonly routerContext: RouterContext,\n @inject(DI_TOKENS.Application) application: Application,\n ) {\n this.trailingSlash = application.config.trailingSlash ?? 'ignore'\n }\n\n /**\n * Set default URL parameters for this request.\n * Applied to all subsequent `route()` calls — explicit params override defaults.\n *\n * @param params - Default parameters (e.g., `{ locale: 'en' }`)\n */\n defaults(params: Record<string, string>): void {\n this._defaults = { ...this._defaults, ...params }\n }\n\n /**\n * Read the currently configured default URL parameters.\n *\n * Used by frameworks that need to share these with the client (e.g. the\n * Inertia adapter ships them as a shared prop so `route()` calls in the\n * browser auto-fill the same sticky params as the server).\n */\n getDefaults(): Record<string, string> {\n return { ...this._defaults }\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are consumed from the same object.\n * Extra keys become query string parameters.\n * Default params (from `defaults()`) are merged — explicit params override.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Generated URL string\n *\n * @throws RouterError if route name not found or required params missing\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n const registeredRoute = this.registry.get(name)\n if (!registeredRoute) {\n throw new RouterError(`Route name \"${name}\" was not found in the registry`)\n }\n\n const mergedParams = { ...this._defaults, ...params } as Record<string, string>\n let url = applyTrailingSlash(buildRouteUrl(registeredRoute, name, mergedParams), this.trailingSlash)\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async signedRoute<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n const url = this.route(name, params, options)\n const secret = this.getAppSecret()\n return signUrl(url, secret, options)\n }\n\n /**\n * Generate a temporary signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param expiresIn - Time-to-live in seconds\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Signed URL string with signature and expires query params\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async temporarySignedRoute<N extends RouteName>(name: N, expiresIn: number, params?: RouteParams<N>, options?: UriOptions): Promise<string> {\n return this.signedRoute(name, params, { ...options, expiresIn })\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n const secret = (this.routerContext.c.env as unknown as Record<string, string>).APP_SECRET\n if (!secret) return false\n return verifySignedUrl(this.routerContext.c.req.url, secret)\n }\n\n /**\n * Get the current request URL pathname (without query string).\n */\n current(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return applyTrailingSlash(parsed.pathname, this.trailingSlash)\n }\n\n /**\n * Get the current request URL with query string (pathname + search).\n */\n full(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash)\n }\n\n /**\n * Get the previous request URL from the Referer header.\n *\n * @param fallback - URL to return if no Referer header (default: '/')\n */\n previous(fallback = '/'): string {\n return this.routerContext.c.req.header('referer') ?? fallback\n }\n\n /**\n * Get the previous request URL pathname (no query string or host) from the Referer header.\n *\n * @param fallback - Path to return if no Referer header (default: '/')\n */\n previousPath(fallback = '/'): string {\n const referer = this.routerContext.c.req.header('referer')\n if (!referer) return fallback\n\n try {\n const parsed = new URL(referer)\n return parsed.pathname\n } catch {\n return referer\n }\n }\n\n /**\n * Build a URL to a raw path (not a named route) with optional query params.\n *\n * @param path - URL path (e.g., '/users')\n * @param queryParams - Query parameters to append\n * @param options - URL generation options\n */\n to(path: string, queryParams?: Record<string, string>, options?: UriOptions): string {\n let url = applyTrailingSlash(path, this.trailingSlash)\n\n if (queryParams) {\n const entries = Object.entries(queryParams)\n if (entries.length > 0) {\n const queryString = entries\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`\n }\n }\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Build a URL with query string parameters. Merges with existing query params in path.\n *\n * @param path - URL path, may already contain query params\n * @param queryParams - Query parameters to merge (new values override existing)\n */\n query(path: string, queryParams: Record<string, string>): string {\n const parsed = new URL(path, 'https://placeholder.local')\n for (const [key, value] of Object.entries(queryParams)) {\n parsed.searchParams.set(key, value)\n }\n return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash)\n }\n\n private getAppSecret(): string {\n const secret = this.routerContext.c.env.APP_SECRET\n if (!secret) {\n throw new Error('APP_SECRET environment variable is required for signed URLs')\n }\n return secret\n }\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":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"seeder-BADTig4n.mjs","names":[],"sources":["../src/seeder/seeder.error.ts","../src/seeder/seeder-registry.ts","../src/seeder/commands/db-seed-list.command.ts","../src/seeder/commands/db-seed.command.ts"],"sourcesContent":["import { ApplicationError } from '../errors'\n\nexport class SeederError extends ApplicationError {}\n","import type { Application } from '../application'\nimport type { Container } from '../di/container'\nimport type { Constructor } from '../types'\nimport { SeederError } from './seeder.error'\nimport { type Seeder, SEEDER_INTERNALS } from './seeder'\n\nexport const SEEDER_TOKENS = {\n SeederRegistry: Symbol.for('stratal:seeders:registry'),\n} as const\n\nexport class SeederRegistry {\n private seeders = new Set<Constructor<Seeder>>()\n private nameIndex = new Map<string, Constructor<Seeder>>()\n\n constructor(private app: Application) { }\n\n register(SeederClass: Constructor<Seeder>): void {\n const existing = this.nameIndex.get(SeederClass.name)\n if (existing && existing !== SeederClass) {\n throw new SeederError(`Seeder name collision: \"${SeederClass.name}\" is already registered`)\n }\n this.seeders.add(SeederClass)\n this.nameIndex.set(SeederClass.name, SeederClass)\n }\n\n async run(SeederClass: Constructor<Seeder>, options?: { container?: Container }): Promise<void> {\n if (!this.seeders.has(SeederClass)) {\n throw new SeederError(`Seeder \"${SeederClass.name}\" is not registered`)\n }\n\n const execute = async (container: Container) => {\n const seeder = container.resolve<Seeder>(SeederClass)\n seeder[SEEDER_INTERNALS] = {\n run: (cls) => this.run(cls, { container }),\n container,\n }\n await seeder.run()\n }\n\n if (options?.container) {\n await execute(options.container)\n } else {\n const mockContext = this.app.createMockRouterContext('en')\n await this.app.container.runInRequestScope(mockContext, execute)\n }\n }\n\n async runAll(options?: { container?: Container }): Promise<void> {\n for (const SeederClass of this.seeders) {\n await this.run(SeederClass, options)\n }\n }\n\n find(name: string): Constructor<Seeder> | undefined {\n return this.nameIndex.get(name)\n }\n\n has(SeederClass: Constructor<Seeder>): boolean {\n return this.seeders.has(SeederClass)\n }\n\n list(): { className: string }[] {\n return [...this.seeders].map(cls => ({ className: cls.name }))\n }\n}\n","import { inject } from '../../di'\nimport { Command } from '../../quarry/command'\nimport { type SeederRegistry, SEEDER_TOKENS } from '../seeder-registry'\n\nexport class DbSeedListCommand extends Command {\n static command = 'db:seed:list'\n static description = 'List available database seeders'\n\n constructor(@inject(SEEDER_TOKENS.SeederRegistry) private seeders: SeederRegistry) {\n super()\n }\n\n handle(): undefined | number {\n const list = this.seeders.list()\n if (list.length === 0) {\n this.info('No seeders found')\n return 0\n }\n this.table(['Class'], list.map(s => [s.className]))\n\n return undefined\n }\n}\n","import { inject } from '../../di'\nimport { Command } from '../../quarry/command'\nimport { type SeederRegistry, SEEDER_TOKENS } from '../seeder-registry'\n\nexport class DbSeedCommand extends Command {\n static command = 'db:seed {names* : Seeder class names} {--a|all : Run all seeders} {--dry-run : Preview without executing}'\n static description = 'Run database seeders'\n\n constructor(@inject(SEEDER_TOKENS.SeederRegistry) private seeders: SeederRegistry) {\n super()\n }\n\n async handle(): Promise<number | undefined> {\n const names = this.array('names')\n const all = this.boolean('all')\n const dryRun = this.boolean('dry-run')\n\n if (names.length > 0 && all) {\n this.warn(`Ignoring \"${names.join(', ')}\" because --all takes precedence`)\n }\n\n if (names.length === 0 && !all) {\n this.fail('Specify one or more seeder class names or use --all')\n return 1\n }\n\n if (dryRun) {\n if (all) {\n const list = this.seeders.list()\n this.info('Dry run — would execute:')\n for (const s of list) {\n this.info(` ${s.className}`)\n }\n } else {\n this.info('Dry run — would execute:')\n for (const name of names) {\n const SeederClass = this.seeders.find(name)\n if (!SeederClass) {\n this.fail(`Seeder \"${name}\" not found`)\n return 1\n }\n this.info(` ${SeederClass.name}`)\n }\n }\n return 0\n }\n\n if (all) {\n await this.seeders.runAll()\n this.success('All seeders completed')\n } else {\n for (const name of names) {\n const SeederClass = this.seeders.find(name)\n if (!SeederClass) {\n this.fail(`Seeder \"${name}\" not found`)\n return 1\n }\n await this.seeders.run(SeederClass)\n this.success(`Seeder \"${name}\" completed`)\n }\n }\n\n return 0\n }\n}\n"],"mappings":"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"}
@@ -1,76 +0,0 @@
1
- import { EmailError } from "./email/index.mjs";
2
- import { t as BaseEmailProvider } from "./base-email.provider-BWZHIjt8.mjs";
3
- import * as nodemailer from "nodemailer";
4
- import { Readable } from "stream";
5
- //#region src/email/providers/smtp.provider.ts
6
- /**
7
- * SMTP Email Provider
8
- *
9
- * Implementation of IEmailProvider using SMTP/nodemailer
10
- * Supports any SMTP server configured via SMTP_URL
11
- */
12
- var SmtpProvider = class extends BaseEmailProvider {
13
- options;
14
- transporter;
15
- defaultFrom;
16
- constructor(options) {
17
- super();
18
- this.options = options;
19
- if (!this.options.smtp) throw new EmailError("SMTP configuration is missing");
20
- if (!this.options.smtp.host) throw new EmailError("SMTP host is required");
21
- this.transporter = nodemailer.createTransport({
22
- host: this.options.smtp.host,
23
- port: this.options.smtp.port,
24
- secure: this.options.smtp.secure,
25
- auth: this.options.smtp.username && this.options.smtp.password ? {
26
- user: this.options.smtp.username,
27
- pass: this.options.smtp.password
28
- } : void 0
29
- });
30
- this.defaultFrom = this.options.from;
31
- }
32
- async send(message) {
33
- try {
34
- const from = message.from ? `${message.from.name} <${message.from.email}>` : `${this.defaultFrom.name} <${this.defaultFrom.email}>`;
35
- const info = await this.transporter.sendMail({
36
- from,
37
- to: Array.isArray(message.to) ? message.to.join(", ") : message.to,
38
- subject: message.subject,
39
- html: message.html,
40
- text: message.text,
41
- replyTo: message.replyTo,
42
- cc: message.cc?.join(", "),
43
- bcc: message.bcc?.join(", "),
44
- attachments: message.attachments?.map((attachment) => ({
45
- filename: attachment.filename,
46
- content: this.toNodeStream(attachment.content),
47
- contentType: attachment.contentType
48
- }))
49
- });
50
- return {
51
- messageId: info.messageId,
52
- accepted: true,
53
- metadata: {
54
- provider: "smtp",
55
- response: info.response
56
- }
57
- };
58
- } catch {
59
- throw new EmailError(`SMTP connection failed to ${this.options.smtp?.host ?? ""}:${this.options.smtp?.port ?? 587}`);
60
- }
61
- }
62
- /**
63
- * Convert attachment content to Node.js stream format
64
- *
65
- * Nodemailer expects Node.js Readable streams, not web ReadableStream.
66
- * Buffer is passed through as-is since nodemailer supports it directly.
67
- */
68
- toNodeStream(content) {
69
- if (Buffer.isBuffer(content)) return content;
70
- return Readable.fromWeb(content);
71
- }
72
- };
73
- //#endregion
74
- export { SmtpProvider };
75
-
76
- //# sourceMappingURL=smtp.provider-C129sNBT.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"smtp.provider-C129sNBT.mjs","names":[],"sources":["../src/email/providers/smtp.provider.ts"],"sourcesContent":["import type { Transporter } from 'nodemailer'\nimport * as nodemailer from 'nodemailer'\nimport type SMTPTransport from 'nodemailer/lib/smtp-transport'\nimport { Readable } from 'stream'\nimport type { ResolvedEmailAttachment, ResolvedEmailMessage } from '../contracts'\nimport type { EmailModuleOptions } from '../email.module'\nimport { EmailError } from '../email.error'\nimport { BaseEmailProvider } from './base-email.provider'\nimport type { EmailSendResult } from './email-provider.interface'\n\n/**\n * SMTP Email Provider\n *\n * Implementation of IEmailProvider using SMTP/nodemailer\n * Supports any SMTP server configured via SMTP_URL\n */\nexport class SmtpProvider extends BaseEmailProvider {\n private readonly transporter: Transporter<SMTPTransport.SentMessageInfo>\n private readonly defaultFrom: { name: string; email: string }\n\n constructor(\n private readonly options: EmailModuleOptions\n ) {\n super()\n\n // Validate SMTP configuration\n if (!this.options.smtp) {\n throw new EmailError('SMTP configuration is missing')\n }\n\n if (!this.options.smtp.host) {\n throw new EmailError('SMTP host is required')\n }\n\n // Create nodemailer transporter\n this.transporter = nodemailer.createTransport({\n host: this.options.smtp.host,\n port: this.options.smtp.port,\n secure: this.options.smtp.secure,\n auth: this.options.smtp.username && this.options.smtp.password\n ? {\n user: this.options.smtp.username,\n pass: this.options.smtp.password,\n }\n : undefined,\n })\n\n this.defaultFrom = this.options.from\n }\n\n async send(message: ResolvedEmailMessage): Promise<EmailSendResult> {\n try {\n const from = message.from\n ? `${message.from.name} <${message.from.email}>`\n : `${this.defaultFrom.name} <${this.defaultFrom.email}>`\n\n const info = await this.transporter.sendMail({\n from,\n to: Array.isArray(message.to) ? message.to.join(', ') : message.to,\n subject: message.subject,\n html: message.html,\n text: message.text,\n replyTo: message.replyTo,\n cc: message.cc?.join(', '),\n bcc: message.bcc?.join(', '),\n attachments: message.attachments?.map(attachment => ({\n filename: attachment.filename,\n content: this.toNodeStream(attachment.content),\n contentType: attachment.contentType,\n })),\n })\n\n return {\n messageId: info.messageId,\n accepted: true,\n metadata: {\n provider: 'smtp',\n response: info.response,\n },\n }\n } catch {\n throw new EmailError(`SMTP connection failed to ${this.options.smtp?.host ?? ''}:${this.options.smtp?.port ?? 587}`)\n }\n }\n\n /**\n * Convert attachment content to Node.js stream format\n *\n * Nodemailer expects Node.js Readable streams, not web ReadableStream.\n * Buffer is passed through as-is since nodemailer supports it directly.\n */\n private toNodeStream(content: ResolvedEmailAttachment['content']): Buffer | Readable {\n if (Buffer.isBuffer(content)) {\n return content\n }\n // Convert web ReadableStream to Node.js Readable\n return Readable.fromWeb(content as unknown as Parameters<typeof Readable.fromWeb>[0])\n }\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAa,eAAb,cAAkC,kBAAkB;CAK/B;CAJnB;CACA;CAEA,YACE,SACA;EACA,OAAO;EAFU,KAAA,UAAA;EAKjB,IAAI,CAAC,KAAK,QAAQ,MAChB,MAAM,IAAI,WAAW,gCAAgC;EAGvD,IAAI,CAAC,KAAK,QAAQ,KAAK,MACrB,MAAM,IAAI,WAAW,wBAAwB;EAI/C,KAAK,cAAc,WAAW,gBAAgB;GAC5C,MAAM,KAAK,QAAQ,KAAK;GACxB,MAAM,KAAK,QAAQ,KAAK;GACxB,QAAQ,KAAK,QAAQ,KAAK;GAC1B,MAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,QAAQ,KAAK,WAClD;IACA,MAAM,KAAK,QAAQ,KAAK;IACxB,MAAM,KAAK,QAAQ,KAAK;IACzB,GACC,KAAA;GACL,CAAC;EAEF,KAAK,cAAc,KAAK,QAAQ;;CAGlC,MAAM,KAAK,SAAyD;EAClE,IAAI;GACF,MAAM,OAAO,QAAQ,OACjB,GAAG,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,KAC5C,GAAG,KAAK,YAAY,KAAK,IAAI,KAAK,YAAY,MAAM;GAExD,MAAM,OAAO,MAAM,KAAK,YAAY,SAAS;IAC3C;IACA,IAAI,MAAM,QAAQ,QAAQ,GAAG,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,QAAQ;IAChE,SAAS,QAAQ;IACjB,MAAM,QAAQ;IACd,MAAM,QAAQ;IACd,SAAS,QAAQ;IACjB,IAAI,QAAQ,IAAI,KAAK,KAAK;IAC1B,KAAK,QAAQ,KAAK,KAAK,KAAK;IAC5B,aAAa,QAAQ,aAAa,KAAI,gBAAe;KACnD,UAAU,WAAW;KACrB,SAAS,KAAK,aAAa,WAAW,QAAQ;KAC9C,aAAa,WAAW;KACzB,EAAE;IACJ,CAAC;GAEF,OAAO;IACL,WAAW,KAAK;IAChB,UAAU;IACV,UAAU;KACR,UAAU;KACV,UAAU,KAAK;KAChB;IACF;UACK;GACN,MAAM,IAAI,WAAW,6BAA6B,KAAK,QAAQ,MAAM,QAAQ,GAAG,GAAG,KAAK,QAAQ,MAAM,QAAQ,MAAM;;;;;;;;;CAUxH,aAAqB,SAAgE;EACnF,IAAI,OAAO,SAAS,QAAQ,EAC1B,OAAO;EAGT,OAAO,SAAS,QAAQ,QAA6D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-provider.interface-DQMtT42e.d.mts","names":[],"sources":["../src/storage/types.ts","../src/storage/contracts/delete-file.input.ts","../src/storage/contracts/download-result.ts","../src/storage/contracts/file-exists.input.ts","../src/storage/contracts/get-presigned-url.input.ts","../src/storage/contracts/upload-file.input.ts","../src/storage/providers/storage-provider.interface.ts"],"mappings":";;;;;;UAIiB,YAAA;EAChB,IAAA;;EAEA,OAAA;EACA,IAAA;AAAA;;;;UAMgB,kBAAA;EAChB,aAAA;EACA,SAAA;AAAA;;AAMD;;UAAiB,kBAAA;EAEhB;EAAA,QAAA;EAQgB;EANhB,QAAA;AAAA;;;;UAMgB,aAAA;EAChB,OAAA,EAAS,YAAA;EACT,kBAAA;EACA,YAAA,EAAc,kBAAA;EADd;EAGA,KAAA,GAAQ,kBAAA;AAAA;;;cCnCI,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;KAKtB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;;;;;;;ADH7C;;UEEiB,cAAA;EFFY;;;EEM3B,QAAA,gBAAwB,cAAA,CAAe,UAAA;EAEvC,QAAA,gBAAwB,OAAA;EAExB,aAAA,gBAA6B,OAAA,CAAQ,UAAA;EFAtB;;;EEKf,WAAA;EFHQ;AAMV;;EEEE,IAAA;EFAD;;AAQD;;EEFE,QAAA,GAAW,MAAA;AAAA;;;cC5BA,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;KAKtB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;;;cCLhC,0BAAA,EAA0B,CAAA,CAAA,SAAA;;;;;;;;;;;KAO3B,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,0BAAA;AAAA,cAErC,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;KAOzB,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;;;;;;UCb/B,aAAA;ELDY;;;EKK3B,IAAA;ELFD;;;EKMC,QAAA;ELCe;;;;EKIf,QAAA,GAAW,MAAA;ELII;;;;EKCf,OAAA;AAAA;AAAA,cAGW,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;KASnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;;;;;;AL/B1C;KMEY,8BAAA,GACR,cAAA,GACA,WAAA,GACA,eAAA,YAEA,IAAA;;;;;UAOa,gBAAA;ENVZ;;AAML;;;;;EMYE,MAAA,CAAO,IAAA,EAAM,8BAAA,EAAgC,IAAA,UAAc,OAAA,EAAS,aAAA,GAAgB,OAAA,CAAQ,YAAA;ENJ3D;;;;AAUnC;EMCE,QAAA,CAAS,IAAA,WAAe,OAAA,CAAQ,cAAA;;;;;EAMhC,MAAA,CAAO,IAAA,WAAe,OAAA;ENFG;;;;;EMSzB,MAAA,CAAO,IAAA,WAAe,OAAA;ENTvB;;;;;;;EMkBC,eAAA,CACE,IAAA,UACA,MAAA,qCACA,SAAA,WACC,OAAA,CAAQ,kBAAA;ELtDX;;;;;;;;EKgEA,aAAA,CACE,IAAA,EAAM,8BAAA,EACN,IAAA,UACA,OAAA,EAAS,IAAA,CAAK,aAAA;IAA2B,IAAA;EAAA,IACxC,OAAA,CAAQ,YAAA;AAAA"}
@@ -1,8 +0,0 @@
1
- import { a as ApplicationError } from "./container-storage-GpNNz79X.mjs";
2
- import "./errors-BBZTnjdq.mjs";
3
- //#region src/storage/storage.error.ts
4
- var StorageError = class extends ApplicationError {};
5
- //#endregion
6
- export { StorageError as t };
7
-
8
- //# sourceMappingURL=storage.error-C6FY037a.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stratal-Bdq4IdB3.mjs","names":["internal.getGroups","internal.getDefaultEntry","internal.getGlobalMiddleware"],"sources":["../src/router/router-resolver.ts","../src/application.ts","../src/stratal.ts"],"sourcesContent":["import 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 parent.extend(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","import { CacheModule } from './cache'\nimport type { CronJob } from './cron/cron-job'\nimport { CronManager } from './cron/cron-manager'\nimport { Container } from './di/container'\nimport { runWithContainer } from './di/container-storage'\nimport { DI_TOKENS } from './di/tokens'\nimport { type StratalEnv } from './env'\nimport { DefaultExceptionHandler } from './errors/default-exception-handler'\nimport { createCliExceptionContext, createCronExceptionContext, createQueueExceptionContext } from './errors/exception-context'\nimport type { ExceptionHandler } from './errors/exception-handler'\nimport type { EventHandler } from './events'\nimport { EventRegistry, getListenerHandlers } from './events'\nimport type { StratalExecutionContext } from './execution-context'\nimport { I18nModule } from './i18n/i18n.module'\nimport { JsonFormatter, LOGGER_TOKENS, LoggerService, LogLevel, PrettyFormatter } from './logger'\nimport { ModuleRegistry } from './module/module-registry'\nimport type { DynamicModule, ModuleClass } from './module/types'\nimport { OpenAPIModule } from './openapi'\nimport type { Command } from './quarry/command'\nimport { QuarryRegistry } from './quarry/quarry-registry'\nimport type { CommandInput, CommandResult } from './quarry/types'\nimport { type ConsumerRegistry } from './queue/consumer-registry'\nimport type { IQueueConsumer, QueueMessage } from './queue/queue-consumer'\nimport { type QueueManager } from './queue/queue-manager'\nimport { QueueModule } from './queue/queue.module'\nimport { type RouterContext } from './router'\nimport { HonoApp } from './router/hono-app'\nimport { RouteRegistry } from './router/route-registry'\nimport { RouterResolver } from './router/router-resolver'\nimport { ROUTER_TOKENS } from './router/router.tokens'\nimport { LocalePathService } from './router/services/locale-path.service'\nimport { RouteRegistrationService } from './router/services/route-registration.service'\nimport { VersioningService } from './router/services/versioning.service'\nimport type { TrailingSlashMode, VersioningOptions } from './router/types'\nimport { Uri } from './router/uri'\nimport { SEEDER_TOKENS, SeederRegistry, type Seeder } from './seeder'\nimport type { Constructor } from './types'\n\nexport interface ApplicationConfig {\n module: ModuleClass | DynamicModule\n logging?: {\n level?: LogLevel\n formatter?: 'json' | 'pretty'\n }\n versioning?: VersioningOptions\n trailingSlash?: TrailingSlashMode\n exceptionHandler?: Constructor<ExceptionHandler>\n}\n\nexport interface ApplicationOptions extends ApplicationConfig {\n env: StratalEnv\n ctx: StratalExecutionContext\n}\n\nexport class Application {\n private _container: Container\n private honoApp!: HonoApp\n private moduleRegistry: ModuleRegistry\n private consumerRegistry!: ConsumerRegistry\n private cronManager!: CronManager\n private quarry!: QuarryRegistry\n private initialized = false\n private routingInitPromise: Promise<void> | null = null\n private handlerInitPromise: Promise<void> | null = null\n\n readonly env: StratalEnv\n private readonly appConfig: ApplicationConfig\n\n constructor({ env, ctx, ...config }: ApplicationOptions) {\n this.env = env\n this.appConfig = config\n\n this._container = new Container()\n\n this._container.registerValue(DI_TOKENS.Application, this)\n this._container.registerValue(DI_TOKENS.CloudflareEnv, env)\n this._container.registerValue(DI_TOKENS.ExecutionContext, ctx)\n this._container.registerValue(ROUTER_TOKENS.RouterContext, null)\n\n this.registerLoggerService()\n this.registerCoreServices()\n\n const logger = this._container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n this.moduleRegistry = new ModuleRegistry(this._container, logger)\n\n this._container.registerValue(DI_TOKENS.ModuleRegistry, this.moduleRegistry)\n }\n\n get container(): Container {\n return this._container\n }\n\n async ensureHono(): Promise<HonoApp> {\n await this.initializeRouting()\n return this.honoApp\n }\n\n get config(): ApplicationConfig {\n return this.appConfig\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return\n }\n\n await runWithContainer(this._container, () => this.initializeInternal())\n }\n\n private async initializeInternal(): Promise<void> {\n // Phase 1: Register core infrastructure modules\n this.moduleRegistry.registerAll([\n I18nModule,\n QueueModule,\n CacheModule,\n ])\n\n // Phase 2: Register user's root module (traverses imports)\n this.moduleRegistry.register(this.appConfig.module)\n\n // Phase 3: Initialize all modules (only those with lifecycle hooks)\n await this.moduleRegistry.initialize()\n\n // Phase 3.5: Initialize ExceptionHandler\n this.initializeExceptionHandler()\n\n // Phase 4: Resolve lightweight managers (CronManager only — others deferred)\n this.cronManager = this._container.resolve<CronManager>(DI_TOKENS.Cron)\n\n // Phase 5: Register cron jobs (static schedule, no resolve), seeders, commands\n this.registerCronJobs()\n this.registerSeeders()\n this.registerCommands()\n\n this.initialized = true\n }\n\n private registerRoutingServices(): void {\n this._container.register(ROUTER_TOKENS.VersioningService, VersioningService)\n this._container.register(ROUTER_TOKENS.HonoApp, HonoApp)\n this._container.register(ROUTER_TOKENS.LocalePathService, LocalePathService)\n this._container.register(ROUTER_TOKENS.RouteRegistry, RouteRegistry)\n this._container.register(ROUTER_TOKENS.Uri, Uri)\n\n const routerConfigs = this.moduleRegistry.getAllRouterConfigs()\n if (routerConfigs.length > 0) {\n this._container.registerValue(ROUTER_TOKENS.RouterResolver, new RouterResolver(routerConfigs))\n }\n\n this._container.register(RouteRegistrationService, RouteRegistrationService)\n }\n\n async initializeHandlers(): Promise<void> {\n this.handlerInitPromise ??= runWithContainer(this._container, () => {\n // Resolve ConsumerRegistry lazily (deferred from Phase 4)\n this.consumerRegistry = this._container.resolve<ConsumerRegistry>(DI_TOKENS.ConsumerRegistry)\n this.registerQueueConsumers()\n this.registerEventListeners()\n return Promise.resolve()\n })\n return this.handlerInitPromise\n }\n\n private initializeRouting(): Promise<void> {\n this.routingInitPromise ??= runWithContainer(this._container, async () => {\n await this.initializeHandlers()\n this.moduleRegistry.register(OpenAPIModule as unknown as ModuleClass)\n this.registerRoutingServices()\n this.honoApp = this._container.resolve<HonoApp>(ROUTER_TOKENS.HonoApp)\n await this.honoApp.configure()\n })\n return this.routingInitPromise\n }\n\n resolve<T>(token: symbol): T {\n try {\n return this._container.resolve(token)\n } catch (error) {\n const handler = this._container.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createCliExceptionContext('resolve')\n void handler.handle(error, ctx)\n throw error\n }\n }\n\n async handleQueue(batch: MessageBatch, queueName: string): Promise<void> {\n await this.initializeHandlers()\n\n const firstMessage = batch.messages[0]?.body as QueueMessage | undefined\n const locale = firstMessage?.metadata?.locale ?? 'en'\n const mockRouterContext = this.createMockRouterContext(locale)\n\n await this._container.runInRequestScope(mockRouterContext, async (requestContainer) => {\n try {\n const queueManager = requestContainer.resolve<QueueManager>(DI_TOKENS.Queue)\n await queueManager.processBatch(queueName, batch)\n } catch (error) {\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n await handler.handle(error, createQueueExceptionContext(queueName))\n throw error\n }\n })\n }\n\n async handleScheduled(controller: ScheduledController): Promise<void> {\n await this.initializeHandlers()\n\n const mockRouterContext = this.createMockRouterContext('en')\n\n await this._container.runInRequestScope(mockRouterContext, async (requestContainer) => {\n try {\n await this.cronManager.executeScheduled(controller, requestContainer)\n } catch (error) {\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n await handler.handle(error, createCronExceptionContext())\n throw error\n }\n })\n }\n\n createMockRouterContext(locale = 'en'): RouterContext {\n return {\n getLocale: () => locale,\n setLocale: () => { /* no-op */ },\n getContainer: () => this._container,\n } as unknown as RouterContext\n }\n\n async shutdown(): Promise<void> {\n if (!this.initialized) return\n this.initialized = false\n\n await this.moduleRegistry.shutdown()\n\n const logger = this._container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n logger.info('Disposing container...')\n\n this._container.dispose()\n }\n\n async handleCommand(name: string, input?: CommandInput): Promise<CommandResult> {\n await this.initializeRouting()\n // Resolve QuarryRegistry lazily (deferred from Phase 4)\n this.quarry ??= this._container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n const mockContext = this.createMockRouterContext('en')\n return this._container.runInRequestScope(mockContext, async () => {\n return this.quarry.call(name, input)\n })\n }\n\n private registerCommands(): void {\n this.quarry ??= this._container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n const commands = this.moduleRegistry.getAllCommands()\n for (const CommandClass of commands) {\n this.quarry.register(CommandClass as Constructor<Command>)\n }\n }\n\n private registerSeeders(): void {\n const seeders = this.moduleRegistry.getAllSeeders()\n if (seeders.length === 0) return\n const registry = this._container.resolve<SeederRegistry>(SEEDER_TOKENS.SeederRegistry)\n for (const SeederClass of seeders) {\n registry.register(SeederClass as Constructor<Seeder>)\n }\n }\n\n private registerQueueConsumers(): void {\n for (const ConsumerClass of this.moduleRegistry.getAllConsumers()) {\n const consumer = this._container.resolve(ConsumerClass) as IQueueConsumer\n this.consumerRegistry.register(consumer)\n }\n }\n\n private registerCronJobs(): void {\n for (const JobClass of this.moduleRegistry.getAllJobs()) {\n const schedule = (JobClass as unknown as { schedule: string }).schedule\n if (schedule) {\n this.cronManager.registerJob(schedule, JobClass as Constructor<CronJob>)\n }\n }\n }\n\n private registerEventListeners(): void {\n const listeners = this.moduleRegistry.getAllListeners()\n if (listeners.length === 0) {\n return\n }\n\n const eventRegistry = this._container.resolve<EventRegistry>(DI_TOKENS.EventRegistry)\n\n for (const ListenerClass of listeners) {\n const instance = this._container.resolve(ListenerClass) as Record<string, ((...args: unknown[]) => unknown)>\n const handlers = getListenerHandlers(ListenerClass)\n\n for (const { methodName, event, options } of handlers) {\n eventRegistry.on(event, instance[methodName].bind(instance) as EventHandler, options)\n }\n }\n }\n\n private registerLoggerService(): void {\n const logLevel = this.appConfig.logging?.level ?? LogLevel.INFO\n const formatter = this.appConfig.logging?.formatter ?? 'json'\n\n this._container.registerValue(LOGGER_TOKENS.LogLevelOptions, logLevel)\n\n this._container\n .when(() => formatter === 'pretty')\n .use(LOGGER_TOKENS.Formatter)\n .give(PrettyFormatter)\n .otherwise(JsonFormatter)\n\n this._container.registerSingleton(LOGGER_TOKENS.LoggerService, LoggerService)\n }\n\n private registerCoreServices(): void {\n this._container.registerSingleton(DI_TOKENS.Cron, CronManager)\n this._container.registerSingleton(\n DI_TOKENS.ExceptionHandler,\n (this.appConfig.exceptionHandler ?? DefaultExceptionHandler) as Constructor,\n )\n this._container.registerSingleton(DI_TOKENS.EventRegistry, EventRegistry)\n this._container.registerSingleton(DI_TOKENS.Quarry, QuarryRegistry)\n this._container.registerValue(SEEDER_TOKENS.SeederRegistry, new SeederRegistry(this))\n }\n\n private initializeExceptionHandler(): void {\n const handler = this._container.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n handler.register()\n this.moduleRegistry.configureExceptionHandlers(handler)\n }\n}\n","import { Application, type ApplicationConfig } from './application'\nimport type { StratalEnv } from './env'\nimport { StratalNotInitializedError } from './errors'\nimport type { HonoApp } from './router/hono-app'\n\n/**\n * Stratal — Hono-style entry point for Cloudflare Workers.\n *\n * Eagerly bootstraps the Application at construction time, dynamically\n * importing `cloudflare:workers` for env and waitUntil.\n *\n * @example\n * ```typescript\n * import { Stratal } from 'stratal'\n * import { AppModule } from './app.module'\n *\n * export default new Stratal({ module: AppModule })\n * ```\n */\nexport class Stratal<Env extends StratalEnv = StratalEnv> {\n private app: Application | null = null\n private initPromise: Promise<Application>\n\n private static _application: Promise<Application> | null = null\n private static _generation = 0\n private static _previousInstance: Stratal | null = null\n\n constructor(config: ApplicationConfig) {\n this.fetch = this.fetch.bind(this)\n this.queue = this.queue.bind(this)\n this.scheduled = this.scheduled.bind(this)\n\n // Invalidate any in-flight initialization from a previous instance (Vite HMR reload)\n const generation = ++Stratal._generation\n\n if (Stratal._previousInstance) {\n void Stratal._previousInstance.shutdown()\n }\n Stratal._previousInstance = this\n\n this.initPromise = this.prepareApp(config, generation)\n Stratal._application = this.initPromise\n }\n\n async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {\n const app = await this.ensureReady()\n const hono = await app.ensureHono()\n return hono.fetch(request, env, ctx)\n }\n\n async queue(batch: MessageBatch): Promise<void> {\n const app = await this.ensureReady()\n return app.handleQueue(batch, batch.queue)\n }\n\n async scheduled(controller: ScheduledController): Promise<void> {\n const app = await this.ensureReady()\n return app.handleScheduled(controller)\n }\n\n get hono(): Promise<HonoApp> {\n return this.initPromise.then(app => app.ensureHono())\n }\n\n async shutdown(): Promise<void> {\n try { this.app = await this.initPromise } catch { /* ignore */ }\n if (this.app) {\n await this.app.shutdown()\n this.app = null\n }\n }\n\n /**\n * @internal\n * Resolves the Application instance from the static singleton.\n * Used by worker base classes (DurableObject, Workflow, WorkerEntrypoint)\n * to access the DI container without going through Cloudflare RPC.\n */\n static resolveApplication(): Promise<Application> {\n if (!Stratal._application) {\n throw new StratalNotInitializedError()\n }\n return Stratal._application\n }\n\n private async ensureReady(): Promise<Application> {\n this.app ??= await this.initPromise;\n return this.app\n }\n\n private async prepareApp(config: ApplicationConfig, generation: number): Promise<Application> {\n const { env, waitUntil } = await import('cloudflare:workers')\n\n // After async import, check if a newer instance has replaced us (Vite HMR reload)\n if (generation !== Stratal._generation) {\n return new Promise<Application>(() => {\n //\n }) // Never resolves — avoids cross-request promise warning\n }\n\n const app = new Application({ ...config, env: env as Env, ctx: { waitUntil } })\n await app.initialize()\n\n // Check again after initialization completes\n if (generation !== Stratal._generation) {\n await app.shutdown()\n return new Promise<Application>(() => {\n //\n })\n }\n\n return app\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-BaeHi67f.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;AAeA;;;;;;;;;;;;;KAAY,WAAA,uBAAkC,IAAA,YAAgB,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"usage-generator-DTqaUMR9.mjs","names":[],"sources":["../src/quarry/usage-generator.ts"],"sourcesContent":["import { bold, cyan, dim, dimWhite, yellow } from './colors'\nimport type { ParsedSignature } from './types'\n\n/**\n * Generate formatted help/usage text from a parsed signature.\n *\n * Pure function, edge-compatible.\n */\nexport function generateUsage(signature: ParsedSignature, description?: string): string {\n const lines: string[] = []\n\n // Usage line\n lines.push(`${bold('Usage:')} ${bold(cyan('quarry ' + buildUsageLine(signature)))}`)\n\n // Description\n if (description) {\n lines.push('')\n lines.push(description)\n }\n\n // Arguments section\n if (signature.arguments.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Arguments:')))\n const argRows = signature.arguments.map((arg) => {\n const label = arg.name\n const parts: string[] = []\n\n if (arg.description) parts.push(arg.description)\n\n if (arg.isArray) {\n parts.push('(variadic)')\n } else if (arg.required) {\n parts.push('(required)')\n } else if (arg.default !== undefined) {\n parts.push(dim(`(default: ${arg.default})`))\n } else {\n parts.push('(optional)')\n }\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(argRows))\n }\n\n // Options section\n if (signature.options.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Options:')))\n const optRows = signature.options.map((opt) => {\n const flagParts: string[] = []\n if (opt.alias) flagParts.push(`-${opt.alias},`)\n flagParts.push(`--${opt.name}`)\n\n const label = flagParts.join(' ')\n const parts: string[] = []\n\n if (opt.description) parts.push(opt.description)\n if (!opt.isFlag && !opt.description) parts.push('Accepts a value')\n if (opt.isFlag && !opt.description) parts.push('Boolean flag')\n if (opt.isArray) parts.push('(multiple)')\n if (opt.default !== undefined) parts.push(dim(`(default: ${opt.default})`))\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(optRows))\n }\n\n return lines.join('\\n')\n}\n\nexport interface ListingOptions {\n binaryName?: string\n binaryLabel?: string\n binaryVersion?: string\n}\n\n/**\n * Generate a compact command listing with visual hierarchy.\n */\nexport function generateListing(\n commands: { name: string; description?: string; aliases: string[] }[],\n signatures: Map<string, ParsedSignature>,\n options?: ListingOptions,\n): string {\n const bin = options?.binaryName ?? 'quarry'\n const label = options?.binaryLabel ?? 'Quarry CLI'\n const version = options?.binaryVersion\n\n const lines: string[] = []\n\n // Header\n lines.push(bold(`${label}${version ? ` v${version}` : ''}`))\n lines.push('')\n\n // Usage\n lines.push(bold(yellow('Usage')))\n lines.push(` $ ${bin} [--env <name>] <command> [options]`)\n lines.push('')\n\n // Global Options\n lines.push(bold(yellow('Global Options')))\n lines.push(...formatTable([\n [`-e, --env ${cyan('<name>')}`, `Select a ${dim('wrangler.jsonc')} environment (e.g. staging, production)`],\n ]))\n lines.push('')\n\n // Commands\n if (commands.length === 0) {\n lines.push('No registered commands.')\n return lines.join('\\n')\n }\n\n lines.push(bold(yellow('Commands')))\n\n const termWidth = typeof process !== 'undefined'\n ? (process.stdout.columns as number | undefined) ?? 80\n : 80\n\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i]\n const sig = signatures.get(cmd.name)\n const sigParts: string[] = [cyan(cmd.name)]\n\n if (cmd.aliases.length > 0) {\n sigParts.push(cyan(`(alias: ${cmd.aliases.join(', ')})`))\n }\n\n if (sig) {\n const inlineParts: string[] = []\n for (const arg of sig.arguments) {\n inlineParts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of sig.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n inlineParts.push(`[${flagStr}]`)\n }\n\n if (inlineParts.length > 0) {\n sigParts.push(dim(inlineParts.join(' ')))\n }\n }\n\n const sigLine = ' ' + sigParts.join(' ')\n lines.push(...wrapLine(sigLine, termWidth, ' '))\n\n if (cmd.description) {\n lines.push(` ${dimWhite(cmd.description)}`)\n }\n\n if (i < commands.length - 1) {\n lines.push('')\n }\n }\n\n lines.push('')\n\n // Footer\n lines.push(dimWhite(`Run ${bin} help <command> for detailed information.`))\n\n return lines.join('\\n')\n}\n\n/** Format a single argument into its placeholder representation (e.g. `<name>`, `[name=default]`). */\nfunction formatArgPlaceholder(arg: ParsedSignature['arguments'][number]): string {\n if (arg.isArray) return `<${arg.name}...>`\n if (arg.required) return `<${arg.name}>`\n if (arg.default !== undefined) return `[${arg.name}=${arg.default}]`\n return `[${arg.name}]`\n}\n\n/** Build the inline usage line showing the command name with argument and option placeholders. */\nfunction buildUsageLine(signature: ParsedSignature): string {\n const parts = [signature.name]\n\n for (const arg of signature.arguments) {\n parts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of signature.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n\n if (opt.isFlag) {\n parts.push(`[${flagStr}]`)\n } else if (opt.isArray) {\n parts.push(`[${flagStr} <value...>]`)\n } else {\n parts.push(`[${flagStr} <value>]`)\n }\n }\n\n return parts.join(' ')\n}\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g\n\n/** Remove ANSI escape sequences from a string. */\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '')\n}\n\n// eslint-disable-next-line no-control-regex\nconst TOKEN_RE = /(?:\\x1b\\[[0-9;]*m)*[^\\s\\x1b]+(?:\\x1b\\[[0-9;]*m)*/g\n\n/** Wrap a single line at word boundaries, preserving ANSI codes across wrapped segments. */\nfunction wrapLine(text: string, maxWidth: number, continuationIndent: string): string[] {\n const visibleLen = stripAnsi(text).length\n if (visibleLen <= maxWidth) return [text]\n\n const tokens = text.match(TOKEN_RE) ?? [text]\n\n const lines: string[] = []\n let currentLine = ''\n let currentVisibleLen = 0\n\n for (const token of tokens) {\n const tokenVisible = stripAnsi(token).length\n const separator = currentLine === '' ? '' : ' '\n const separatorLen = separator.length\n\n if (currentLine !== '' && currentVisibleLen + separatorLen + tokenVisible > maxWidth) {\n lines.push(currentLine)\n currentLine = continuationIndent + token\n currentVisibleLen = continuationIndent.length + tokenVisible\n } else {\n currentLine += separator + token\n currentVisibleLen += separatorLen + tokenVisible\n }\n }\n\n if (currentLine !== '') {\n lines.push(currentLine)\n }\n\n return lines\n}\n\n/** Format label/description pairs into aligned two-column table rows. */\nfunction formatTable(rows: readonly (readonly [string, string])[]): string[] {\n if (rows.length === 0) return []\n\n const maxLabel = Math.max(...rows.map(([label]) => stripAnsi(label).length))\n const padding = 4\n\n return rows.map(([label, desc]) => {\n const visibleLen = stripAnsi(label).length\n const pad = ' '.repeat(maxLabel - visibleLen + padding)\n return ` ${label}${pad}${desc}`\n })\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"zod-DvWTfRpI.d.mts","names":[],"sources":["../src/i18n/validation/cuid2.ts","../src/i18n/i18n.types.ts","../src/i18n/validation/validation.types.ts","../src/i18n/validation/zod.ts"],"mappings":";;;;;;;;;;;;;AAWA;;cAAa,WAAA,EAAW,MAAA;;;AAsCxB;;;;;;;;;;;;;;;;;;;;;AC7BA;;;;;;;;;;;;;iBD6BgB,KAAA,CAAM,OAAA;EAAY,OAAA,GAAU,MAAA;EAAQ,KAAA,cAAmB,MAAA,EAAQ,YAAA;AAAA,IAA0B,CAAA,CAAA,QAAA;;;;AAtCzG;;;;;AAsCA;;;;;KC7BY,QAAA,kCAA0C,CAAA,gCAEtC,CAAA,YAAa,CAAA,CAAE,CAAA,mBACzB,QAAA,CAAS,CAAA,CAAE,CAAA,MAAO,MAAA,GAAS,CAAA,UACxB,MAAA,GAAS,CAAA,WACR,CAAA;;;;;KAOE,iBAAA,GAAoB,QAAA,QAAgB,eAAA;;;;;;;;;AAZhD;;;;;;;;;;;;;;;;UAsCiB,oBAAA;;;;;KAML,WAAA,iBAA4B,oBAAA,GAAuB,oBAAA,CAAqB,CAAA;;;;;KAMxE,cAAA,GAAiB,QAAA,CAAS,WAAA;;;;;KAO1B,WAAA,GAAc,iBAAA,GAAoB,cAAA;;;;;AAnB9C;;;;;AAMA;;;;KA4BY,QAAA,qBAA6B,CAAA,yCACrC,IAAA,MAAU,IAAA,IAAQ,QAAA,CAAS,IAAA,MAC3B,CAAA;;;;;;;;;;AAxBJ;;;;;KAwCY,gBAAA,GAAmB,QAAA,CAAS,WAAA;;;;;KAM5B,aAAA,GAAgB,MAAA;;;;UAKX,YAAA;EA5BH;;;;;;;EAoCZ,CAAA,CAAE,GAAA,EAAK,WAAA,EAAa,MAAA,GAAS,aAAA;EArC6B;;;;;EA4C1D,SAAA;AAAA;;;;;;UClIe,iBAAA;;;AFKjB;EEDE,GAAA,EAAK,WAAA;;;;EAKL,MAAA,GAAS,MAAA;AAAA;;;;;KAOC,cAAA,GAAiB,eAAA;EAC3B,MAAA;IACE,IAAA,GAAO,iBAAA;IAAA,CACN,GAAA;EAAA;AAAA;AAAA"}
File without changes