stratal 0.0.26 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +912 -0
  2. package/README.md +96 -14
  3. package/dist/bin/cloudflare-workers-loader.mjs +18 -3
  4. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  5. package/dist/bin/quarry.mjs +85 -14
  6. package/dist/bin/quarry.mjs.map +1 -1
  7. package/dist/cache/index.d.mts +8 -9
  8. package/dist/cache/index.d.mts.map +1 -1
  9. package/dist/cache/index.mjs +56 -17
  10. package/dist/cache/index.mjs.map +1 -1
  11. package/dist/{cache.service-uElmBtdS.d.mts → cache.service-Dg0Hj0gp.d.mts} +27 -12
  12. package/dist/cache.service-Dg0Hj0gp.d.mts.map +1 -0
  13. package/dist/{command-DoBD2Cwl.d.mts → command-BXMccV_9.d.mts} +6 -3
  14. package/dist/command-BXMccV_9.d.mts.map +1 -0
  15. package/dist/{command-BvmUAPPQ.mjs → command-Bb820B6W.mjs} +36 -13
  16. package/dist/command-Bb820B6W.mjs.map +1 -0
  17. package/dist/common.schemas-BigQCwYB.mjs +89 -0
  18. package/dist/common.schemas-BigQCwYB.mjs.map +1 -0
  19. package/dist/config/index.d.mts +15 -15
  20. package/dist/config/index.d.mts.map +1 -1
  21. package/dist/config/index.mjs +4 -6
  22. package/dist/config/index.mjs.map +1 -1
  23. package/dist/{consumer-registry-D3iMTSdy.d.mts → consumer-registry-i9oCdarv.d.mts} +2 -3
  24. package/dist/consumer-registry-i9oCdarv.d.mts.map +1 -0
  25. package/dist/{container-storage-BmOJ4_Na.mjs → container-storage-DfF7SXdV.mjs} +11 -1
  26. package/dist/container-storage-DfF7SXdV.mjs.map +1 -0
  27. package/dist/{controller.decorator-YSTPQntu.mjs → controller.decorator-BB0JcwMg.mjs} +18 -9
  28. package/dist/controller.decorator-BB0JcwMg.mjs.map +1 -0
  29. package/dist/cron/index.d.mts +6 -7
  30. package/dist/cron/index.d.mts.map +1 -1
  31. package/dist/cron/index.mjs +1 -1
  32. package/dist/{cron-job-NesZRk8F.d.mts → cron-job-DAgNw4Bn.d.mts} +1 -2
  33. package/dist/cron-job-DAgNw4Bn.d.mts.map +1 -0
  34. package/dist/{cron.module-C81HTzR7.mjs → cron.module-Dnyl9sFk.mjs} +6 -7
  35. package/dist/{cron.module-C81HTzR7.mjs.map → cron.module-Dnyl9sFk.mjs.map} +1 -1
  36. package/dist/{decorate-CuAoSZvs.mjs → decorate-C79yt3Wt.mjs} +2 -2
  37. package/dist/di/index.d.mts +1 -1
  38. package/dist/di/index.mjs +2 -3
  39. package/dist/{di-D7qmrAir.mjs → di-DQ3xbjgf.mjs} +48 -6
  40. package/dist/di-DQ3xbjgf.mjs.map +1 -0
  41. package/dist/email/index.d.mts +158 -133
  42. package/dist/email/index.d.mts.map +1 -1
  43. package/dist/email/index.mjs +66 -78
  44. package/dist/email/index.mjs.map +1 -1
  45. package/dist/{en-CDZBMcc1.mjs → en-CCL84z4k.mjs} +2 -2
  46. package/dist/{en-CDZBMcc1.mjs.map → en-CCL84z4k.mjs.map} +1 -1
  47. package/dist/env-ug22bJj7.d.mts.map +1 -1
  48. package/dist/errors/index.d.mts +1 -1
  49. package/dist/errors/index.mjs +3 -3
  50. package/dist/{errors-C01O2T-n.mjs → errors-CrOXI_y5.mjs} +6 -8
  51. package/dist/errors-CrOXI_y5.mjs.map +1 -0
  52. package/dist/events/index.d.mts +8 -9
  53. package/dist/events/index.d.mts.map +1 -1
  54. package/dist/events/index.mjs +1 -1
  55. package/dist/{events-BhEQuT1X.mjs → events-GtwGEHyT.mjs} +5 -6
  56. package/dist/events-GtwGEHyT.mjs.map +1 -0
  57. package/dist/{exception-context-D-kvney-.mjs → exception-context-CdnGTQNF.mjs} +13 -7
  58. package/dist/exception-context-CdnGTQNF.mjs.map +1 -0
  59. package/dist/{gateway-context-m7kEzRa2.mjs → gateway-context-Cmc1NRS0.mjs} +7 -7
  60. package/dist/{gateway-context-m7kEzRa2.mjs.map → gateway-context-Cmc1NRS0.mjs.map} +1 -1
  61. package/dist/gateway-mode-0rUaeW3g.mjs +53 -0
  62. package/dist/gateway-mode-0rUaeW3g.mjs.map +1 -0
  63. package/dist/guards/index.d.mts +38 -20
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +2 -2
  66. package/dist/{guards-DALPXy3_.mjs → guards-DOGly9IF.mjs} +34 -11
  67. package/dist/guards-DOGly9IF.mjs.map +1 -0
  68. package/dist/hono-app-IhdqL0Fk.mjs +399 -0
  69. package/dist/hono-app-IhdqL0Fk.mjs.map +1 -0
  70. package/dist/{http-method.decorator-BljM8BDj.mjs → http-method.decorator-BDi9LTWj.mjs} +9 -8
  71. package/dist/http-method.decorator-BDi9LTWj.mjs.map +1 -0
  72. package/dist/i18n/index.d.mts +26 -137
  73. package/dist/i18n/index.d.mts.map +1 -1
  74. package/dist/i18n/index.mjs +4 -5
  75. package/dist/i18n/index.mjs.map +1 -1
  76. package/dist/i18n/messages/en/index.d.mts +1 -1
  77. package/dist/i18n/messages/en/index.mjs +1 -1
  78. package/dist/i18n/utils/index.d.mts +1 -2
  79. package/dist/i18n/utils/index.d.mts.map +1 -1
  80. package/dist/i18n/validation/index.d.mts +80 -5
  81. package/dist/i18n/validation/index.d.mts.map +1 -0
  82. package/dist/i18n/validation/index.mjs +4 -5
  83. package/dist/{i18n.module-B2DvWUPa.mjs → i18n.module-Bm3xlViA.mjs} +28 -13
  84. package/dist/i18n.module-Bm3xlViA.mjs.map +1 -0
  85. package/dist/index-0ItCjaqw.d.mts.map +1 -1
  86. package/dist/{index-CNuFQSNj.d.mts → index-3HJfhLlE.d.mts} +9 -11
  87. package/dist/index-3HJfhLlE.d.mts.map +1 -0
  88. package/dist/{index-uybm0bhQ.d.mts → index-B2WtEagR.d.mts} +1187 -234
  89. package/dist/index-B2WtEagR.d.mts.map +1 -0
  90. package/dist/index-BUt92sAE.d.mts.map +1 -1
  91. package/dist/index-CAHNCpvr.d.mts +203 -0
  92. package/dist/index-CAHNCpvr.d.mts.map +1 -0
  93. package/dist/index.d.mts +4 -4
  94. package/dist/index.mjs +2 -2
  95. package/dist/{is-command-CEPO9n8c.mjs → is-command-CSVv14wh.mjs} +2 -2
  96. package/dist/{is-command-CEPO9n8c.mjs.map → is-command-CSVv14wh.mjs.map} +1 -1
  97. package/dist/{is-seeder-Gvh_AM71.mjs → is-seeder-gLgXYbqC.mjs} +2 -2
  98. package/dist/is-seeder-gLgXYbqC.mjs.map +1 -0
  99. package/dist/{lazy-module-loader-M6YKudNL.d.mts → lazy-module-loader-C3OHoUnR.d.mts} +4 -5
  100. package/dist/lazy-module-loader-C3OHoUnR.d.mts.map +1 -0
  101. package/dist/limit-BE0HNAF6.mjs +116 -0
  102. package/dist/limit-BE0HNAF6.mjs.map +1 -0
  103. package/dist/locale-path.service-BqzDIrgy.mjs +213 -0
  104. package/dist/locale-path.service-BqzDIrgy.mjs.map +1 -0
  105. package/dist/locale-url-nZrZxqJP.mjs.map +1 -1
  106. package/dist/{locale-url.service-6bgia24_.mjs → locale-url.service-H8PH6GGh.mjs} +15 -5
  107. package/dist/{locale-url.service-6bgia24_.mjs.map → locale-url.service-H8PH6GGh.mjs.map} +1 -1
  108. package/dist/logger/index.mjs +3 -5
  109. package/dist/logger/index.mjs.map +1 -1
  110. package/dist/macroable-cvDTFZ_A.mjs.map +1 -1
  111. package/dist/metadata-Ba8Fxs1F.mjs +48 -0
  112. package/dist/metadata-Ba8Fxs1F.mjs.map +1 -0
  113. package/dist/module/index.d.mts +8 -9
  114. package/dist/module/index.d.mts.map +1 -1
  115. package/dist/module/index.mjs +3 -4
  116. package/dist/module/index.mjs.map +1 -1
  117. package/dist/{module-registry-NxX5O0Qk.mjs → module-registry-lkQPDuQe.mjs} +17 -15
  118. package/dist/module-registry-lkQPDuQe.mjs.map +1 -0
  119. package/dist/{module.decorator-CYHY6pG5.mjs → module.decorator-CYbrOlX9.mjs} +2 -2
  120. package/dist/{module.decorator-CYHY6pG5.mjs.map → module.decorator-CYbrOlX9.mjs.map} +1 -1
  121. package/dist/openapi/index.d.mts +19 -16
  122. package/dist/openapi/index.d.mts.map +1 -1
  123. package/dist/openapi/index.mjs +2 -2
  124. package/dist/{openapi-CMwuCp31.mjs → openapi-DBfBa5Qh.mjs} +41 -65
  125. package/dist/openapi-DBfBa5Qh.mjs.map +1 -0
  126. package/dist/openapi-generator-CCwiu8AU.mjs +134 -0
  127. package/dist/openapi-generator-CCwiu8AU.mjs.map +1 -0
  128. package/dist/{openapi-tools.service-BC5EC3R3.mjs → openapi-tools.service-VKZJlTIX.mjs} +12 -4
  129. package/dist/openapi-tools.service-VKZJlTIX.mjs.map +1 -0
  130. package/dist/openapi.service-Ds-R1tih.d.mts +43 -0
  131. package/dist/openapi.service-Ds-R1tih.d.mts.map +1 -0
  132. package/dist/quarry/index.d.mts +10 -11
  133. package/dist/quarry/index.d.mts.map +1 -1
  134. package/dist/quarry/index.mjs +4 -4
  135. package/dist/quarry/runner.d.mts +19 -20
  136. package/dist/quarry/runner.d.mts.map +1 -1
  137. package/dist/quarry/runner.mjs +16 -13
  138. package/dist/quarry/runner.mjs.map +1 -1
  139. package/dist/{quarry-registry-DRnV-DDa.d.mts → quarry-registry-Ci4k58FZ.d.mts} +3 -4
  140. package/dist/quarry-registry-Ci4k58FZ.d.mts.map +1 -0
  141. package/dist/{quarry.module-CcGxU2dJ.mjs → quarry.module-BssRR8f0.mjs} +20 -37
  142. package/dist/quarry.module-BssRR8f0.mjs.map +1 -0
  143. package/dist/queue/index.d.mts +2 -2
  144. package/dist/queue/index.mjs +3 -3
  145. package/dist/queue/index.mjs.map +1 -1
  146. package/dist/{queue.module-CEs4_kEM.mjs → queue.module-DnAdSbR-.mjs} +40 -41
  147. package/dist/queue.module-DnAdSbR-.mjs.map +1 -0
  148. package/dist/{r2-storage.provider-BoZmR6Ut.mjs → r2-storage.provider-wU_6api4.mjs} +45 -6
  149. package/dist/r2-storage.provider-wU_6api4.mjs.map +1 -0
  150. package/dist/{rate-limit.decorator-Djs4oYDB.mjs → rate-limit.decorator-PYQ9EYqs.mjs} +10 -5
  151. package/dist/{rate-limit.decorator-Djs4oYDB.mjs.map → rate-limit.decorator-PYQ9EYqs.mjs.map} +1 -1
  152. package/dist/rate-limiter/index.d.mts +64 -19
  153. package/dist/rate-limiter/index.d.mts.map +1 -1
  154. package/dist/rate-limiter/index.mjs +67 -83
  155. package/dist/rate-limiter/index.mjs.map +1 -1
  156. package/dist/response-cache/index.d.mts +326 -0
  157. package/dist/response-cache/index.d.mts.map +1 -0
  158. package/dist/response-cache/index.mjs +511 -0
  159. package/dist/response-cache/index.mjs.map +1 -0
  160. package/dist/response-cache.error-B4D0zy9W.mjs +24 -0
  161. package/dist/response-cache.error-B4D0zy9W.mjs.map +1 -0
  162. package/dist/response-headers-BqA57S_X.mjs +158 -0
  163. package/dist/response-headers-BqA57S_X.mjs.map +1 -0
  164. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  165. package/dist/route-cache-binding-CrLh8tB6.mjs +390 -0
  166. package/dist/route-cache-binding-CrLh8tB6.mjs.map +1 -0
  167. package/dist/route-metadata-QQhbed1i.mjs +17 -0
  168. package/dist/route-metadata-QQhbed1i.mjs.map +1 -0
  169. package/dist/{route-name-DGoBOfPg.mjs → route-name-BslSbmMP.mjs} +15 -11
  170. package/dist/route-name-BslSbmMP.mjs.map +1 -0
  171. package/dist/route-registration.service-COKBZTsn.mjs +1265 -0
  172. package/dist/route-registration.service-COKBZTsn.mjs.map +1 -0
  173. package/dist/{route-registry-BvLJisvK.mjs → route-registry-DFz9_-N6.mjs} +6 -6
  174. package/dist/{route-registry-BvLJisvK.mjs.map → route-registry-DFz9_-N6.mjs.map} +1 -1
  175. package/dist/router/index.d.mts +2 -2
  176. package/dist/router/index.mjs +16 -15
  177. package/dist/{router-resolver-sUV_jTrU.mjs → router-resolver-B-dMSMIG.mjs} +7 -3
  178. package/dist/router-resolver-B-dMSMIG.mjs.map +1 -0
  179. package/dist/{router-DwyqEXgf.mjs → router-wlsVkGkM.mjs} +5 -14
  180. package/dist/{router-DwyqEXgf.mjs.map → router-wlsVkGkM.mjs.map} +1 -1
  181. package/dist/seeder/index.d.mts +12 -13
  182. package/dist/seeder/index.d.mts.map +1 -1
  183. package/dist/seeder/index.mjs +4 -4
  184. package/dist/{seeder-BPGY5rUb.mjs → seeder-BrAk7XIj.mjs} +5 -6
  185. package/dist/{seeder-BPGY5rUb.mjs.map → seeder-BrAk7XIj.mjs.map} +1 -1
  186. package/dist/{seeder-registry-DEvCycsT.mjs → seeder-registry-Bo5BgLbC.mjs} +5 -6
  187. package/dist/{seeder-registry-DEvCycsT.mjs.map → seeder-registry-Bo5BgLbC.mjs.map} +1 -1
  188. package/dist/{seeder.module-CIwQbdN4.mjs → seeder.module-DOoVgTsK.mjs} +5 -5
  189. package/dist/{seeder.module-CIwQbdN4.mjs.map → seeder.module-DOoVgTsK.mjs.map} +1 -1
  190. package/dist/signed-url-DIU0sK_6.mjs.map +1 -1
  191. package/dist/storage/index.d.mts +63 -13
  192. package/dist/storage/index.d.mts.map +1 -1
  193. package/dist/storage/index.mjs +2 -2
  194. package/dist/storage/providers/index.d.mts +18 -16
  195. package/dist/storage/providers/index.d.mts.map +1 -1
  196. package/dist/storage/providers/index.mjs +1 -1
  197. package/dist/{storage-C30X81CS.mjs → storage-DBWVYMnn.mjs} +167 -49
  198. package/dist/storage-DBWVYMnn.mjs.map +1 -0
  199. package/dist/storage-provider.interface-CinHpjl1.d.mts +315 -0
  200. package/dist/storage-provider.interface-CinHpjl1.d.mts.map +1 -0
  201. package/dist/storage.error-Ao38Qdjx.mjs +7 -0
  202. package/dist/storage.error-Ao38Qdjx.mjs.map +1 -0
  203. package/dist/{stratal-D5j_I14G.d.mts → stratal-Bs1_E8GQ.d.mts} +13 -3
  204. package/dist/stratal-Bs1_E8GQ.d.mts.map +1 -0
  205. package/dist/{stratal-BL6FKUM_.mjs → stratal-CiwNpWy2.mjs} +56 -23
  206. package/dist/stratal-CiwNpWy2.mjs.map +1 -0
  207. package/dist/{tiered-cache.service-Dv3BhxxE.d.mts → tiered-cache.service-Bz8bbvyb.d.mts} +16 -3
  208. package/dist/tiered-cache.service-Bz8bbvyb.d.mts.map +1 -0
  209. package/dist/trailing-slash-2SctvePW.mjs.map +1 -1
  210. package/dist/types-CmV_9xBD.d.mts.map +1 -1
  211. package/dist/{uri-iwofWJ_T.mjs → uri-BrOq148R.mjs} +13 -9
  212. package/dist/{uri-iwofWJ_T.mjs.map → uri-BrOq148R.mjs.map} +1 -1
  213. package/dist/{usage-generator-DAWYasuP.mjs → usage-generator-BW7EcO-C.mjs} +3 -3
  214. package/dist/{usage-generator-DAWYasuP.mjs.map → usage-generator-BW7EcO-C.mjs.map} +1 -1
  215. package/dist/{zod-eKqqhZ5_.mjs → validation-CZ_B0aXY.mjs} +38 -17
  216. package/dist/validation-CZ_B0aXY.mjs.map +1 -0
  217. package/dist/{validation.context-CRvmrhq7.mjs → validation.context-CdbwQWIr.mjs} +2 -2
  218. package/dist/{validation.context-CRvmrhq7.mjs.map → validation.context-CdbwQWIr.mjs.map} +1 -1
  219. package/dist/{versioning.service-CCa2oYMJ.mjs → versioning.service-DnF_4Lnd.mjs} +5 -5
  220. package/dist/{versioning.service-CCa2oYMJ.mjs.map → versioning.service-DnF_4Lnd.mjs.map} +1 -1
  221. package/dist/websocket/index.d.mts +12 -13
  222. package/dist/websocket/index.d.mts.map +1 -1
  223. package/dist/websocket/index.mjs +1 -1
  224. package/dist/workers/index.d.mts +70 -7
  225. package/dist/workers/index.d.mts.map +1 -1
  226. package/dist/workers/index.mjs +72 -3
  227. package/dist/workers/index.mjs.map +1 -1
  228. package/dist/{zod-wecrEVAs.d.mts → zod-BGisqLs3.d.mts} +9 -16
  229. package/dist/zod-BGisqLs3.d.mts.map +1 -0
  230. package/package.json +33 -25
  231. package/dist/cache.service-uElmBtdS.d.mts.map +0 -1
  232. package/dist/chunk-BBjsoOtd.mjs +0 -27
  233. package/dist/command-BvmUAPPQ.mjs.map +0 -1
  234. package/dist/command-DoBD2Cwl.d.mts.map +0 -1
  235. package/dist/consumer-registry-D3iMTSdy.d.mts.map +0 -1
  236. package/dist/container-storage-BmOJ4_Na.mjs.map +0 -1
  237. package/dist/controller.decorator-YSTPQntu.mjs.map +0 -1
  238. package/dist/cron-job-NesZRk8F.d.mts.map +0 -1
  239. package/dist/di-D7qmrAir.mjs.map +0 -1
  240. package/dist/errors-C01O2T-n.mjs.map +0 -1
  241. package/dist/events-BhEQuT1X.mjs.map +0 -1
  242. package/dist/exception-context-D-kvney-.mjs.map +0 -1
  243. package/dist/guards-DALPXy3_.mjs.map +0 -1
  244. package/dist/hono-app-COAgmutc.mjs +0 -168
  245. package/dist/hono-app-COAgmutc.mjs.map +0 -1
  246. package/dist/http-method.decorator-BljM8BDj.mjs.map +0 -1
  247. package/dist/i18n.module-B2DvWUPa.mjs.map +0 -1
  248. package/dist/index-CNuFQSNj.d.mts.map +0 -1
  249. package/dist/index-DtBNIFuP.d.mts +0 -42
  250. package/dist/index-DtBNIFuP.d.mts.map +0 -1
  251. package/dist/index-HgOLNruQ.d.mts +0 -203
  252. package/dist/index-HgOLNruQ.d.mts.map +0 -1
  253. package/dist/index-uybm0bhQ.d.mts.map +0 -1
  254. package/dist/is-seeder-Gvh_AM71.mjs.map +0 -1
  255. package/dist/lazy-module-loader-M6YKudNL.d.mts.map +0 -1
  256. package/dist/locale-path.service-CH0CaxwH.mjs +0 -165
  257. package/dist/locale-path.service-CH0CaxwH.mjs.map +0 -1
  258. package/dist/metadata-DzzprcID.mjs +0 -39
  259. package/dist/metadata-DzzprcID.mjs.map +0 -1
  260. package/dist/module-registry-NxX5O0Qk.mjs.map +0 -1
  261. package/dist/openapi-CMwuCp31.mjs.map +0 -1
  262. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +0 -1
  263. package/dist/openapi.service-2rvJBCEg.d.mts +0 -50
  264. package/dist/openapi.service-2rvJBCEg.d.mts.map +0 -1
  265. package/dist/quarry-registry-DRnV-DDa.d.mts.map +0 -1
  266. package/dist/quarry.module-CcGxU2dJ.mjs.map +0 -1
  267. package/dist/queue.module-CEs4_kEM.mjs.map +0 -1
  268. package/dist/r2-storage.provider-BoZmR6Ut.mjs.map +0 -1
  269. package/dist/route-name-DGoBOfPg.mjs.map +0 -1
  270. package/dist/route-registration.service-CDPQKpm4.mjs +0 -918
  271. package/dist/route-registration.service-CDPQKpm4.mjs.map +0 -1
  272. package/dist/router-resolver-sUV_jTrU.mjs.map +0 -1
  273. package/dist/storage-C30X81CS.mjs.map +0 -1
  274. package/dist/storage-provider.interface-ClUwxz4S.d.mts +0 -201
  275. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +0 -1
  276. package/dist/storage.error-BStXPmO4.mjs +0 -8
  277. package/dist/storage.error-BStXPmO4.mjs.map +0 -1
  278. package/dist/stratal-BL6FKUM_.mjs.map +0 -1
  279. package/dist/stratal-D5j_I14G.d.mts.map +0 -1
  280. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +0 -1
  281. package/dist/validation-CpOjviyT.mjs +0 -49
  282. package/dist/validation-CpOjviyT.mjs.map +0 -1
  283. package/dist/zod-eKqqhZ5_.mjs.map +0 -1
  284. package/dist/zod-wecrEVAs.d.mts.map +0 -1
@@ -1,8 +1,7 @@
1
- import { n as CONTAINER_TOKEN, p as inject, r as DI_TOKENS, u as Transient } from "./di-D7qmrAir.mjs";
2
- import { a as ApplicationError } from "./container-storage-BmOJ4_Na.mjs";
3
- import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
1
+ import { n as CONTAINER_TOKEN, p as inject, r as DI_TOKENS, u as Transient } from "./di-DQ3xbjgf.mjs";
2
+ import { a as ApplicationError } from "./container-storage-DfF7SXdV.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-C79yt3Wt.mjs";
4
4
  import { LOGGER_TOKENS } from "./logger/index.mjs";
5
- import "./exception-context-D-kvney-.mjs";
6
5
  //#region src/errors/http-exception.ts
7
6
  const HTTP_STATUS_MESSAGES = {
8
7
  400: "Bad Request",
@@ -157,6 +156,7 @@ let ExceptionHandler = class ExceptionHandler {
157
156
  const severity = this.resolveSeverity(error);
158
157
  const globalContext = this.gatherContext();
159
158
  const logData = {
159
+ ...error.reportContext(),
160
160
  message: error.message,
161
161
  timestamp: error.timestamp,
162
162
  name: error.name,
@@ -175,9 +175,7 @@ let ExceptionHandler = class ExceptionHandler {
175
175
  case "warn":
176
176
  this.logger.warn("[ApplicationError]", logData);
177
177
  break;
178
- case "error":
179
- this.logger.error("[ApplicationError]", logData);
180
- break;
178
+ case "error": this.logger.error("[ApplicationError]", logData);
181
179
  }
182
180
  }
183
181
  async defaultRender(error, context) {
@@ -345,4 +343,4 @@ var AuthError = class extends ApplicationError {
345
343
  //#endregion
346
344
  export { isErrorResponse as a, isApplicationError as c, HttpException as d, abort as f, StratalNotInitializedError as i, InternalError as l, DatabaseError as n, DefaultExceptionHandler as o, StratalSupersededError as r, ExceptionHandler as s, AuthError as t, HTTP_STATUS_MESSAGES as u };
347
345
 
348
- //# sourceMappingURL=errors-C01O2T-n.mjs.map
346
+ //# sourceMappingURL=errors-CrOXI_y5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-CrOXI_y5.mjs","names":[],"sources":["../src/errors/http-exception.ts","../src/errors/internal-error.ts","../src/errors/is-application-error.ts","../src/errors/exception-handler.ts","../src/errors/default-exception-handler.ts","../src/errors/error-response.ts","../src/errors/stratal-not-initialized.error.ts","../src/errors/stratal-superseded.error.ts","../src/errors/database.error.ts","../src/errors/auth.error.ts"],"sourcesContent":["import type { ContentfulStatusCode } from 'hono/utils/http-status'\nimport { ApplicationError } from './application-error'\n\nexport const HTTP_STATUS_MESSAGES: Partial<Record<number, string>> = {\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 402: 'Payment Required',\n 403: 'Forbidden',\n 404: 'Not Found',\n 409: 'Conflict',\n 413: 'Content Too Large',\n 422: 'Unprocessable Entity',\n 423: 'Locked',\n 429: 'Too Many Requests',\n 500: 'Internal Server Error',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n}\n\nexport class HttpException extends ApplicationError {\n public readonly httpStatus: ContentfulStatusCode\n\n constructor(httpStatus: ContentfulStatusCode, message?: string, cause?: unknown) {\n super(message ?? HTTP_STATUS_MESSAGES[httpStatus] ?? 'Internal Server Error', cause)\n this.httpStatus = httpStatus\n }\n}\n\nexport function abort(\n status: ContentfulStatusCode,\n message?: string,\n): never {\n throw new HttpException(status, message)\n}\n","import { ApplicationError } from './application-error'\n\nexport class InternalError extends ApplicationError {\n constructor(cause?: unknown) {\n super('Internal Server Error', cause)\n }\n}\n","import { ApplicationError } from './application-error'\n\nexport function isApplicationError(error: unknown): error is ApplicationError {\n if (error instanceof ApplicationError) return true\n return error instanceof Error\n && typeof (error as ApplicationError).timestamp === 'string'\n}\n","import type { ContentfulStatusCode } from 'hono/utils/http-status';\nimport { inject } from '../di';\nimport { CONTAINER_TOKEN, type Container } from '../di';\nimport { Transient } from '../di/decorators';\nimport { DI_TOKENS } from '../di/tokens';\nimport { type StratalEnv } from '../env';\nimport type { StratalExecutionContext } from '../execution-context';\nimport { LOGGER_TOKENS, type LoggerService } from '../logger';\nimport type { ApplicationError } from './application-error';\nimport type { Environment, ErrorResponse } from './error-response';\nimport type { ExceptionContext, HttpExceptionContext } from './exception-context';\nimport type {\n ApplicationErrorConstructor,\n ContextCallback,\n ErrorPageCallback,\n LogSeverity,\n RenderableCallback,\n Reportable,\n ReportableCallback,\n RespondCallback,\n} from './exception-handler.types';\nimport { HTTP_STATUS_MESSAGES, HttpException } from './http-exception';\nimport { InternalError } from './internal-error';\nimport { isApplicationError } from './is-application-error';\n\ninterface ReportableEntry {\n errorClass: ApplicationErrorConstructor\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n callback: ReportableCallback<any>\n shouldStop: boolean\n}\n\ninterface RenderableEntry {\n errorClass: ApplicationErrorConstructor\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n callback: RenderableCallback<any>\n}\n\n@Transient()\nexport abstract class ExceptionHandler {\n private readonly reportables: ReportableEntry[] = []\n private readonly renderables: RenderableEntry[] = []\n private readonly dontReportSet = new Set<ApplicationErrorConstructor>()\n private readonly levelOverrides = new Map<ApplicationErrorConstructor, LogSeverity>()\n private readonly contextCallbacks: ContextCallback[] = []\n private readonly respondCallbacks: RespondCallback[] = []\n private readonly errorPages: ErrorPageCallback[] = []\n private readonly environment: Environment\n\n constructor(\n @inject(LOGGER_TOKENS.LoggerService) protected readonly logger: LoggerService,\n @inject(DI_TOKENS.CloudflareEnv) protected readonly env: StratalEnv,\n @inject(CONTAINER_TOKEN) private readonly container: Container,\n @inject(DI_TOKENS.ExecutionContext) private readonly executionContext: StratalExecutionContext,\n ) {\n this.environment = this.env.ENVIRONMENT as Environment\n }\n\n abstract register(): void\n\n // ── Public Configuration API ──────────────────────────────────────\n\n reportable<T extends ApplicationError>(\n errorClass: ApplicationErrorConstructor<T>,\n callback: ReportableCallback<T>,\n ): Reportable {\n const entry: ReportableEntry = { errorClass, callback, shouldStop: false }\n this.reportables.push(entry)\n return {\n stop: () => { entry.shouldStop = true },\n }\n }\n\n renderable<T extends ApplicationError>(\n errorClass: ApplicationErrorConstructor<T>,\n callback: RenderableCallback<T>,\n ): void {\n this.renderables.push({ errorClass, callback })\n }\n\n dontReport(errorClasses: ApplicationErrorConstructor[]): void {\n for (const cls of errorClasses) {\n this.dontReportSet.add(cls)\n }\n }\n\n level(errorClass: ApplicationErrorConstructor, severity: LogSeverity): void {\n this.levelOverrides.set(errorClass, severity)\n }\n\n context(callback: ContextCallback): void {\n this.contextCallbacks.push(callback)\n }\n\n respond(callback: RespondCallback): void {\n this.respondCallbacks.push(callback)\n }\n\n errorPage(callback: ErrorPageCallback): void {\n this.errorPages.push(callback)\n }\n\n resolve<T>(token: symbol | (new (...args: unknown[]) => T)): T {\n return this.container.resolve<T>(token)\n }\n\n // ── Pipeline Entry Point ──────────────────────────────────────────\n\n async handle(error: unknown, context: ExceptionContext): Promise<Response> {\n const appError = this.normalizeError(error)\n\n this.executionContext.waitUntil(this.performReport(appError, context))\n\n const response = await this.performRender(appError, context)\n\n return this.applyRespondCallbacks(response, appError, context)\n }\n\n // ── Internals ─────────────────────────────────────────────────────\n\n private normalizeError(error: unknown): ApplicationError {\n if (isApplicationError(error)) {\n return error\n }\n\n return new InternalError(error)\n }\n\n private async performReport(error: ApplicationError, context: ExceptionContext): Promise<void> {\n if (this.shouldNotReport(error)) return\n\n const entry = this.findReportable(error)\n if (entry) {\n await entry.callback(error, context)\n if (entry.shouldStop) return\n }\n\n this.defaultReport(error)\n }\n\n private async performRender(error: ApplicationError, context: ExceptionContext): Promise<Response> {\n const entry = this.findRenderable(error)\n if (entry) {\n const result = entry.callback(error, context)\n if (result !== undefined) {\n return this.toResponse(await result, error)\n }\n }\n\n return await this.defaultRender(error, context)\n }\n\n private applyRespondCallbacks(\n response: Response,\n error: ApplicationError,\n context: ExceptionContext,\n ): Response {\n let result = response\n for (const callback of this.respondCallbacks) {\n result = callback(result, error, context)\n }\n return result\n }\n\n private shouldNotReport(error: ApplicationError): boolean {\n for (const cls of this.dontReportSet) {\n if (error instanceof cls) return true\n }\n return false\n }\n\n private findReportable(error: ApplicationError): ReportableEntry | undefined {\n let best: ReportableEntry | undefined\n for (const entry of this.reportables) {\n if (this.matchesErrorClass(error, entry.errorClass)) {\n if (!best || !this.matchesErrorClass(error, best.errorClass) || entry.errorClass.prototype instanceof best.errorClass) {\n best = entry\n }\n }\n }\n return best\n }\n\n private findRenderable(error: ApplicationError): RenderableEntry | undefined {\n let best: RenderableEntry | undefined\n for (const entry of this.renderables) {\n if (this.matchesErrorClass(error, entry.errorClass)) {\n if (!best || !this.matchesErrorClass(error, best.errorClass) || entry.errorClass.prototype instanceof best.errorClass) {\n best = entry\n }\n }\n }\n return best\n }\n\n private matchesErrorClass(error: ApplicationError, cls: ApplicationErrorConstructor): boolean {\n if (error instanceof cls) return true\n return (error as Error).constructor.name === cls.name\n }\n\n private defaultReport(error: ApplicationError): void {\n const severity = this.resolveSeverity(error)\n const globalContext = this.gatherContext()\n\n const logData: Record<string, unknown> = {\n ...error.reportContext(),\n message: error.message,\n timestamp: error.timestamp,\n name: error.name,\n stack: error.stack,\n ...globalContext,\n }\n\n const chain = serializeErrorChain(error)\n if (chain) {\n logData.cause = chain\n }\n\n switch (severity) {\n case 'debug':\n this.logger.debug('[ApplicationError]', logData)\n break\n case 'info':\n this.logger.info('[ApplicationError]', logData)\n break\n case 'warn':\n this.logger.warn('[ApplicationError]', logData)\n break\n case 'error':\n this.logger.error('[ApplicationError]', logData)\n break\n }\n }\n\n private async defaultRender(error: ApplicationError, context: ExceptionContext): Promise<Response> {\n const status = this.resolveStatus(error)\n const errorResponse = this.buildErrorResponse(error, status)\n\n if (context.type === 'http' && this.wantsHtml(context)) {\n for (const callback of this.errorPages) {\n try {\n const result = await callback(errorResponse, status, context, error)\n if (result !== undefined) return result\n } catch (callbackError) {\n this.logger.warn('errorPage callback failed, falling back to next handler', {\n error: callbackError instanceof Error ? callbackError.message : String(callbackError),\n })\n }\n }\n return this.renderDefaultHtml(errorResponse, status)\n }\n\n return Response.json(errorResponse, { status })\n }\n\n // ── Content Negotiation ──────────────────────────────────────────\n\n protected wantsHtml(context: HttpExceptionContext): boolean {\n const accept = context.ctx.c.req.header('accept') ?? ''\n return accept.includes('text/html')\n }\n\n protected renderDefaultHtml(\n errorResponse: ErrorResponse,\n status: ContentfulStatusCode,\n ): Response {\n const title = this.escapeHtml(errorResponse.message)\n const html = `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>${status} - ${title}</title>\n<link rel=\"icon\" type=\"image/x-icon\" href=\"/favicon.svg\">\n<style>*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,-apple-system,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f8fafc;color:#334155}.container{text-align:center;padding:2rem}.status{font-size:6rem;font-weight:800;color:#13c397;line-height:1}.message{font-size:1.25rem;color:#64748b;margin-top:1rem}</style>\n</head><body><div class=\"container\"><div class=\"status\">${status}</div><div class=\"message\">${title}</div></div></body></html>`\n return new Response(html, {\n status,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n })\n }\n\n private resolveStatus(error: ApplicationError): ContentfulStatusCode {\n if (error instanceof HttpException) return error.httpStatus\n const httpStatus = (error as { httpStatus?: number }).httpStatus\n if (typeof httpStatus === 'number') return httpStatus as ContentfulStatusCode\n return 500\n }\n\n private buildErrorResponse(error: ApplicationError, status: ContentfulStatusCode): ErrorResponse {\n const isServerError = status >= 500\n const isDev = this.environment === 'development'\n const message = isServerError && !isDev\n ? (HTTP_STATUS_MESSAGES[status] ?? 'Internal Server Error')\n : error.message\n\n return {\n message,\n timestamp: error.timestamp,\n stack: isDev ? error.stack : undefined,\n }\n }\n\n private escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n }\n\n private toResponse(result: Response | ErrorResponse, error: ApplicationError): Response {\n if (result instanceof Response) return result\n const status = this.resolveStatus(error)\n return Response.json(result, { status })\n }\n\n private resolveSeverity(error: ApplicationError): LogSeverity {\n let bestClass: ApplicationErrorConstructor | undefined\n let bestSeverity: LogSeverity | undefined\n\n for (const [cls, severity] of this.levelOverrides) {\n if (error instanceof cls) {\n if (!bestClass || cls.prototype instanceof bestClass) {\n bestClass = cls\n bestSeverity = severity\n }\n }\n }\n\n if (bestSeverity) return bestSeverity\n\n const status = this.resolveStatus(error)\n return this.getDefaultSeverity(status)\n }\n\n private getDefaultSeverity(status: number): LogSeverity {\n if (status >= 500) return 'error'\n if (status >= 400) return 'warn'\n return 'error'\n }\n\n private gatherContext(): Record<string, unknown> {\n if (this.contextCallbacks.length === 0) return {}\n const merged: Record<string, unknown> = {}\n for (const callback of this.contextCallbacks) {\n Object.assign(merged, callback())\n }\n return merged\n }\n}\n\ninterface SerializedErrorNode {\n name: string\n message: string\n stack?: string\n cause?: SerializedErrorNode | { value: unknown }\n errors?: SerializedErrorNode[]\n}\n\nconst MAX_CAUSE_DEPTH = 5\n\nfunction serializeErrorChain(error: Error): SerializedErrorNode | undefined {\n const cause = (error as { cause?: unknown }).cause\n const aggregated = error instanceof AggregateError && Array.isArray(error.errors) && error.errors.length > 0\n if (cause === undefined && !aggregated) {\n return undefined\n }\n if (cause !== undefined) {\n return cause instanceof Error\n ? serializeErrorNode(cause, 0)\n : ({ value: cause } as unknown as SerializedErrorNode)\n }\n return {\n name: error.name,\n message: error.message,\n errors: (error as AggregateError).errors.map((inner) =>\n inner instanceof Error\n ? serializeErrorNode(inner, 0)\n : { name: 'Unknown', message: String(inner) },\n ),\n }\n}\n\nfunction serializeErrorNode(error: Error, depth: number): SerializedErrorNode {\n const out: SerializedErrorNode = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n\n if (depth >= MAX_CAUSE_DEPTH) return out\n\n if (error instanceof AggregateError && Array.isArray(error.errors) && error.errors.length > 0) {\n out.errors = error.errors.map((inner) =>\n inner instanceof Error\n ? serializeErrorNode(inner, depth + 1)\n : { name: 'Unknown', message: String(inner) },\n )\n }\n\n const cause = (error as { cause?: unknown }).cause\n if (cause !== undefined) {\n out.cause = cause instanceof Error\n ? serializeErrorNode(cause, depth + 1)\n : { value: cause }\n }\n\n return out\n}\n","import { Transient } from '../di/decorators';\nimport { ExceptionHandler } from './exception-handler';\n\n/**\n * DefaultExceptionHandler — the built-in exception handler used when no\n * custom handler is provided via `ApplicationConfig.exceptionHandler`.\n *\n * Has an empty `register()` method, so all exceptions flow through the\n * default pipeline: severity-based logging, i18n translation, and JSON\n * error response serialization.\n *\n * To customize exception handling, extend {@link ExceptionHandler} and\n * override `register()`, then pass your class to the Stratal config:\n *\n * @example\n * ```typescript\n * new Stratal({\n * module: AppModule,\n * exceptionHandler: AppExceptionHandler,\n * })\n * ```\n */\n@Transient()\nexport class DefaultExceptionHandler extends ExceptionHandler {\n register(): void {\n // No custom configuration — uses all defaults\n }\n}\n","export type Environment = 'development' | 'staging' | 'production'\n\nexport interface ErrorResponse {\n message: string\n timestamp: string\n stack?: string\n}\n\nexport function isErrorResponse(obj: unknown): obj is ErrorResponse {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n 'message' in obj &&\n typeof (obj as ErrorResponse).message === 'string' &&\n 'timestamp' in obj &&\n typeof (obj as ErrorResponse).timestamp === 'string'\n )\n}\n","import { ApplicationError } from './application-error'\n\nexport class StratalNotInitializedError extends ApplicationError {\n constructor() {\n super('Stratal has not been initialized. Ensure you export a Stratal instance as the default export.')\n }\n}\n","import { ApplicationError } from './application-error'\n\n/**\n * Thrown (as a promise rejection) when a Stratal generation is superseded by a\n * newer instance before its initialization completed — e.g. a Vite HMR reload\n * re-evaluated the worker entry mid-boot. Awaiters should retry against the\n * current generation via `Stratal.resolveApplication()`.\n */\nexport class StratalSupersededError extends ApplicationError {\n constructor(readonly generation: number) {\n super(`Stratal generation ${generation} was superseded by a newer instance (hot reload).`)\n }\n}\n","import { ApplicationError } from './application-error'\n\nexport class DatabaseError extends ApplicationError {\n constructor(message?: string, cause?: unknown) {\n super(message ?? 'Database error', cause)\n }\n}\n","import { ApplicationError } from './application-error'\n\nexport class AuthError extends ApplicationError {\n constructor(message?: string, cause?: unknown) {\n super(message ?? 'Authentication error', cause)\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { r as LoggerService } from "../index-BUt92sAE.mjs";
2
2
  import { t as Constructor } from "../types-CmV_9xBD.mjs";
3
-
4
3
  //#region src/events/constants.d.ts
5
4
  /**
6
5
  * Metadata keys for event listener decorators.
@@ -8,7 +7,7 @@ import { t as Constructor } from "../types-CmV_9xBD.mjs";
8
7
  * Uses `Symbol.for()` (global symbol registry) so that both core and
9
8
  * framework packages can reference the same symbols without cross-imports.
10
9
  */
11
- declare const LISTENER_METADATA_KEYS: {
10
+ export declare const LISTENER_METADATA_KEYS: {
12
11
  readonly IS_LISTENER: symbol;
13
12
  readonly EVENT_HANDLERS: symbol;
14
13
  };
@@ -31,11 +30,11 @@ declare const LISTENER_METADATA_KEYS: {
31
30
  * }
32
31
  * ```
33
32
  */
34
- declare function Listener(): <T extends Constructor>(target: T) => T;
33
+ export declare function Listener(): <T extends Constructor>(target: T) => T;
35
34
  /**
36
35
  * Check if a class is decorated with `@Listener()`
37
36
  */
38
- declare function isListener(target: Constructor): boolean;
37
+ export declare function isListener(target: Constructor): boolean;
39
38
  //#endregion
40
39
  //#region src/events/types.d.ts
41
40
  /**
@@ -182,14 +181,14 @@ interface ListenerHandlerMetadata {
182
181
  * }
183
182
  * ```
184
183
  */
185
- declare function On<E extends EventName>(event: E, options?: EventOptions): (target: object, propertyKey: string, _descriptor: PropertyDescriptor) => void;
184
+ export declare function On<E extends EventName>(event: E, options?: EventOptions): (target: object, propertyKey: string, _descriptor: PropertyDescriptor) => void;
186
185
  /**
187
186
  * Get all `@On()` handler metadata from a listener class
188
187
  */
189
- declare function getListenerHandlers(target: object): ListenerHandlerMetadata[];
188
+ export declare function getListenerHandlers(target: object): ListenerHandlerMetadata[];
190
189
  //#endregion
191
190
  //#region src/events/event-registry.d.ts
192
- declare class EventRegistry implements IEventRegistry {
191
+ export declare class EventRegistry implements IEventRegistry {
193
192
  private readonly ctx;
194
193
  private readonly logger;
195
194
  private handlers;
@@ -223,7 +222,7 @@ declare class EventRegistry implements IEventRegistry {
223
222
  * application's event-listener trigger paths. Kept out of cold start for apps
224
223
  * that neither emit events nor use the database.
225
224
  */
226
- declare class EventsModule {}
225
+ export declare class EventsModule {}
227
226
  //#endregion
228
- export { type CustomEventContext, type CustomEventRegistry, type EventContext, type EventHandler, type EventName, type EventOptions, EventRegistry, EventsModule, type IEventRegistry, LISTENER_METADATA_KEYS, Listener, type ListenerHandlerMetadata, On, type RegisteredHandler, getListenerHandlers, isListener };
227
+ export type { CustomEventContext, CustomEventRegistry, EventContext, EventHandler, EventName, EventOptions, IEventRegistry, ListenerHandlerMetadata, RegisteredHandler };
229
228
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/events/constants.ts","../../src/events/decorators/listener.decorator.ts","../../src/events/types.ts","../../src/events/decorators/on.decorator.ts","../../src/events/event-registry.ts","../../src/events/events.module.ts"],"mappings":";;;;;;;;AAMA;;cAAa,sBAAA;EAAA,SAGH,WAAA;EAAA,SAAA,cAAA;AAAA;;;;;;AAHV;;;;;;;;ACgBA;;;;;;iBAAgB,QAAA,eACa,WAAA,EAAa,MAAA,EAAQ,CAAA,KAAC,CAAA;;;;iBAUnC,UAAA,CAAW,MAAmB,EAAX,WAAW;;;;;;;AD3B9C;;;;;;;;ACgBA;;;;;;;;;;;;;;AACmD;AAUnD;;;;AAA8C;;;;ACS9C;;UAAiB,mBAAA;AAAmB;AAMpC;;;AANoC,KAMxB,SAAA,SAAkB,mBAAA,0BAE1B,OAAA,OAAc,mBAAA;;;;;;;;;AAAmB;AAkBrC;;;UAAiB,kBAAA;EACf,IAAA,EAAM,KAAA;EACN,QAAA,GAAW,MAAM;AAAA;;;;AAAA;AAQnB;KAAY,YAAA,WAAuB,SAAA,GAAY,SAAA,IAC7C,CAAA,eAAgB,mBAAA,GACd,mBAAA,CAAoB,CAAA;EAClB,IAAA;EAAgB,MAAA;AAAA;;;;UASL,YAAA;EAVQ;EAYvB,QAAA;EAduB;;;;;;;;EAuBvB,QAAQ;AAAA;AApBkB;AAS5B;;AAT4B,KA0BhB,YAAA,WAAuB,SAAA,GAAY,SAAA,KAC7C,OAAA,EAAS,YAAA,CAAa,CAAA,MACnB,OAAA;;AARK;AAMV;;UAQiB,iBAAA;EACf,OAAA,EAAS,YAAY;EACrB,QAAA;EACA,QAAA;AAAA;;;;UAMe,cAAA;EACf,EAAA,WAAa,SAAA,EACX,KAAA,EAAO,CAAA,EACP,OAAA,EAAS,YAAA,CAAa,CAAA,GACtB,OAAA,GAAU,YAAA;EAGZ,IAAA,WAAe,SAAA,EACb,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,OAAA,CAAQ,YAAA,CAAa,CAAA,KAC9B,OAAA;EAEH,GAAA,WAAc,SAAA,EAAW,KAAA,EAAO,CAAA,EAAG,OAAA,EAAS,YAAA,CAAa,CAAA;EAEzD,IAAA,WAAe,SAAA,EACb,KAAA,EAAO,CAAA,EACP,OAAA,EAAS,YAAA,CAAa,CAAA,GACtB,OAAA,GAAU,YAAA;EAjCZ;;;AACU;AAMZ;;EAmCE,YAAA,CAAa,KAAA,EAAO,SAAA;AAAA;;;;UAUL,uBAAA;EACf,UAAA;EACA,KAAA;EACA,OAAA,GAAU,YAAY;AAAA;;;;;;AF7JxB;;;;;;;;ACgBA;;;;;;;;;;iBEGgB,EAAA,WAAa,SAAA,EAAW,KAAA,EAAO,CAAA,EAAG,OAAA,GAAU,YAAA,IAExD,MAAA,UACA,WAAA,UACA,WAAA,EAAa,kBAAA;;;;iBAsBD,mBAAA,CAAoB,MAAA,WAAiB,uBAAuB;;;cCrC/D,aAAA,YAAyB,cAAA;EAAA,iBAImB,GAAA;EAAA,iBACC,MAAA;EAAA,QAJhD,QAAA;cAG+C,GAAA,EAAK,gBAAA,EACJ,MAAA,EAAQ,aAAA;EAGhE,EAAA,WAAa,SAAA,EAAW,KAAA,EAAO,CAAA,EAAG,OAAA,EAAS,YAAA,CAAa,CAAA,GAAI,OAAA,GAAU,YAAA;EAkBhE,IAAA,WAAe,SAAA,EACnB,KAAA,EAAO,CAAA,EACP,OAAA,GAAU,OAAA,CAAQ,YAAA,CAAa,CAAA,KAC9B,OAAA;EAmCH,GAAA,WAAc,SAAA,EAAW,KAAA,EAAO,CAAA,EAAG,OAAA,EAAS,YAAA,CAAa,CAAA;EAczD,YAAA,CAAa,KAAA,EAAO,SAAA;EAIpB,IAAA,WAAe,SAAA,EAAW,KAAA,EAAO,CAAA,EAAG,OAAA,EAAS,YAAA,CAAa,CAAA,GAAI,OAAA,GAAU,YAAA;EH1E1D;;;;EAAA,QGuFN,oBAAA;EHtFyC;;;EAAA,QG2HzC,kBAAA;EH3HmB;;;EAAA,QG8Ib,cAAA;AAAA;;;;;;;AJ/JhB;;;;cKWa,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/events/constants.ts","../../src/events/decorators/listener.decorator.ts","../../src/events/types.ts","../../src/events/decorators/on.decorator.ts","../../src/events/event-registry.ts","../../src/events/events.module.ts"],"mappings":";;;;;;;;;qBAMa;WACX;WACA;;;;;;;;;;;;;;;;;;;;;wBCcc,aACG,UAAU,aAAW,QAAU,MAAC;;;;wBAUnC,WAAW,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCSlB;;;;;KAML,kBAAkB,6CAE1B,cAAc;;;;;;;;;;;;;UAkBD,mBAAmB;EAClC,MAAM;EACN,WAAW;;;;;;;KAQD,aAAa,UAAU,YAAY,aAC7C,gBAAgB,sBACd,oBAAoB;EAClB;EAAgB;;;;;UASL;;EAEf;;;;;;;;;EASA;;;;;KAMU,aAAa,UAAU,YAAY,cAC7C,SAAS,aAAa,OACnB;;;;;UAMY;EACf,SAAS;EACT;EACA;;;;;UAMe;EACf,GAAG,UAAU,WACX,OAAO,GACP,SAAS,aAAa,IACtB,UAAU;EAGZ,KAAK,UAAU,WACb,OAAO,GACP,UAAU,QAAQ,aAAa,MAC9B;EAEH,IAAI,UAAU,WAAW,OAAO,GAAG,SAAS,aAAa;EAEzD,KAAK,UAAU,WACb,OAAO,GACP,SAAS,aAAa,IACtB,UAAU;;;;;;;EASZ,aAAa,OAAO;;;;;UAUL;EACf;EACA;EACA,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;wBC1II,GAAG,UAAU,WAAW,OAAO,GAAG,UAAU,gBAAY,gBAEtD,qBACK,aACN;;;;wBAsBD,oBAAoB,iBAAiB;;;qBCrCxC,yBAAyB;mBAImB;mBACC;UAJhD;EAER,YACuD,KAAK,kBACJ,QAAQ;EAGhE,GAAG,UAAU,WAAW,OAAO,GAAG,SAAS,aAAa,IAAI,UAAU;EAkBhE,KAAK,UAAU,WACnB,OAAO,GACP,UAAU,QAAQ,aAAa,MAC9B;EAmCH,IAAI,UAAU,WAAW,OAAO,GAAG,SAAS,aAAa;EAczD,aAAa,OAAO;EAIpB,KAAK,UAAU,WAAW,OAAO,GAAG,SAAS,aAAa,IAAI,UAAU;;;;;UAahE;;;;UAqCA;;;;UAmBM;;;;;;;;;;;;qBCpJH"}
@@ -1,2 +1,2 @@
1
- import { a as getListenerHandlers, c as LISTENER_METADATA_KEYS, i as On, o as Listener, r as EventRegistry, s as isListener, t as EventsModule } from "../events-BhEQuT1X.mjs";
1
+ import { a as getListenerHandlers, c as LISTENER_METADATA_KEYS, i as On, o as Listener, r as EventRegistry, s as isListener, t as EventsModule } from "../events-GtwGEHyT.mjs";
2
2
  export { EventRegistry, EventsModule, LISTENER_METADATA_KEYS, Listener, On, getListenerHandlers, isListener };
@@ -1,9 +1,8 @@
1
- import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
- import { l as Singleton, p as inject, r as DI_TOKENS, u as Transient } from "./di-D7qmrAir.mjs";
3
- import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
4
- import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { _ as defineMetadata, l as Singleton, p as inject, r as DI_TOKENS, u as Transient, v as getMetadata } from "./di-DQ3xbjgf.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-C79yt3Wt.mjs";
5
4
  import { LOGGER_TOKENS } from "./logger/index.mjs";
6
- import { n as Module } from "./module.decorator-CYHY6pG5.mjs";
5
+ import { n as Module } from "./module.decorator-CYbrOlX9.mjs";
7
6
  //#region src/events/constants.ts
8
7
  /**
9
8
  * Metadata keys for event listener decorators.
@@ -202,4 +201,4 @@ EventsModule = __decorate([Module({ providers: [{
202
201
  //#endregion
203
202
  export { getListenerHandlers as a, LISTENER_METADATA_KEYS as c, On as i, events_module_exports as n, Listener as o, EventRegistry as r, isListener as s, EventsModule as t };
204
203
 
205
- //# sourceMappingURL=events-BhEQuT1X.mjs.map
204
+ //# sourceMappingURL=events-GtwGEHyT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-GtwGEHyT.mjs","names":[],"sources":["../src/events/constants.ts","../src/events/decorators/listener.decorator.ts","../src/events/decorators/on.decorator.ts","../src/events/event-registry.ts","../src/events/events.module.ts"],"sourcesContent":["/**\n * Metadata keys for event listener decorators.\n *\n * Uses `Symbol.for()` (global symbol registry) so that both core and\n * framework packages can reference the same symbols without cross-imports.\n */\nexport const LISTENER_METADATA_KEYS = {\n IS_LISTENER: Symbol.for('stratal:listener'),\n EVENT_HANDLERS: Symbol.for('stratal:listener:handlers'),\n} as const\n","import { Transient } from '../../di/decorators'\nimport { defineMetadata, getMetadata } from '../../di/metadata'\nimport type { Constructor } from '../../types'\nimport { LISTENER_METADATA_KEYS } from '../constants'\n\n/**\n * Mark a class as an event listener.\n *\n * Applies `@Transient()` for DI and sets metadata so the module system\n * can auto-discover and wire listener handlers at bootstrap time.\n *\n * @example\n * ```typescript\n * @Listener()\n * export class UserCreatedListener {\n * @On('after.User.create')\n * async sendWelcomeEmail(context: EventContext<'after.User.create'>) {\n * // ...\n * }\n * }\n * ```\n */\nexport function Listener() {\n return function <T extends Constructor>(target: T) {\n Transient()(target)\n defineMetadata(LISTENER_METADATA_KEYS.IS_LISTENER, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is decorated with `@Listener()`\n */\nexport function isListener(target: Constructor): boolean {\n return getMetadata(LISTENER_METADATA_KEYS.IS_LISTENER, target) === true\n}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { LISTENER_METADATA_KEYS } from '../constants'\nimport type { EventName, EventOptions, ListenerHandlerMetadata } from '../types'\n\n/**\n * Register a method as an event handler within a `@Listener()` class.\n *\n * Accumulates handler metadata on the class so the framework can\n * auto-wire handlers with the EventRegistry at bootstrap time.\n *\n * @param event - Event name to listen for (fully typed with autocomplete)\n * @param options - Optional handler options (priority, blocking)\n *\n * @example\n * ```typescript\n * @Listener()\n * export class AuditListener {\n * @On('after.User.create')\n * async logCreate(context: EventContext<'after.User.create'>) { ... }\n *\n * @On('after.User.delete', { priority: 10 })\n * async logDelete(context: EventContext<'after.User.delete'>) { ... }\n * }\n * ```\n */\nexport function On<E extends EventName>(event: E, options?: EventOptions) {\n return function (\n target: object,\n propertyKey: string,\n _descriptor: PropertyDescriptor\n ) {\n const existingHandlers: ListenerHandlerMetadata[] =\n getMetadata<ListenerHandlerMetadata[]>(LISTENER_METADATA_KEYS.EVENT_HANDLERS, target.constructor) ?? []\n\n existingHandlers.push({\n methodName: propertyKey,\n event: event,\n options,\n })\n\n defineMetadata(\n LISTENER_METADATA_KEYS.EVENT_HANDLERS,\n existingHandlers,\n target.constructor\n )\n }\n}\n\n/**\n * Get all `@On()` handler metadata from a listener class\n */\nexport function getListenerHandlers(target: object): ListenerHandlerMetadata[] {\n const metadataTarget = typeof target === 'function' ? target : target.constructor\n return getMetadata<ListenerHandlerMetadata[]>(LISTENER_METADATA_KEYS.EVENT_HANDLERS, metadataTarget) ?? []\n}\n","import { inject } from '../di'\nimport { Singleton } from '../di/decorators'\nimport { DI_TOKENS } from '../di/tokens'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type {\n EventContext,\n EventHandler,\n EventName,\n EventOptions,\n IEventRegistry,\n RegisteredHandler\n} from './types'\n\n@Singleton(DI_TOKENS.EventRegistry)\nexport class EventRegistry implements IEventRegistry {\n private handlers = new Map<string, RegisteredHandler[]>()\n\n constructor(\n @inject(DI_TOKENS.ExecutionContext) private readonly ctx: ExecutionContext,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) { }\n\n on<E extends EventName>(event: E, handler: EventHandler<E>, options?: EventOptions): void {\n const registered: RegisteredHandler = {\n handler: handler,\n priority: options?.priority ?? 0,\n blocking: options?.blocking\n }\n\n const existingHandlers = this.handlers.get(event) ?? []\n existingHandlers.push(registered)\n this.handlers.set(event, existingHandlers)\n\n this.logger.debug('Event handler registered', {\n event,\n priority: registered.priority,\n blocking: registered.blocking\n })\n }\n\n async emit<E extends EventName>(\n event: E,\n context?: Partial<EventContext<E>>\n ): Promise<void> {\n // Build full context with caller-provided fields\n const fullContext = {\n ...context\n } as EventContext<E>\n\n // Find matching handlers using pattern matching\n const matchingHandlers = this.findMatchingHandlers(event)\n\n if (matchingHandlers.length === 0) {\n return\n }\n\n // Sort by priority (higher first)\n const sortedHandlers = [...matchingHandlers].sort(\n (a, b) => b.priority - a.priority\n )\n\n // Determine if we should use waitUntil\n const shouldUseWaitUntil = this.shouldUseWaitUntil(event, sortedHandlers)\n\n // Execute handlers\n const promises = sortedHandlers.map((registered) =>\n this.executeHandler(registered.handler, fullContext, event)\n )\n\n if (shouldUseWaitUntil) {\n // Non-blocking: use ctx.waitUntil\n this.ctx.waitUntil(Promise.all(promises))\n } else {\n // Blocking: await all handlers\n await Promise.all(promises)\n }\n }\n\n off<E extends EventName>(event: E, handler: EventHandler<E>): void {\n const existingHandlers = this.handlers.get(event)\n if (!existingHandlers) return\n\n const filtered = existingHandlers.filter((h) => h.handler !== handler)\n if (filtered.length > 0) {\n this.handlers.set(event, filtered)\n } else {\n this.handlers.delete(event)\n }\n\n this.logger.debug('Event handler unregistered', { event })\n }\n\n hasListeners(event: EventName): boolean {\n return this.findMatchingHandlers(event).length > 0\n }\n\n once<E extends EventName>(event: E, handler: EventHandler<E>, options?: EventOptions): void {\n const wrappedHandler = (async (context: EventContext<E>) => {\n await handler(context)\n this.off(event, wrappedHandler)\n }) as EventHandler<E>\n\n this.on(event, wrappedHandler, options)\n }\n\n /**\n * Find all handlers matching the event using pattern matching.\n * Order: exact match -> model wildcard -> operation wildcard -> global wildcard\n */\n private findMatchingHandlers(event: string): RegisteredHandler[] {\n const handlers: RegisteredHandler[] = []\n\n const parts = event.split('.')\n\n if (parts.length === 3) {\n // Database event: \"phase.model.operation\"\n const [phase, model, operation] = parts\n\n // 1. Exact match: \"after.user.create\"\n handlers.push(...(this.handlers.get(event) ?? []))\n\n // 2. Model wildcard: \"after.user\"\n handlers.push(...(this.handlers.get(`${phase}.${model}`) ?? []))\n\n // 3. Operation wildcard: \"after.create\"\n handlers.push(...(this.handlers.get(`${phase}.${operation}`) ?? []))\n\n // 4. Global wildcard: \"after\"\n handlers.push(...(this.handlers.get(phase) ?? []))\n } else if (parts.length === 2) {\n // Could be wildcard like \"after.user\" or custom event like \"auth.verified\"\n handlers.push(...(this.handlers.get(event) ?? []))\n\n if (parts[0] === 'before' || parts[0] === 'after') {\n handlers.push(...(this.handlers.get(parts[0]) ?? []))\n }\n } else {\n handlers.push(...(this.handlers.get(event) ?? []))\n }\n\n return handlers\n }\n\n /**\n * Determine if we should use ctx.waitUntil (non-blocking) or await (blocking)\n */\n private shouldUseWaitUntil(\n event: string,\n handlers: RegisteredHandler[]\n ): boolean {\n const hasBlockingHandler = handlers.some((h) => h.blocking === true)\n if (hasBlockingHandler) return false\n\n const hasNonBlockingHandler = handlers.some((h) => h.blocking === false)\n if (hasNonBlockingHandler) return true\n\n const phase = event.split('.')[0]\n if (phase === 'before') return false\n if (phase === 'after') return true\n return false // Custom events block by default\n }\n\n /**\n * Execute a single handler with error isolation\n */\n private async executeHandler<E extends EventName>(\n handler: EventHandler,\n context: EventContext<E>,\n event: string\n ): Promise<void> {\n try {\n await handler(context)\n } catch (error) {\n this.logger.error('Event handler error', {\n event,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n }\n }\n}\n","import { DI_TOKENS } from '../di/tokens'\nimport { Module } from '../module/module.decorator'\nimport { EventRegistry } from './event-registry'\n\n/**\n * Registers the event registry (`DI_TOKENS.EventRegistry`).\n *\n * Lazy: loaded on demand via `LazyModuleLoader` — by the framework's\n * `DatabaseModule` (which needs it to wire DB event emission) and by the\n * application's event-listener trigger paths. Kept out of cold start for apps\n * that neither emit events nor use the database.\n */\n@Module({\n providers: [\n { provide: DI_TOKENS.EventRegistry, useClass: EventRegistry },\n ],\n})\nexport class EventsModule { }\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { b as ROUTER_TOKENS, y as ContainerError } from "./di-D7qmrAir.mjs";
1
+ import { C as ROUTER_TOKENS, S as ContainerError } from "./di-DQ3xbjgf.mjs";
2
2
  import { t as Macroable } from "./macroable-cvDTFZ_A.mjs";
3
3
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
4
4
  import { stream, streamSSE, streamText } from "hono/streaming";
@@ -9,7 +9,8 @@ import { stream, streamSSE, streamText } from "hono/streaming";
9
9
  */
10
10
  const ROUTER_CONTEXT_KEYS = {
11
11
  REQUEST_CONTAINER: "requestContainer",
12
- LOCALE: "locale"
12
+ LOCALE: "locale",
13
+ RESPONSE_PAYLOAD: "responsePayload"
13
14
  };
14
15
  /**
15
16
  * Metadata keys for storing route and controller configuration
@@ -26,7 +27,9 @@ const ROUTE_METADATA_KEYS = {
26
27
  WS_ON_MESSAGE: Symbol.for("stratal:ws:on-message"),
27
28
  WS_ON_CLOSE: Symbol.for("stratal:ws:on-close"),
28
29
  WS_ON_ERROR: Symbol.for("stratal:ws:on-error"),
29
- RATE_LIMIT: Symbol.for("stratal:route:rate-limit")
30
+ RATE_LIMIT: Symbol.for("stratal:route:rate-limit"),
31
+ CACHEABLE: Symbol.for("stratal:route:cacheable"),
32
+ PURGES_CACHE: Symbol.for("stratal:route:purges-cache")
30
33
  };
31
34
  /**
32
35
  * Security scheme identifiers for OpenAPI
@@ -148,7 +151,10 @@ var RouterContext = class extends Macroable {
148
151
  return container;
149
152
  }
150
153
  /**
151
- * Set locale for the current request
154
+ * Override the locale for the current request (e.g. force a specific locale
155
+ * for this response). Request-scoped only — it does not persist. Persistence
156
+ * is the detection layer's job: cookie-strategy paths auto-persist the
157
+ * `locale` cookie (scoped via the config's `cookieOptions`).
152
158
  *
153
159
  * @param locale - Locale code (e.g., 'en', 'fr')
154
160
  */
@@ -161,7 +167,7 @@ var RouterContext = class extends Macroable {
161
167
  * @returns Current locale code
162
168
  */
163
169
  getLocale() {
164
- return this.c.get(ROUTER_CONTEXT_KEYS.LOCALE) || "en";
170
+ return this.c.get(ROUTER_CONTEXT_KEYS.LOCALE) ?? "en";
165
171
  }
166
172
  /**
167
173
  * Return JSON response
@@ -185,7 +191,7 @@ var RouterContext = class extends Macroable {
185
191
  * @param key - Query parameter name
186
192
  */
187
193
  query(key) {
188
- const validated = this.c.req.valid("query");
194
+ const validated = this.c.req.valid("query") ?? {};
189
195
  return key ? validated[key] : validated;
190
196
  }
191
197
  /**
@@ -426,4 +432,4 @@ function createCliExceptionContext(commandName) {
426
432
  //#endregion
427
433
  export { RouterContext as a, METHOD_STATUS_CODES as c, SECURITY_SCHEMES as d, VERSION_NEUTRAL as f, createQueueExceptionContext as i, ROUTER_CONTEXT_KEYS as l, createCronExceptionContext as n, DEFAULT_CONTENT_TYPE as o, createHttpExceptionContext as r, HTTP_METHODS as s, createCliExceptionContext as t, ROUTE_METADATA_KEYS as u };
428
434
 
429
- //# sourceMappingURL=exception-context-D-kvney-.mjs.map
435
+ //# sourceMappingURL=exception-context-CdnGTQNF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exception-context-CdnGTQNF.mjs","names":["honoGetCookie","honoDeleteCookie","honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts","../src/errors/exception-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale',\n RESPONSE_PAYLOAD: 'responsePayload',\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n RATE_LIMIT: Symbol.for('stratal:route:rate-limit'),\n CACHEABLE: Symbol.for('stratal:route:cacheable'),\n PURGES_CACHE: Symbol.for('stratal:route:purges-cache'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport {\n deleteCookie as honoDeleteCookie,\n getCookie as honoGetCookie,\n setCookie as honoSetCookie,\n} from 'hono/cookie'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { ContainerError } from '../di/container.error'\nimport { Macroable } from '../macroable'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouteName, RouteParams } from './route-map'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { RouterEnv } from './types'\nimport type { SignedUriOptions, Uri, UriOptions } from './uri'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> extends Macroable {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) {\n super()\n }\n\n /**\n * Cloudflare-provided request properties (geo, TLS, bot management, etc.).\n * Always available on Cloudflare Workers requests via `c.req.raw.cf`.\n */\n get cf(): CfProperties {\n return this.c.req.raw.cf!\n }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new ContainerError('Request container has not been initialized')\n }\n return container as Container\n }\n\n /**\n * Override the locale for the current request (e.g. force a specific locale\n * for this response). Request-scoped only — it does not persist. Persistence\n * is the detection layer's job: cookie-strategy paths auto-persist the\n * `locale` cookie (scoped via the config's `cookieOptions`).\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale: string | undefined = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return locale ?? 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value(s).\n *\n * Reads the validated, Zod-coerced param record from `c.req.valid('param')`,\n * which is what `@hono/zod-openapi` populates for every route registered\n * via `app.openapi(...)`. Bare `c.req.param()` returns `undefined` for those\n * routes — always go through the validated record.\n *\n * - With a key → returns the single string value.\n * - With no args → returns the full `Record<string, string>` (or `{}` when\n * the matched route has no path params).\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(): Record<string, string>\n param(key: string): string\n param(key?: string): string | Record<string, string> {\n const all = (this.c.req as unknown as { valid(target: 'param'): Record<string, string> | undefined }).valid('param') ?? {}\n return key === undefined ? all : all[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n // Routes without a declared query schema attach no validator, so\n // `valid('query')` is unset — default to an empty record.\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> | undefined }).valid('query') ?? {}\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Read a cookie value from the current request.\n *\n * @param name - Cookie name\n * @returns The cookie value, or `undefined` if the cookie is not present\n *\n * @example\n * ```typescript\n * const redirectTo = ctx.getCookie('redirectTo')\n * ```\n */\n getCookie(name: string): string | undefined {\n return honoGetCookie(this.c, name)\n }\n\n /**\n * Set a cookie on the response.\n *\n * Cookie operations must run while the response is mutable — call this\n * before returning the final `Response` from the handler.\n *\n * @param name - Cookie name\n * @param value - Cookie value\n * @param options - Cookie attributes (httpOnly, secure, sameSite, path, etc.)\n *\n * @example\n * ```typescript\n * ctx.setCookie('redirectTo', '/app/', {\n * httpOnly: true,\n * secure: true,\n * sameSite: 'lax',\n * path: '/',\n * })\n * ```\n */\n setCookie(name: string, value: string, options?: CookieOptions): void {\n honoSetCookie(this.c, name, value, options)\n }\n\n /**\n * Delete a cookie from the response.\n *\n * Pass the same `path` and `domain` options that were used when the cookie\n * was set, otherwise the browser will not clear the matching cookie.\n *\n * @param name - Cookie name\n * @param options - Cookie attributes used at set time (path, domain, etc.)\n * @returns The deleted cookie's previous value, or `undefined`\n *\n * @example\n * ```typescript\n * ctx.deleteCookie('redirectTo', { path: '/' })\n * ```\n */\n deleteCookie(name: string, options?: CookieOptions): string | undefined {\n return honoDeleteCookie(this.c, name, options)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params are consumed from the same object.\n * Extra keys become query string parameters.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options (e.g., `{ absolute: true }`)\n *\n * @example\n * ```typescript\n * ctx.route('users.show', { id: '1' }) // '/v1/users/1'\n * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'\n * ```\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n return this.resolveUri().route(name, params, options)\n }\n\n /**\n * Get a domain parameter value from the current request.\n * Domain params are set by the domain matching middleware.\n *\n * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * const tenant = ctx.domain('tenant')\n * ```\n */\n domain(key: string): string {\n return this.c.get(`domain:${key}`) as string\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params (same as route())\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n */\n async signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n return this.resolveUri().signedRoute(name, params, options)\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 return this.resolveUri().hasValidSignature()\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n\n private resolveUri(): Uri {\n return this.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n }\n}\n","import type { Context } from 'hono'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\n\n/**\n * Exception context for errors occurring during HTTP request handling.\n *\n * Provides access to the full {@link RouterContext} for building responses\n * with `ctx.json()`, `ctx.text()`, `ctx.html()`, etc.\n */\nexport interface HttpExceptionContext {\n readonly type: 'http'\n /** Stratal RouterContext — use for building HTTP responses */\n readonly ctx: RouterContext\n}\n\n/**\n * Exception context for errors occurring during queue message processing.\n */\nexport interface QueueExceptionContext {\n readonly type: 'queue'\n /** Name of the queue being processed */\n readonly queueName: string\n}\n\n/**\n * Exception context for errors occurring during scheduled cron execution.\n */\nexport interface CronExceptionContext {\n readonly type: 'cron'\n}\n\n/**\n * Exception context for errors occurring during CLI command execution.\n */\nexport interface CliExceptionContext {\n readonly type: 'cli'\n /** Name of the command that threw */\n readonly commandName: string\n}\n\n/**\n * Discriminated union of all exception context types.\n *\n * Narrow via `ctx.type` to access context-specific properties:\n *\n * @example\n * ```typescript\n * handler.renderable(MyError, (error, ctx) => {\n * if (ctx.type === 'http') {\n * return ctx.ctx.json({ message: 'Something went wrong' }, 500)\n * }\n * // Non-HTTP contexts: return undefined to use default rendering\n * })\n * ```\n */\nexport type ExceptionContext =\n | HttpExceptionContext\n | QueueExceptionContext\n | CronExceptionContext\n | CliExceptionContext\n\n/**\n * Create an HTTP exception context from a Hono context.\n *\n * @param c - The raw Hono context from the request\n * @returns An {@link HttpExceptionContext} wrapping a RouterContext\n */\nexport function createHttpExceptionContext(c: Context<RouterEnv>): HttpExceptionContext {\n return { type: 'http', ctx: new RouterContext(c) }\n}\n\n/**\n * Create a queue exception context.\n *\n * @param queueName - The name of the queue being processed\n * @returns A {@link QueueExceptionContext}\n */\nexport function createQueueExceptionContext(queueName: string): QueueExceptionContext {\n return { type: 'queue', queueName }\n}\n\n/**\n * Create a cron exception context.\n *\n * @returns A {@link CronExceptionContext}\n */\nexport function createCronExceptionContext(): CronExceptionContext {\n return { type: 'cron' }\n}\n\n/**\n * Create a CLI command exception context.\n *\n * @param commandName - The name of the command that threw\n * @returns A {@link CliExceptionContext}\n */\nexport function createCliExceptionContext(commandName: string): CliExceptionContext {\n return { type: 'cli', commandName }\n}\n"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
- import { a as ApplicationError } from "./container-storage-BmOJ4_Na.mjs";
2
- import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
1
+ import { _ as defineMetadata, v as getMetadata } from "./di-DQ3xbjgf.mjs";
2
+ import { a as ApplicationError } from "./container-storage-DfF7SXdV.mjs";
3
3
  import { LOGGER_TOKENS } from "./logger/index.mjs";
4
- import "./errors-C01O2T-n.mjs";
5
- import { a as RouterContext, u as ROUTE_METADATA_KEYS } from "./exception-context-D-kvney-.mjs";
6
- import { t as Controller } from "./controller.decorator-YSTPQntu.mjs";
4
+ import { a as RouterContext, u as ROUTE_METADATA_KEYS } from "./exception-context-CdnGTQNF.mjs";
5
+ import { t as Controller } from "./controller.decorator-BB0JcwMg.mjs";
7
6
  //#region src/websocket/decorators/gateway.decorator.ts
8
7
  const GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER;
9
8
  /**
@@ -48,7 +47,8 @@ function Gateway(route, options) {
48
47
  * @returns true if the class is decorated with @Gateway
49
48
  */
50
49
  function isGateway(target) {
51
- return getMetadata(GATEWAY_MARKER_KEY, typeof target === "function" ? target : target.constructor) === true;
50
+ const metadataTarget = typeof target === "function" ? target : target.constructor;
51
+ return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true;
52
52
  }
53
53
  //#endregion
54
54
  //#region src/websocket/websocket.error.ts
@@ -222,4 +222,4 @@ var GatewayContext = class extends RouterContext {
222
222
  //#endregion
223
223
  export { getWsOnCloseMethod as a, WebSocketError as c, OnMessage as i, Gateway as l, OnClose as n, getWsOnErrorMethod as o, OnError as r, getWsOnMessageMethod as s, GatewayContext as t, isGateway as u };
224
224
 
225
- //# sourceMappingURL=gateway-context-m7kEzRa2.mjs.map
225
+ //# sourceMappingURL=gateway-context-Cmc1NRS0.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-context-m7kEzRa2.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */\nconst WS_OPEN = 1\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /**\n * Send only if the socket is still open. Returns `false` (and logs a warning)\n * when the socket is closing/closed — e.g. inside `@OnError`, which fires on a\n * transport error after the socket is already dead, or after an `await` in\n * `@OnMessage` when the client disconnected mid-handler. Use this for\n * fire-and-forget acks/errors instead of `send()`, which throws on a closed\n * socket (\"Can't call WebSocket send() after close()\").\n */\n trySend(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): boolean {\n if (this.ws.readyState !== WS_OPEN) {\n this.getContainer()\n .resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n .warn('Skipped WebSocket send on non-open socket', { readyState: this.ws.readyState })\n return false\n }\n this.ws.send(data)\n return true\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,OAAO,EAAE,MAAM;EACjC,eAAe,oBAAoB,MAAM,MAAM;EAC/C,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,UAAU,QAAyB;CAEjD,OAAO,YAAY,oBADI,OAAO,WAAW,aAAa,SAAU,OAAmC,WAC9C,MAAM;AAC7D;;;ACnDA,IAAa,iBAAb,cAAoC,iBAAiB,CAAC;;;ACGtD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,MAAM;CACzD,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,QAAQ,EAAE,wBAAwB;CAEpH,eAAe,KAAK,aAAa,MAAM;AACzC;;;;;;;;;;;;;;;AAgBA,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,WAAW;CAClF;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;AAKA,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,SAAmB;AAC1E;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AC7FA,MAAM,UAAU;;;;;;;;;;;;;;;;;;AAmBhB,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,CAAC;EAD0C,KAAA,KAAA;CAEnD;;CAGA,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,IAAI;CACnB;;;;;;;;;CAUA,QAAQ,MAA+D;EACrE,IAAI,KAAK,GAAG,eAAe,SAAS;GAClC,KAAK,aAAa,EACf,QAAuB,cAAc,aAAa,EAClD,KAAK,6CAA6C,EAAE,YAAY,KAAK,GAAG,WAAW,CAAC;GACvF,OAAO;EACT;EACA,KAAK,GAAG,KAAK,IAAI;EACjB,OAAO;CACT;;CAGA,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,MAAM;CAC5B;;CAGA,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;CACjB;CAaA,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,CAAC;EACrD,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;CAC7B;;;;;;CAOA,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;EAE7B,OAAO,KAAK,EAAE,IAAI,MAAM;CAC1B;;;;;;CAOA,OAA+B;EAC7B,MAAM,IAAI,eAAe,qDAAqD;CAChF;AACF"}
1
+ {"version":3,"file":"gateway-context-Cmc1NRS0.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */\nconst WS_OPEN = 1\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /**\n * Send only if the socket is still open. Returns `false` (and logs a warning)\n * when the socket is closing/closed — e.g. inside `@OnError`, which fires on a\n * transport error after the socket is already dead, or after an `await` in\n * `@OnMessage` when the client disconnected mid-handler. Use this for\n * fire-and-forget acks/errors instead of `send()`, which throws on a closed\n * socket (\"Can't call WebSocket send() after close()\").\n */\n trySend(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): boolean {\n if (this.ws.readyState !== WS_OPEN) {\n this.getContainer()\n .resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n .warn('Skipped WebSocket send on non-open socket', { readyState: this.ws.readyState })\n return false\n }\n this.ws.send(data)\n return true\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,OAAO,CAAC,CAAC,MAAM;EACjC,eAAe,oBAAoB,MAAM,MAAM;EAC/C,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,UAAU,QAAyB;CACjD,MAAM,iBAAiB,OAAO,WAAW,aAAa,SAAU,OAAmC;CACnG,OAAO,YAAY,oBAAoB,cAAc,MAAM;AAC7D;;;ACnDA,IAAa,iBAAb,cAAoC,iBAAiB,CAAC;;;ACGtD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,MAAM;CACzD,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,QAAQ,EAAE,wBAAwB;CAEpH,eAAe,KAAK,aAAa,MAAM;AACzC;;;;;;;;;;;;;;;AAgBA,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,WAAW;CAClF;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;AAKA,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,SAAmB;AAC1E;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AC7FA,MAAM,UAAU;;;;;;;;;;;;;;;;;;AAmBhB,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,CAAC;EAD0C,KAAA,KAAA;CAEnD;;CAGA,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,IAAI;CACnB;;;;;;;;;CAUA,QAAQ,MAA+D;EACrE,IAAI,KAAK,GAAG,eAAe,SAAS;GAClC,KAAK,aAAa,CAAC,CAChB,QAAuB,cAAc,aAAa,CAAC,CACnD,KAAK,6CAA6C,EAAE,YAAY,KAAK,GAAG,WAAW,CAAC;GACvF,OAAO;EACT;EACA,KAAK,GAAG,KAAK,IAAI;EACjB,OAAO;CACT;;CAGA,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,MAAM;CAC5B;;CAGA,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;CACjB;CAaA,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,CAAC;EACrD,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;CAC7B;;;;;;CAOA,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;EAE7B,OAAO,KAAK,EAAE,IAAI,MAAM;CAC1B;;;;;;CAOA,OAA+B;EAC7B,MAAM,IAAI,eAAe,qDAAqD;CAChF;AACF"}
@@ -0,0 +1,53 @@
1
+ //#region src/response-cache/gateway-mode.ts
2
+ /**
3
+ * Contexts that Stratal itself dispatched as the **gateway** entrypoint.
4
+ *
5
+ * The gateway and the cached entrypoint run the *same* Hono app, so the
6
+ * dispatch middleware needs to know which of the two it is running inside. That
7
+ * signal must not be forgeable: a header, a query parameter, or a value read
8
+ * out of `ctx.props` is all attacker-influenced, and getting it wrong in the
9
+ * cached entrypoint means an infinite loopback; getting it wrong in the gateway
10
+ * means a partitioned response served from the wrong entrypoint's cache.
11
+ *
12
+ * So the mark lives here, in a module-private `WeakSet`, keyed on the
13
+ * `ExecutionContext` object the runtime handed to `Stratal.fetch`. Nothing
14
+ * reachable from a request can add to it, and entries are collected with the
15
+ * context they mark.
16
+ *
17
+ * A `WeakSet` rather than a symbol property on a wrapper object, which is what
18
+ * the design sketched, for two reasons:
19
+ *
20
+ * - `ExecutionContext` is a host object with `readonly exports`, `readonly
21
+ * props`, `cache`, `access`, and `tracing`. Re-creating it as a literal means
22
+ * enumerating those members by hand and silently dropping whichever ones the
23
+ * runtime adds next; eagerly reading `exports` in the wrapper would also
24
+ * throw on any Worker without the `enable_ctx_exports` compatibility flag,
25
+ * i.e. every app that doesn't use this feature.
26
+ * - Assigning a symbol onto the runtime's own object mutates something we don't
27
+ * own, and throws outright under ESM strict mode if it is ever frozen.
28
+ *
29
+ * The `WeakSet` needs neither: the context passes through untouched.
30
+ */
31
+ const GATEWAY_CONTEXTS = /* @__PURE__ */ new WeakSet();
32
+ /**
33
+ * Mark an execution context as running in gateway mode.
34
+ *
35
+ * Called by `Stratal.fetch` (the default export — the eyeball entrypoint) and
36
+ * by `@stratal/testing`, which drives `HonoApp#fetch` directly. Deliberately
37
+ * **not** called by `cachedEntrypoint`, which is what stops the cached
38
+ * entrypoint from dispatching back into itself.
39
+ *
40
+ * Returns the same object it was given, so it can be used inline.
41
+ */
42
+ function markGatewayMode(ctx) {
43
+ GATEWAY_CONTEXTS.add(ctx);
44
+ return ctx;
45
+ }
46
+ /** Whether this execution context was marked by {@link markGatewayMode}. */
47
+ function isGatewayMode(ctx) {
48
+ return typeof ctx === "object" && ctx !== null && GATEWAY_CONTEXTS.has(ctx);
49
+ }
50
+ //#endregion
51
+ export { markGatewayMode as n, isGatewayMode as t };
52
+
53
+ //# sourceMappingURL=gateway-mode-0rUaeW3g.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-mode-0rUaeW3g.mjs","names":[],"sources":["../src/response-cache/gateway-mode.ts"],"sourcesContent":["/**\n * Contexts that Stratal itself dispatched as the **gateway** entrypoint.\n *\n * The gateway and the cached entrypoint run the *same* Hono app, so the\n * dispatch middleware needs to know which of the two it is running inside. That\n * signal must not be forgeable: a header, a query parameter, or a value read\n * out of `ctx.props` is all attacker-influenced, and getting it wrong in the\n * cached entrypoint means an infinite loopback; getting it wrong in the gateway\n * means a partitioned response served from the wrong entrypoint's cache.\n *\n * So the mark lives here, in a module-private `WeakSet`, keyed on the\n * `ExecutionContext` object the runtime handed to `Stratal.fetch`. Nothing\n * reachable from a request can add to it, and entries are collected with the\n * context they mark.\n *\n * A `WeakSet` rather than a symbol property on a wrapper object, which is what\n * the design sketched, for two reasons:\n *\n * - `ExecutionContext` is a host object with `readonly exports`, `readonly\n * props`, `cache`, `access`, and `tracing`. Re-creating it as a literal means\n * enumerating those members by hand and silently dropping whichever ones the\n * runtime adds next; eagerly reading `exports` in the wrapper would also\n * throw on any Worker without the `enable_ctx_exports` compatibility flag,\n * i.e. every app that doesn't use this feature.\n * - Assigning a symbol onto the runtime's own object mutates something we don't\n * own, and throws outright under ESM strict mode if it is ever frozen.\n *\n * The `WeakSet` needs neither: the context passes through untouched.\n */\nconst GATEWAY_CONTEXTS = new WeakSet<object>()\n\n/**\n * Mark an execution context as running in gateway mode.\n *\n * Called by `Stratal.fetch` (the default export — the eyeball entrypoint) and\n * by `@stratal/testing`, which drives `HonoApp#fetch` directly. Deliberately\n * **not** called by `cachedEntrypoint`, which is what stops the cached\n * entrypoint from dispatching back into itself.\n *\n * Returns the same object it was given, so it can be used inline.\n */\nexport function markGatewayMode<T extends object>(ctx: T): T {\n GATEWAY_CONTEXTS.add(ctx)\n return ctx\n}\n\n/** Whether this execution context was marked by {@link markGatewayMode}. */\nexport function isGatewayMode(ctx: unknown): boolean {\n return typeof ctx === 'object' && ctx !== null && GATEWAY_CONTEXTS.has(ctx)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,mCAAmB,IAAI,QAAgB;;;;;;;;;;;AAY7C,SAAgB,gBAAkC,KAAW;CAC3D,iBAAiB,IAAI,GAAG;CACxB,OAAO;AACT;;AAGA,SAAgB,cAAc,KAAuB;CACnD,OAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,iBAAiB,IAAI,GAAG;AAC5E"}