stratal 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/cloudflare-workers-loader.mjs +80 -7
  3. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  4. package/dist/bin/quarry.mjs +41 -54
  5. package/dist/bin/quarry.mjs.map +1 -1
  6. package/dist/cache/index.d.mts +5 -3
  7. package/dist/cache/index.d.mts.map +1 -1
  8. package/dist/cache/index.mjs +123 -39
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/{cache.service-e34gV6tz.d.mts → cache.service-uElmBtdS.d.mts} +24 -34
  11. package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
  12. package/dist/{command-BU4ApTo5.mjs → command-BvmUAPPQ.mjs} +15 -3
  13. package/dist/command-BvmUAPPQ.mjs.map +1 -0
  14. package/dist/{command-wXfvHbBZ.d.mts → command-CPhFHjG3.d.mts} +2 -2
  15. package/dist/command-CPhFHjG3.d.mts.map +1 -0
  16. package/dist/command-not-found.error-ONAZ2Bpk.mjs +14 -0
  17. package/dist/command-not-found.error-ONAZ2Bpk.mjs.map +1 -0
  18. package/dist/config/index.d.mts +3 -3
  19. package/dist/config/index.d.mts.map +1 -1
  20. package/dist/config/index.mjs +7 -6
  21. package/dist/config/index.mjs.map +1 -1
  22. package/dist/{consumer-registry-DHQtypr1.d.mts → consumer-registry-D3iMTSdy.d.mts} +54 -22
  23. package/dist/consumer-registry-D3iMTSdy.d.mts.map +1 -0
  24. package/dist/{container-storage-GpNNz79X.mjs → container-storage-BmOJ4_Na.mjs} +1 -1
  25. package/dist/{container-storage-GpNNz79X.mjs.map → container-storage-BmOJ4_Na.mjs.map} +1 -1
  26. package/dist/{controller.decorator-DIUazNU7.mjs → controller.decorator-C5UVeJS3.mjs} +4 -4
  27. package/dist/{controller.decorator-DIUazNU7.mjs.map → controller.decorator-C5UVeJS3.mjs.map} +1 -1
  28. package/dist/cron/index.d.mts +79 -4
  29. package/dist/cron/index.d.mts.map +1 -1
  30. package/dist/cron/index.mjs +2 -2
  31. package/dist/cron-job-NesZRk8F.d.mts +58 -0
  32. package/dist/cron-job-NesZRk8F.d.mts.map +1 -0
  33. package/dist/{cron-manager-9bpN9bu4.mjs → cron.module-Bgzq5hiT.mjs} +17 -7
  34. package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
  35. package/dist/{decorate-HgTKAYK8.mjs → decorate-CuAoSZvs.mjs} +2 -2
  36. package/dist/{deep-merge-C8NgcXw4.mjs → deep-merge-ByiAOZ3r.mjs} +1 -1
  37. package/dist/{deep-merge-C8NgcXw4.mjs.map → deep-merge-ByiAOZ3r.mjs.map} +1 -1
  38. package/dist/di/index.d.mts +2 -2
  39. package/dist/di/index.mjs +3 -3
  40. package/dist/{di-BO1QIb5H.mjs → di-DseMn-z9.mjs} +244 -135
  41. package/dist/di-DseMn-z9.mjs.map +1 -0
  42. package/dist/email/index.d.mts +33 -40
  43. package/dist/email/index.d.mts.map +1 -1
  44. package/dist/email/index.mjs +456 -41
  45. package/dist/email/index.mjs.map +1 -1
  46. package/dist/{en-BPP6h6y5.mjs → en-CDZBMcc1.mjs} +2 -2
  47. package/dist/{en-BPP6h6y5.mjs.map → en-CDZBMcc1.mjs.map} +1 -1
  48. package/dist/{env-DKSbuBi5.d.mts → env-ug22bJj7.d.mts} +1 -1
  49. package/dist/env-ug22bJj7.d.mts.map +1 -0
  50. package/dist/errors/index.d.mts +1 -1
  51. package/dist/errors/index.mjs +3 -3
  52. package/dist/{errors-BBZTnjdq.mjs → errors-mXYxG0XB.mjs} +5 -5
  53. package/dist/{errors-BBZTnjdq.mjs.map → errors-mXYxG0XB.mjs.map} +1 -1
  54. package/dist/events/index.d.mts +14 -3
  55. package/dist/events/index.d.mts.map +1 -1
  56. package/dist/events/index.mjs +2 -2
  57. package/dist/{events-D1KdDaiP.mjs → events-BXJGZjpG.mjs} +16 -6
  58. package/dist/events-BXJGZjpG.mjs.map +1 -0
  59. package/dist/{exception-context-B4kM-M53.mjs → exception-context-kEoMFwze.mjs} +3 -3
  60. package/dist/{exception-context-B4kM-M53.mjs.map → exception-context-kEoMFwze.mjs.map} +1 -1
  61. package/dist/{gateway-context-CFe6a9gz.mjs → gateway-context-TMu_AlJt.mjs} +25 -6
  62. package/dist/{gateway-context-CFe6a9gz.mjs.map → gateway-context-TMu_AlJt.mjs.map} +1 -1
  63. package/dist/guards/index.d.mts +3 -3
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +1 -1
  66. package/dist/{guards-Ced-uNIF.mjs → guards-DALPXy3_.mjs} +2 -2
  67. package/dist/{guards-Ced-uNIF.mjs.map → guards-DALPXy3_.mjs.map} +1 -1
  68. package/dist/hono-app-CvV3hOfT.mjs +161 -0
  69. package/dist/hono-app-CvV3hOfT.mjs.map +1 -0
  70. package/dist/{http-method.decorator-CdjKFJZZ.mjs → http-method.decorator-ByWZb9DO.mjs} +4 -4
  71. package/dist/{http-method.decorator-CdjKFJZZ.mjs.map → http-method.decorator-ByWZb9DO.mjs.map} +1 -1
  72. package/dist/i18n/index.d.mts +4 -4
  73. package/dist/i18n/index.d.mts.map +1 -1
  74. package/dist/i18n/index.mjs +5 -5
  75. package/dist/i18n/index.mjs.map +1 -1
  76. package/dist/i18n/messages/en/index.d.mts +1 -1
  77. package/dist/i18n/messages/en/index.mjs +1 -1
  78. package/dist/i18n/utils/index.mjs +1 -1
  79. package/dist/i18n/validation/index.d.mts +3 -3
  80. package/dist/i18n/validation/index.mjs +3 -3
  81. package/dist/{i18n.module-BlXrtAlV.mjs → i18n.module-DRQAZoSZ.mjs} +14 -11
  82. package/dist/{i18n.module-BlXrtAlV.mjs.map → i18n.module-DRQAZoSZ.mjs.map} +1 -1
  83. package/dist/{i18n.tokens-hwRpmjRq.mjs → i18n.tokens-CZ_v8oyS.mjs} +1 -1
  84. package/dist/{i18n.tokens-hwRpmjRq.mjs.map → i18n.tokens-CZ_v8oyS.mjs.map} +1 -1
  85. package/dist/{index-B4UBK-2T.d.mts → index-0ItCjaqw.d.mts} +1 -1
  86. package/dist/index-0ItCjaqw.d.mts.map +1 -0
  87. package/dist/{index-CW1YHSft.d.mts → index-B5JBRcWD.d.mts} +249 -103
  88. package/dist/index-B5JBRcWD.d.mts.map +1 -0
  89. package/dist/{index-BtlE9RuO.d.mts → index-BUt92sAE.d.mts} +1 -1
  90. package/dist/index-BUt92sAE.d.mts.map +1 -0
  91. package/dist/{index-DEncMcC6.d.mts → index-B_JoEl3V.d.mts} +221 -16
  92. package/dist/index-B_JoEl3V.d.mts.map +1 -0
  93. package/dist/{index-Dj5IMwtr.d.mts → index-DtBNIFuP.d.mts} +4 -6
  94. package/dist/index-DtBNIFuP.d.mts.map +1 -0
  95. package/dist/{index-KMgSCSM7.d.mts → index-HgOLNruQ.d.mts} +1 -1
  96. package/dist/{index-KMgSCSM7.d.mts.map → index-HgOLNruQ.d.mts.map} +1 -1
  97. package/dist/index.d.mts +6 -5
  98. package/dist/index.mjs +3 -2
  99. package/dist/{is-command-CX5rAfZW.mjs → is-command-CEPO9n8c.mjs} +2 -2
  100. package/dist/{is-command-CX5rAfZW.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
  101. package/dist/{is-seeder-CYCtELlm.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
  102. package/dist/{is-seeder-CYCtELlm.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
  103. package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
  104. package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
  105. package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
  106. package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
  107. package/dist/locale-url-nZrZxqJP.mjs +44 -0
  108. package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
  109. package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
  110. package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
  111. package/dist/logger/index.d.mts +1 -1
  112. package/dist/logger/index.mjs +2 -2
  113. package/dist/logger/index.mjs.map +1 -1
  114. package/dist/macroable/index.d.mts +2 -2
  115. package/dist/macroable/index.mjs +1 -1
  116. package/dist/{macroable-DzlfzT50.mjs → macroable-cvDTFZ_A.mjs} +1 -1
  117. package/dist/{macroable-DzlfzT50.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
  118. package/dist/{metadata-BVkc4aUu.mjs → metadata-DzzprcID.mjs} +1 -1
  119. package/dist/{metadata-BVkc4aUu.mjs.map → metadata-DzzprcID.mjs.map} +1 -1
  120. package/dist/module/index.d.mts +4 -3
  121. package/dist/module/index.d.mts.map +1 -1
  122. package/dist/module/index.mjs +10 -2
  123. package/dist/module/index.mjs.map +1 -0
  124. package/dist/{module-xYoHba6B.mjs → module-registry-Dm-pqHd3.mjs} +189 -57
  125. package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
  126. package/dist/module.decorator-CYHY6pG5.mjs +19 -0
  127. package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
  128. package/dist/openapi/index.d.mts +44 -8
  129. package/dist/openapi/index.d.mts.map +1 -1
  130. package/dist/openapi/index.mjs +3 -2
  131. package/dist/{openapi-C6lm0RmV.mjs → openapi-CstuTM8S.mjs} +55 -229
  132. package/dist/openapi-CstuTM8S.mjs.map +1 -0
  133. package/dist/openapi-tools.service-BC5EC3R3.mjs +206 -0
  134. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
  135. package/dist/{openapi.service-CrLlsXAd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
  136. package/dist/{openapi.service-CrLlsXAd.d.mts.map → openapi.service-YhTiJ1bO.d.mts.map} +1 -1
  137. package/dist/quarry/index.d.mts +14 -5
  138. package/dist/quarry/index.d.mts.map +1 -1
  139. package/dist/quarry/index.mjs +6 -5
  140. package/dist/quarry/runner.d.mts +11 -11
  141. package/dist/quarry/runner.d.mts.map +1 -1
  142. package/dist/quarry/runner.mjs +192 -22
  143. package/dist/quarry/runner.mjs.map +1 -1
  144. package/dist/{quarry-registry-D4hIGScf.d.mts → quarry-registry-CXg0RFXq.d.mts} +4 -4
  145. package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
  146. package/dist/{quarry-registry-DkraZNwn.mjs → quarry.module-BuRPGMDm.mjs} +22 -21
  147. package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
  148. package/dist/queue/index.d.mts +3 -3
  149. package/dist/queue/index.mjs +42 -31
  150. package/dist/queue/index.mjs.map +1 -1
  151. package/dist/queue.module-nddvxzCB.mjs +613 -0
  152. package/dist/queue.module-nddvxzCB.mjs.map +1 -0
  153. package/dist/queue.tokens-DjHnFmre.mjs +11 -0
  154. package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
  155. package/dist/{r2-storage.provider-Hfm6LdZQ.mjs → r2-storage.provider-DCxQt9dD.mjs} +4 -4
  156. package/dist/{r2-storage.provider-Hfm6LdZQ.mjs.map → r2-storage.provider-DCxQt9dD.mjs.map} +1 -1
  157. package/dist/{rate-limit.decorator-D69zdZbp.mjs → rate-limit.decorator-BPAie_p3.mjs} +3 -3
  158. package/dist/{rate-limit.decorator-D69zdZbp.mjs.map → rate-limit.decorator-BPAie_p3.mjs.map} +1 -1
  159. package/dist/rate-limiter/index.d.mts +5 -5
  160. package/dist/rate-limiter/index.d.mts.map +1 -1
  161. package/dist/rate-limiter/index.mjs +26 -21
  162. package/dist/rate-limiter/index.mjs.map +1 -1
  163. package/dist/route-name-DGoBOfPg.mjs +171 -0
  164. package/dist/route-name-DGoBOfPg.mjs.map +1 -0
  165. package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
  166. package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
  167. package/dist/route-registry-CYqLp2Nj.mjs +123 -0
  168. package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
  169. package/dist/router/index.d.mts +2 -2
  170. package/dist/router/index.mjs +18 -8
  171. package/dist/router-CWGBD-Bg.mjs +78 -0
  172. package/dist/router-CWGBD-Bg.mjs.map +1 -0
  173. package/dist/router-resolver-D4YlPNlm.mjs +88 -0
  174. package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
  175. package/dist/seeder/index.d.mts +14 -4
  176. package/dist/seeder/index.d.mts.map +1 -1
  177. package/dist/seeder/index.mjs +5 -3
  178. package/dist/{seeder-BADTig4n.mjs → seeder-7ubkms-Y.mjs} +7 -56
  179. package/dist/seeder-7ubkms-Y.mjs.map +1 -0
  180. package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
  181. package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
  182. package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
  183. package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
  184. package/dist/{signed-url-BqUqt5dF.mjs → signed-url-DIU0sK_6.mjs} +1 -1
  185. package/dist/{signed-url-BqUqt5dF.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
  186. package/dist/storage/index.d.mts +3 -3
  187. package/dist/storage/index.d.mts.map +1 -1
  188. package/dist/storage/index.mjs +2 -2
  189. package/dist/storage/providers/index.d.mts +2 -2
  190. package/dist/storage/providers/index.d.mts.map +1 -1
  191. package/dist/storage/providers/index.mjs +1 -1
  192. package/dist/{storage-BA3ppVYM.mjs → storage-MDZypIE9.mjs} +12 -11
  193. package/dist/{storage-BA3ppVYM.mjs.map → storage-MDZypIE9.mjs.map} +1 -1
  194. package/dist/{storage-provider.interface-DQMtT42e.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -2
  195. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
  196. package/dist/storage.error-Dnib4VHc.mjs +8 -0
  197. package/dist/{storage.error-C6FY037a.mjs.map → storage.error-Dnib4VHc.mjs.map} +1 -1
  198. package/dist/{stratal-Bdq4IdB3.mjs → stratal-DL9M38_s.mjs} +142 -140
  199. package/dist/stratal-DL9M38_s.mjs.map +1 -0
  200. package/dist/{stratal-BsKmvP6J.d.mts → stratal-DwDJPY9N.d.mts} +3 -3
  201. package/dist/{stratal-BsKmvP6J.d.mts.map → stratal-DwDJPY9N.d.mts.map} +1 -1
  202. package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
  203. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
  204. package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
  205. package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
  206. package/dist/{types-BaeHi67f.d.mts → types-CmV_9xBD.d.mts} +1 -1
  207. package/dist/types-CmV_9xBD.d.mts.map +1 -0
  208. package/dist/uri-h7Q8Jug9.mjs +251 -0
  209. package/dist/uri-h7Q8Jug9.mjs.map +1 -0
  210. package/dist/{usage-generator-DTqaUMR9.mjs → usage-generator-DAWYasuP.mjs} +4 -4
  211. package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
  212. package/dist/{validation-DUzcjb8Q.mjs → validation-CpOjviyT.mjs} +6 -6
  213. package/dist/{validation-DUzcjb8Q.mjs.map → validation-CpOjviyT.mjs.map} +1 -1
  214. package/dist/{validation.context-XTysWJ3b.mjs → validation.context-CRvmrhq7.mjs} +3 -3
  215. package/dist/{validation.context-XTysWJ3b.mjs.map → validation.context-CRvmrhq7.mjs.map} +1 -1
  216. package/dist/versioning.service-C6aHky8-.mjs +36 -0
  217. package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
  218. package/dist/websocket/index.d.mts +11 -2
  219. package/dist/websocket/index.d.mts.map +1 -1
  220. package/dist/websocket/index.mjs +1 -1
  221. package/dist/workers/index.d.mts +2 -2
  222. package/dist/workers/index.d.mts.map +1 -1
  223. package/dist/workers/index.mjs +3 -3
  224. package/dist/workers/index.mjs.map +1 -1
  225. package/dist/{zod-hMa3rSHV.mjs → zod-eKqqhZ5_.mjs} +2 -2
  226. package/dist/{zod-hMa3rSHV.mjs.map → zod-eKqqhZ5_.mjs.map} +1 -1
  227. package/dist/{zod-DvWTfRpI.d.mts → zod-wecrEVAs.d.mts} +8 -3
  228. package/dist/zod-wecrEVAs.d.mts.map +1 -0
  229. package/package.json +19 -30
  230. package/dist/base-email.provider-BWZHIjt8.mjs +0 -42
  231. package/dist/base-email.provider-BWZHIjt8.mjs.map +0 -1
  232. package/dist/cache.service-e34gV6tz.d.mts.map +0 -1
  233. package/dist/cache.tokens-ovi_c52J.mjs +0 -6
  234. package/dist/cache.tokens-ovi_c52J.mjs.map +0 -1
  235. package/dist/colors-axmupKdp.mjs +0 -16
  236. package/dist/colors-axmupKdp.mjs.map +0 -1
  237. package/dist/command-BU4ApTo5.mjs.map +0 -1
  238. package/dist/command-wXfvHbBZ.d.mts.map +0 -1
  239. package/dist/consumer-registry-DHQtypr1.d.mts.map +0 -1
  240. package/dist/cron-manager-9bpN9bu4.mjs.map +0 -1
  241. package/dist/cron-manager-CSTIBPcM.d.mts +0 -124
  242. package/dist/cron-manager-CSTIBPcM.d.mts.map +0 -1
  243. package/dist/di-BO1QIb5H.mjs.map +0 -1
  244. package/dist/env-DKSbuBi5.d.mts.map +0 -1
  245. package/dist/events-D1KdDaiP.mjs.map +0 -1
  246. package/dist/index-B4UBK-2T.d.mts.map +0 -1
  247. package/dist/index-BtlE9RuO.d.mts.map +0 -1
  248. package/dist/index-CW1YHSft.d.mts.map +0 -1
  249. package/dist/index-DEncMcC6.d.mts.map +0 -1
  250. package/dist/index-Dj5IMwtr.d.mts.map +0 -1
  251. package/dist/module-xYoHba6B.mjs.map +0 -1
  252. package/dist/openapi-C6lm0RmV.mjs.map +0 -1
  253. package/dist/quarry-registry-D4hIGScf.d.mts.map +0 -1
  254. package/dist/quarry-registry-DkraZNwn.mjs.map +0 -1
  255. package/dist/queue.module-DeWJ0tQM.mjs +0 -355
  256. package/dist/queue.module-DeWJ0tQM.mjs.map +0 -1
  257. package/dist/resend.provider-Ur6tU7fK.mjs +0 -68
  258. package/dist/resend.provider-Ur6tU7fK.mjs.map +0 -1
  259. package/dist/router-Cy6DjkvP.mjs +0 -1852
  260. package/dist/router-Cy6DjkvP.mjs.map +0 -1
  261. package/dist/seeder-BADTig4n.mjs.map +0 -1
  262. package/dist/smtp.provider-C129sNBT.mjs +0 -76
  263. package/dist/smtp.provider-C129sNBT.mjs.map +0 -1
  264. package/dist/storage-provider.interface-DQMtT42e.d.mts.map +0 -1
  265. package/dist/storage.error-C6FY037a.mjs +0 -8
  266. package/dist/stratal-Bdq4IdB3.mjs.map +0 -1
  267. package/dist/types-BaeHi67f.d.mts.map +0 -1
  268. package/dist/usage-generator-DTqaUMR9.mjs.map +0 -1
  269. package/dist/zod-DvWTfRpI.d.mts.map +0 -1
  270. /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
@@ -0,0 +1,165 @@
1
+ import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
+ import { d as inject, n as CONTAINER_TOKEN, s as Singleton, v as ROUTER_TOKENS } from "./di-DseMn-z9.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
4
+ import { l as ROUTER_CONTEXT_KEYS } from "./exception-context-kEoMFwze.mjs";
5
+ import { t as I18N_TOKENS } from "./i18n.tokens-CZ_v8oyS.mjs";
6
+ import { languageDetector } from "hono/language";
7
+ //#region src/i18n/i18n.options.ts
8
+ /**
9
+ * Resolve I18n options with defaults
10
+ */
11
+ function resolveI18nOptions(options) {
12
+ const detection = options?.detection;
13
+ const enabled = detection ? detection.enabled !== false : true;
14
+ const strategy = detection && "strategy" in detection ? detection.strategy ?? "cookie" : "cookie";
15
+ const prefixDefaultLocale = detection && "prefixDefaultLocale" in detection && detection.prefixDefaultLocale !== void 0 ? detection.prefixDefaultLocale : false;
16
+ return {
17
+ defaultLocale: options?.defaultLocale ?? "en",
18
+ fallbackLocale: options?.fallbackLocale ?? "en",
19
+ locales: options?.locales ?? ["en"],
20
+ detection: {
21
+ enabled,
22
+ strategy,
23
+ prefixDefaultLocale
24
+ }
25
+ };
26
+ }
27
+ /**
28
+ * Build Hono languageDetector options from I18n module options
29
+ */
30
+ function buildDetectorOptions(options) {
31
+ const resolved = resolveI18nOptions(options);
32
+ const strategy = resolved.detection.strategy;
33
+ const detectorOptions = {
34
+ order: [strategy],
35
+ fallbackLanguage: resolved.defaultLocale,
36
+ supportedLanguages: resolved.locales,
37
+ lookupCookie: "locale",
38
+ lookupQueryString: "locale",
39
+ lookupFromPathIndex: 0,
40
+ ignoreCase: true
41
+ };
42
+ if (strategy === "cookie") {
43
+ detectorOptions.caches = ["cookie"];
44
+ if (options?.detection && "cookieOptions" in options.detection && options.detection.cookieOptions) detectorOptions.cookieOptions = options.detection.cookieOptions;
45
+ } else detectorOptions.caches = false;
46
+ return detectorOptions;
47
+ }
48
+ //#endregion
49
+ //#region src/router/services/locale-path.service.ts
50
+ var locale_path_service_exports = /* @__PURE__ */ __exportAll({ LocalePathService: () => LocalePathService });
51
+ let LocalePathService = class LocalePathService {
52
+ honoApp;
53
+ _config;
54
+ _pathDetectionEnabled;
55
+ _prefixDefaultLocale;
56
+ constructor(container, honoApp) {
57
+ this.honoApp = honoApp;
58
+ const i18nOptions = container.isRegistered(I18N_TOKENS.Options) ? container.resolve(I18N_TOKENS.Options) : void 0;
59
+ const detection = i18nOptions?.detection;
60
+ const detectionEnabled = detection ? detection.enabled !== false : true;
61
+ const strategy = (detection && "strategy" in detection && detection.strategy) ?? "cookie";
62
+ this._pathDetectionEnabled = detectionEnabled && strategy === "path";
63
+ this._prefixDefaultLocale = detection && "prefixDefaultLocale" in detection && detection.prefixDefaultLocale !== void 0 ? detection.prefixDefaultLocale : false;
64
+ if (this._pathDetectionEnabled) {
65
+ const allLocales = i18nOptions?.locales ?? ["en"];
66
+ const defaultLocale = i18nOptions?.defaultLocale ?? "en";
67
+ this._config = this._prefixDefaultLocale === true ? {
68
+ allLocales,
69
+ prefixedLocales: allLocales,
70
+ defaultLocale: null
71
+ } : {
72
+ allLocales,
73
+ prefixedLocales: allLocales.filter((l) => l !== defaultLocale),
74
+ defaultLocale
75
+ };
76
+ } else this._config = null;
77
+ if (detectionEnabled) this.setupLanguageDetection(i18nOptions);
78
+ if (this._config?.defaultLocale && this._prefixDefaultLocale === "redirect") this.setupDefaultLocaleRedirect(this._config.defaultLocale);
79
+ }
80
+ /** Whether path-based locale detection is enabled */
81
+ get enabled() {
82
+ return this._pathDetectionEnabled;
83
+ }
84
+ /** The computed locale path config, or null if path detection is disabled */
85
+ get localePathConfig() {
86
+ return this._config;
87
+ }
88
+ /** The prefixDefaultLocale setting (false, true, or 'redirect') */
89
+ get prefixDefaultLocale() {
90
+ return this._prefixDefaultLocale;
91
+ }
92
+ /**
93
+ * Expand a path into primary + locale-prefixed variants.
94
+ *
95
+ * @param path - The base path to expand
96
+ * @returns Array of resolved paths with locale metadata
97
+ */
98
+ resolve(path) {
99
+ if (!this._config) return [{
100
+ path,
101
+ isLocaleVariant: false
102
+ }];
103
+ const constraint = this.buildLocaleConstraint();
104
+ const suffix = path === "/" ? "" : path;
105
+ if (this._config.defaultLocale === null) return [{
106
+ path: `/:locale${constraint}${suffix}`,
107
+ isLocaleVariant: true
108
+ }];
109
+ const result = [{
110
+ path,
111
+ isLocaleVariant: false
112
+ }];
113
+ if (this._config.prefixedLocales.length > 0) result.push({
114
+ path: `/:locale${constraint}${suffix}`,
115
+ isLocaleVariant: true
116
+ });
117
+ return result;
118
+ }
119
+ /**
120
+ * Build a Hono regex constraint from prefixed locales.
121
+ * e.g., `{en|de|fr}` — restricts `:locale` to only match known values.
122
+ */
123
+ buildLocaleConstraint() {
124
+ return `{${(this._config.defaultLocale === null ? this._config.allLocales : this._config.prefixedLocales).join("|")}}`;
125
+ }
126
+ /**
127
+ * Apply Hono's languageDetector middleware and bridge the detected language
128
+ * to Stratal's LOCALE context variable.
129
+ */
130
+ setupLanguageDetection(i18nOptions) {
131
+ const detectorOptions = buildDetectorOptions(i18nOptions);
132
+ this.honoApp.use("*", languageDetector(detectorOptions));
133
+ this.honoApp.use("*", async (c, next) => {
134
+ const language = c.get("language");
135
+ if (language) c.set(ROUTER_CONTEXT_KEYS.LOCALE, language);
136
+ await next();
137
+ });
138
+ }
139
+ /**
140
+ * Redirect requests that include the default locale prefix to the unprefixed path.
141
+ * For example, `/en/users` → 301 redirect to `/users`.
142
+ *
143
+ * Only active when `prefixDefaultLocale` is `'redirect'`.
144
+ */
145
+ setupDefaultLocaleRedirect(defaultLocale) {
146
+ const prefix = `/${defaultLocale}`;
147
+ this.honoApp.use("*", async (c, next) => {
148
+ const path = new URL(c.req.url).pathname;
149
+ if (path === prefix || path.startsWith(`${prefix}/`)) {
150
+ const stripped = path.slice(prefix.length) || "/";
151
+ return c.redirect(stripped, 301);
152
+ }
153
+ await next();
154
+ });
155
+ }
156
+ };
157
+ LocalePathService = __decorate([
158
+ Singleton(),
159
+ __decorateParam(0, inject(CONTAINER_TOKEN)),
160
+ __decorateParam(1, inject(ROUTER_TOKENS.HonoApp))
161
+ ], LocalePathService);
162
+ //#endregion
163
+ export { resolveI18nOptions as i, locale_path_service_exports as n, buildDetectorOptions as r, LocalePathService as t };
164
+
165
+ //# sourceMappingURL=locale-path.service-D-dHiIPc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-path.service-D-dHiIPc.mjs","names":[],"sources":["../src/i18n/i18n.options.ts","../src/router/services/locale-path.service.ts"],"sourcesContent":["/**\n * I18n Module Options\n *\n * Configuration options for the I18n dynamic module.\n * Use with I18nModule.forRoot() to configure locale settings.\n * Use I18nModule.registerMessages() to add translations.\n */\n\nimport type { DetectorOptions } from 'hono/language';\n\n/**\n * Detection strategy for locale resolution\n *\n * - `'cookie'` — reads from the `locale` cookie (default)\n * - `'header'` — reads from the `Accept-Language` header\n * - `'querystring'` — reads from the `?locale=` query parameter\n * - `'path'` — reads from the first URL path segment (e.g., `/en/api/users`)\n */\nexport type DetectionStrategy = 'cookie' | 'header' | 'querystring' | 'path'\n\ninterface BaseDetection {\n /** Set to false to disable language detection entirely. @default true */\n enabled?: boolean\n}\n\n/**\n * Language detection options (discriminated by strategy)\n *\n * @example Cookie detection (default)\n * ```typescript\n * { strategy: 'cookie' }\n * ```\n *\n * @example Header detection\n * ```typescript\n * { strategy: 'header' }\n * ```\n *\n * @example Path detection\n * ```typescript\n * { strategy: 'path' }\n * ```\n *\n * @example Disable detection\n * ```typescript\n * { enabled: false }\n * ```\n */\nexport type LanguageDetectionOptions =\n | (BaseDetection & { strategy?: 'cookie'; cookieOptions?: DetectorOptions['cookieOptions'] })\n | (BaseDetection & { strategy: 'header' })\n | (BaseDetection & { strategy: 'querystring' })\n | (BaseDetection & {\n strategy: 'path'\n /**\n * Controls whether the default locale gets a URL path prefix.\n *\n * - `false` (default) — The default locale has no prefix (`/users`), other locales\n * are prefixed (`/fr/users`). Requests to the prefixed default locale (`/en/users`) return 404.\n * - `'redirect'` — Same as `false`, but requests to the prefixed default locale\n * (`/en/users`) are 301-redirected to the unprefixed path (`/users`).\n * - `true` — All locales are prefixed (`/en/users`, `/fr/users`).\n *\n * @default false\n */\n prefixDefaultLocale?: false | true | 'redirect'\n })\n | { enabled: false }\n\n/**\n * Options for configuring the I18n module\n *\n * @example\n * ```typescript\n * I18nModule.forRoot({\n * defaultLocale: 'en',\n * fallbackLocale: 'en',\n * locales: ['en', 'fr'],\n * detection: { strategy: 'header' },\n * })\n * ```\n */\nexport interface I18nModuleOptions {\n /**\n * Default locale for the application\n * @default 'en'\n */\n defaultLocale?: string\n\n /**\n * Fallback locale when translation is missing\n * @default 'en'\n */\n fallbackLocale?: string\n\n /**\n * List of supported locales\n * Request locales not in this list will fall back to defaultLocale\n */\n locales?: string[]\n\n /**\n * Language detection configuration\n * Controls how the locale is extracted from incoming requests\n */\n detection?: LanguageDetectionOptions\n}\n\n/**\n * Resolved options with all defaults applied\n * Used internally by I18n services\n */\nexport interface ResolvedI18nOptions {\n defaultLocale: string\n fallbackLocale: string\n locales: string[]\n detection: {\n enabled: boolean\n strategy: DetectionStrategy\n /** Resolved value of the path detection `prefixDefaultLocale` option. Only meaningful when `strategy` is `'path'`. */\n prefixDefaultLocale: false | true | 'redirect'\n }\n}\n\n/**\n * Resolve I18n options with defaults\n */\nexport function resolveI18nOptions(options?: I18nModuleOptions): ResolvedI18nOptions {\n const detection = options?.detection\n const enabled = detection ? (detection.enabled !== false) : true\n const strategy: DetectionStrategy = (detection && 'strategy' in detection) ? detection.strategy ?? 'cookie' : 'cookie'\n const prefixDefaultLocale: false | true | 'redirect' =\n (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n return {\n defaultLocale: options?.defaultLocale ?? 'en',\n fallbackLocale: options?.fallbackLocale ?? 'en',\n locales: options?.locales ?? ['en'],\n detection: { enabled, strategy, prefixDefaultLocale },\n }\n}\n\n/**\n * Build Hono languageDetector options from I18n module options\n */\nexport function buildDetectorOptions(options?: I18nModuleOptions): Partial<DetectorOptions> {\n const resolved = resolveI18nOptions(options)\n const strategy = resolved.detection.strategy\n\n const detectorOptions: Partial<DetectorOptions> = {\n order: [strategy],\n fallbackLanguage: resolved.defaultLocale,\n supportedLanguages: resolved.locales,\n lookupCookie: 'locale',\n lookupQueryString: 'locale',\n lookupFromPathIndex: 0,\n ignoreCase: true,\n }\n\n if (strategy === 'cookie') {\n detectorOptions.caches = ['cookie']\n if (options?.detection && 'cookieOptions' in options.detection && options.detection.cookieOptions) {\n detectorOptions.cookieOptions = options.detection.cookieOptions\n }\n } else {\n detectorOptions.caches = false\n }\n\n return detectorOptions\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { languageDetector } from 'hono/language'\nimport { inject } from '../../di'\nimport type { Container } from '../../di/container'\nimport { Singleton } from '../../di/decorators'\nimport { CONTAINER_TOKEN } from '../../di/tokens'\nimport { buildDetectorOptions, type I18nModuleOptions } from '../../i18n/i18n.options'\nimport { I18N_TOKENS } from '../../i18n/i18n.tokens'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\nimport type { HonoApp } from '../hono-app'\nimport { ROUTER_TOKENS } from '../router.tokens'\nimport type { LocalePathConfig, RouterEnv } from '../types'\n\n/**\n * A resolved path with locale variant metadata.\n */\nexport interface ResolvedPath {\n /** The fully resolved path (may include /:locale prefix) */\n path: string\n /** Whether this path is a locale-prefixed variant */\n isLocaleVariant: boolean\n}\n\n/**\n * Resolves locale path variants for route paths.\n *\n * Computes `LocalePathConfig` from `I18nModuleOptions` and provides\n * path expansion for locale-prefixed route variants.\n *\n * Also applies language detection and default locale redirect middleware\n * to HonoApp when resolved from the container.\n *\n * Registered as a singleton in the container.\n */\n@Singleton()\nexport class LocalePathService {\n private readonly _config: LocalePathConfig | null\n private readonly _pathDetectionEnabled: boolean\n private readonly _prefixDefaultLocale: false | true | 'redirect'\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(ROUTER_TOKENS.HonoApp) private readonly honoApp: HonoApp,\n ) {\n const i18nOptions = container.isRegistered(I18N_TOKENS.Options)\n ? container.resolve<I18nModuleOptions>(I18N_TOKENS.Options)\n : undefined\n\n const detection = i18nOptions?.detection\n const detectionEnabled = detection ? detection.enabled !== false : true\n const strategy = (detection && 'strategy' in detection && detection.strategy) ?? 'cookie'\n\n this._pathDetectionEnabled = detectionEnabled && strategy === 'path'\n this._prefixDefaultLocale = (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n if (this._pathDetectionEnabled) {\n const allLocales = i18nOptions?.locales ?? ['en']\n const defaultLocale = i18nOptions?.defaultLocale ?? 'en'\n\n this._config = this._prefixDefaultLocale === true\n ? { allLocales, prefixedLocales: allLocales, defaultLocale: null }\n : { allLocales, prefixedLocales: allLocales.filter(l => l !== defaultLocale), defaultLocale }\n } else {\n this._config = null\n }\n\n // Apply locale middleware to HonoApp\n if (detectionEnabled) {\n this.setupLanguageDetection(i18nOptions)\n }\n if (this._config?.defaultLocale && this._prefixDefaultLocale === 'redirect') {\n this.setupDefaultLocaleRedirect(this._config.defaultLocale)\n }\n }\n\n /** Whether path-based locale detection is enabled */\n get enabled(): boolean {\n return this._pathDetectionEnabled\n }\n\n /** The computed locale path config, or null if path detection is disabled */\n get localePathConfig(): LocalePathConfig | null {\n return this._config\n }\n\n /** The prefixDefaultLocale setting (false, true, or 'redirect') */\n get prefixDefaultLocale(): false | true | 'redirect' {\n return this._prefixDefaultLocale\n }\n\n /**\n * Expand a path into primary + locale-prefixed variants.\n *\n * @param path - The base path to expand\n * @returns Array of resolved paths with locale metadata\n */\n resolve(path: string): ResolvedPath[] {\n if (!this._config) {\n return [{ path, isLocaleVariant: false }]\n }\n\n const constraint = this.buildLocaleConstraint()\n const suffix = path === '/' ? '' : path\n\n // All locales prefixed (prefixDefaultLocale: true)\n if (this._config.defaultLocale === null) {\n return [{ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true }]\n }\n\n // Default locale unprefixed, other locales prefixed\n const result: ResolvedPath[] = [{ path, isLocaleVariant: false }]\n\n // Only add /:locale route when there are non-default locales to match\n // (z.enum requires at least one value)\n if (this._config.prefixedLocales.length > 0) {\n result.push({ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true })\n }\n\n return result\n }\n\n /**\n * Build a Hono regex constraint from prefixed locales.\n * e.g., `{en|de|fr}` — restricts `:locale` to only match known values.\n */\n private buildLocaleConstraint(): string {\n const locales = this._config!.defaultLocale === null\n ? this._config!.allLocales\n : this._config!.prefixedLocales\n return `{${locales.join('|')}}`\n }\n\n /**\n * Apply Hono's languageDetector middleware and bridge the detected language\n * to Stratal's LOCALE context variable.\n */\n private setupLanguageDetection(i18nOptions?: I18nModuleOptions): void {\n const detectorOptions = buildDetectorOptions(i18nOptions)\n\n // Apply Hono's languageDetector\n this.honoApp.use('*', languageDetector(detectorOptions) as MiddlewareHandler<RouterEnv>)\n\n // Bridge: sync Hono's 'language' variable to Stratal's LOCALE context key\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const language = c.get('language')\n if (language) {\n c.set(ROUTER_CONTEXT_KEYS.LOCALE, language)\n }\n await next()\n })\n }\n\n /**\n * Redirect requests that include the default locale prefix to the unprefixed path.\n * For example, `/en/users` → 301 redirect to `/users`.\n *\n * Only active when `prefixDefaultLocale` is `'redirect'`.\n */\n private setupDefaultLocaleRedirect(defaultLocale: string): void {\n const prefix = `/${defaultLocale}`\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const path = new URL(c.req.url).pathname\n if (path === prefix || path.startsWith(`${prefix}/`)) {\n const stripped = path.slice(prefix.length) || '/'\n return c.redirect(stripped, 301)\n }\n await next()\n })\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ //#region src/router/locale-url.ts
2
+ /**
3
+ * Pure helpers for locale-aware URL path manipulation.
4
+ *
5
+ * Each function takes config explicitly so it can run anywhere (no DI, no request
6
+ * context). For ergonomic DI-driven access, see {@link LocaleUrlService} which
7
+ * binds these to the resolved {@link LocalePathService} config.
8
+ */
9
+ /**
10
+ * Whether a locale should be URL-prefixed under the given config.
11
+ *
12
+ * - No config → always prefix (caller didn't opt into locale-aware URLs).
13
+ * - `prefixDefaultLocale: true` → every locale, including the default, is prefixed.
14
+ * - Otherwise → only non-default locales are prefixed.
15
+ */
16
+ function shouldPrefixLocale(locale, config) {
17
+ if (!config) return true;
18
+ if (config.prefixDefaultLocale === true) return true;
19
+ return locale !== config.defaultLocale;
20
+ }
21
+ /**
22
+ * Prepend `/{locale}` to a pathname, respecting `prefixDefaultLocale`.
23
+ * Returns the pathname unchanged when the locale shouldn't be prefixed.
24
+ */
25
+ function applyLocalePrefix(pathname, locale, config) {
26
+ if (!shouldPrefixLocale(locale, config)) return pathname;
27
+ return pathname === "/" ? `/${locale}` : `/${locale}${pathname}`;
28
+ }
29
+ /**
30
+ * Strip a known-locale prefix from the start of a pathname.
31
+ * Returns the pathname unchanged if the first segment isn't in `knownLocales`.
32
+ */
33
+ function stripLocalePrefix(pathname, knownLocales) {
34
+ const segments = pathname.split("/").filter(Boolean);
35
+ if (segments.length > 0 && knownLocales.includes(segments[0])) {
36
+ const rest = segments.slice(1).join("/");
37
+ return rest ? `/${rest}` : "/";
38
+ }
39
+ return pathname;
40
+ }
41
+ //#endregion
42
+ export { shouldPrefixLocale as n, stripLocalePrefix as r, applyLocalePrefix as t };
43
+
44
+ //# sourceMappingURL=locale-url-nZrZxqJP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-url-nZrZxqJP.mjs","names":[],"sources":["../src/router/locale-url.ts"],"sourcesContent":["import type { LocaleUrlConfig } from './types'\n\n/**\n * Pure helpers for locale-aware URL path manipulation.\n *\n * Each function takes config explicitly so it can run anywhere (no DI, no request\n * context). For ergonomic DI-driven access, see {@link LocaleUrlService} which\n * binds these to the resolved {@link LocalePathService} config.\n */\n\n/**\n * Whether a locale should be URL-prefixed under the given config.\n *\n * - No config → always prefix (caller didn't opt into locale-aware URLs).\n * - `prefixDefaultLocale: true` → every locale, including the default, is prefixed.\n * - Otherwise → only non-default locales are prefixed.\n */\nexport function shouldPrefixLocale(locale: string, config: LocaleUrlConfig | undefined): boolean {\n if (!config) return true\n if (config.prefixDefaultLocale === true) return true\n return locale !== config.defaultLocale\n}\n\n/**\n * Prepend `/{locale}` to a pathname, respecting `prefixDefaultLocale`.\n * Returns the pathname unchanged when the locale shouldn't be prefixed.\n */\nexport function applyLocalePrefix(pathname: string, locale: string, config: LocaleUrlConfig | undefined): string {\n if (!shouldPrefixLocale(locale, config)) return pathname\n return pathname === '/' ? `/${locale}` : `/${locale}${pathname}`\n}\n\n/**\n * Strip a known-locale prefix from the start of a pathname.\n * Returns the pathname unchanged if the first segment isn't in `knownLocales`.\n */\nexport function stripLocalePrefix(pathname: string, knownLocales: readonly string[]): string {\n const segments = pathname.split('/').filter(Boolean)\n if (segments.length > 0 && knownLocales.includes(segments[0])) {\n const rest = segments.slice(1).join('/')\n return rest ? `/${rest}` : '/'\n }\n return pathname\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,mBAAmB,QAAgB,QAA8C;CAC/F,IAAI,CAAC,QAAQ,OAAO;CACpB,IAAI,OAAO,wBAAwB,MAAM,OAAO;CAChD,OAAO,WAAW,OAAO;AAC3B;;;;;AAMA,SAAgB,kBAAkB,UAAkB,QAAgB,QAA6C;CAC/G,IAAI,CAAC,mBAAmB,QAAQ,MAAM,GAAG,OAAO;CAChD,OAAO,aAAa,MAAM,IAAI,WAAW,IAAI,SAAS;AACxD;;;;;AAMA,SAAgB,kBAAkB,UAAkB,cAAyC;CAC3F,MAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;CACnD,IAAI,SAAS,SAAS,KAAK,aAAa,SAAS,SAAS,EAAE,GAAG;EAC7D,MAAM,OAAO,SAAS,MAAM,CAAC,EAAE,KAAK,GAAG;EACvC,OAAO,OAAO,IAAI,SAAS;CAC7B;CACA,OAAO;AACT"}
@@ -0,0 +1,41 @@
1
+ import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
+ import { d as inject, s as Singleton, v as ROUTER_TOKENS } from "./di-DseMn-z9.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
4
+ import { n as shouldPrefixLocale, r as stripLocalePrefix, t as applyLocalePrefix } from "./locale-url-nZrZxqJP.mjs";
5
+ //#region src/router/services/locale-url.service.ts
6
+ var locale_url_service_exports = /* @__PURE__ */ __exportAll({ LocaleUrlService: () => LocaleUrlService });
7
+ let LocaleUrlService = class LocaleUrlService {
8
+ localePath;
9
+ constructor(localePath) {
10
+ this.localePath = localePath;
11
+ }
12
+ /** Whether path-based locale detection is enabled — i.e., locales have URL-distinct path variants. */
13
+ get pathEnabled() {
14
+ return this.localePath.enabled;
15
+ }
16
+ /** Whether the given locale should get a URL prefix under the current config. */
17
+ shouldPrefix(locale) {
18
+ return shouldPrefixLocale(locale, this.toUrlConfig());
19
+ }
20
+ /** Prepend `/{locale}` to a pathname, respecting `prefixDefaultLocale`. */
21
+ applyPrefix(pathname, locale) {
22
+ return applyLocalePrefix(pathname, locale, this.toUrlConfig());
23
+ }
24
+ /** Strip a known-locale prefix from the start of a pathname. */
25
+ stripPrefix(pathname) {
26
+ return stripLocalePrefix(pathname, this.localePath.localePathConfig?.allLocales ?? []);
27
+ }
28
+ toUrlConfig() {
29
+ const config = this.localePath.localePathConfig;
30
+ if (!config) return void 0;
31
+ return {
32
+ defaultLocale: config.defaultLocale,
33
+ prefixDefaultLocale: this.localePath.prefixDefaultLocale
34
+ };
35
+ }
36
+ };
37
+ LocaleUrlService = __decorate([Singleton(), __decorateParam(0, inject(ROUTER_TOKENS.LocalePathService))], LocaleUrlService);
38
+ //#endregion
39
+ export { locale_url_service_exports as n, LocaleUrlService as t };
40
+
41
+ //# sourceMappingURL=locale-url.service-C2EWmGdq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-url.service-C2EWmGdq.mjs","names":[],"sources":["../src/router/services/locale-url.service.ts"],"sourcesContent":["import { inject } from '../../di'\nimport { Singleton } from '../../di/decorators'\nimport { applyLocalePrefix, shouldPrefixLocale, stripLocalePrefix } from '../locale-url'\nimport { ROUTER_TOKENS } from '../router.tokens'\nimport type { LocaleUrlConfig } from '../types'\nimport { type LocalePathService } from './locale-path.service'\n\n/**\n * DI-friendly wrapper around the pure locale-url helpers.\n *\n * Binds {@link LocalePathService} config so consumers can call `applyPrefix`,\n * `stripPrefix`, and `shouldPrefix` without passing config every time.\n *\n * Useful for canonical URL generation, sitemap builders, redirect middleware,\n * hreflang link emission, and anywhere else a request handler needs to compute\n * locale-aware path variants.\n */\n@Singleton()\nexport class LocaleUrlService {\n constructor(\n @inject(ROUTER_TOKENS.LocalePathService) private readonly localePath: LocalePathService,\n ) { }\n\n /** Whether path-based locale detection is enabled — i.e., locales have URL-distinct path variants. */\n get pathEnabled(): boolean {\n return this.localePath.enabled\n }\n\n /** Whether the given locale should get a URL prefix under the current config. */\n shouldPrefix(locale: string): boolean {\n return shouldPrefixLocale(locale, this.toUrlConfig())\n }\n\n /** Prepend `/{locale}` to a pathname, respecting `prefixDefaultLocale`. */\n applyPrefix(pathname: string, locale: string): string {\n return applyLocalePrefix(pathname, locale, this.toUrlConfig())\n }\n\n /** Strip a known-locale prefix from the start of a pathname. */\n stripPrefix(pathname: string): string {\n const known = this.localePath.localePathConfig?.allLocales ?? []\n return stripLocalePrefix(pathname, known)\n }\n\n private toUrlConfig(): LocaleUrlConfig | undefined {\n const config = this.localePath.localePathConfig\n if (!config) return undefined\n return { defaultLocale: config.defaultLocale, prefixDefaultLocale: this.localePath.prefixDefaultLocale }\n }\n}\n"],"mappings":";;;;;;AAkBO,IAAA,mBAAA,MAAM,iBAAiB;CAEgC;CAD5D,YACE,YACA;EAD0D,KAAA,aAAA;CACxD;;CAGJ,IAAI,cAAuB;EACzB,OAAO,KAAK,WAAW;CACzB;;CAGA,aAAa,QAAyB;EACpC,OAAO,mBAAmB,QAAQ,KAAK,YAAY,CAAC;CACtD;;CAGA,YAAY,UAAkB,QAAwB;EACpD,OAAO,kBAAkB,UAAU,QAAQ,KAAK,YAAY,CAAC;CAC/D;;CAGA,YAAY,UAA0B;EAEpC,OAAO,kBAAkB,UADX,KAAK,WAAW,kBAAkB,cAAc,CAAC,CACvB;CAC1C;CAEA,cAAmD;EACjD,MAAM,SAAS,KAAK,WAAW;EAC/B,IAAI,CAAC,QAAQ,OAAO,KAAA;EACpB,OAAO;GAAE,eAAe,OAAO;GAAe,qBAAqB,KAAK,WAAW;EAAoB;CACzG;AACF;+BAhCC,UAAU,GAAA,gBAAA,GAGN,OAAO,cAAc,iBAAiB,CAAA,CAAA,GAAA,gBAAA"}
@@ -1,2 +1,2 @@
1
- import { a as InternalLogContext, c as LogLevel, i as LogEntry, l as LOGGER_TOKENS, n as JsonFormatter, o as LogContext, r as LoggerService, s as LOG_LEVEL_PRIORITY, t as PrettyFormatter } from "../index-BtlE9RuO.mjs";
1
+ import { a as InternalLogContext, c as LogLevel, i as LogEntry, l as LOGGER_TOKENS, n as JsonFormatter, o as LogContext, r as LoggerService, s as LOG_LEVEL_PRIORITY, t as PrettyFormatter } from "../index-BUt92sAE.mjs";
2
2
  export { InternalLogContext, JsonFormatter, LOGGER_TOKENS, LOG_LEVEL_PRIORITY, LogContext, LogEntry, LogLevel, LoggerService, PrettyFormatter };
@@ -1,5 +1,5 @@
1
- import { d as Transient, m as inject } from "../di-BO1QIb5H.mjs";
2
- import { n as __decorateParam, t as __decorate } from "../decorate-HgTKAYK8.mjs";
1
+ import { c as Transient, d as inject } from "../di-DseMn-z9.mjs";
2
+ import { n as __decorateParam, t as __decorate } from "../decorate-CuAoSZvs.mjs";
3
3
  //#region src/logger/logger.tokens.ts
4
4
  const LOGGER_TOKENS = {
5
5
  LoggerService: Symbol.for("stratal:logger:service"),
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/logger/logger.tokens.ts","../../src/logger/contracts/log-level.ts","../../src/logger/services/logger.service.ts","../../src/logger/formatters/json-formatter.ts","../../src/logger/formatters/pretty-formatter.ts"],"sourcesContent":["export const LOGGER_TOKENS = {\n LoggerService: Symbol.for('stratal:logger:service'),\n Formatter: Symbol.for('stratal:logger:formatter'),\n LogLevelOptions: Symbol.for('stratal:logger:log:level:options'),\n} as const\n","/**\n * Log severity levels\n * Ordered from least to most severe\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Map log levels to numeric priorities (for filtering)\n * Higher numbers = more severe = higher priority\n */\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n [LogLevel.DEBUG]: 0,\n [LogLevel.INFO]: 1,\n [LogLevel.WARN]: 2,\n [LogLevel.ERROR]: 3,\n}\n","import { inject } from '../../di'\nimport { Transient } from '../../di/decorators'\nimport type { InternalLogContext, LogContext, LogEntry } from '../contracts'\nimport { LOG_LEVEL_PRIORITY, LogLevel } from '../contracts/log-level'\nimport type { ILogFormatter } from '../formatters/formatter.interface'\nimport { LOGGER_TOKENS } from '../logger.tokens'\n\n@Transient()\nexport class LoggerService {\n constructor(\n @inject(LOGGER_TOKENS.LogLevelOptions)\n private readonly logLevel: LogLevel,\n\n @inject(LOGGER_TOKENS.Formatter)\n private readonly formatter: ILogFormatter,\n ) { }\n\n debug(message: string, context?: LogContext): void {\n this.log(LogLevel.DEBUG, message, context)\n }\n\n info(message: string, context?: LogContext): void {\n this.log(LogLevel.INFO, message, context)\n }\n\n warn(message: string, context?: LogContext): void {\n this.log(LogLevel.WARN, message, context)\n }\n\n error(message: string, error: Error, context?: LogContext): void\n error(message: string, context?: LogContext): void\n error(message: string, errorOrContext?: Error | LogContext, maybeContext?: LogContext): void {\n let context: LogContext | undefined\n let error: Error | undefined\n\n if (errorOrContext instanceof Error) {\n error = errorOrContext\n context = maybeContext\n } else {\n context = errorOrContext\n }\n\n this.log(LogLevel.ERROR, message, context, error)\n }\n\n private log(\n level: LogLevel,\n message: string,\n userContext?: LogContext,\n error?: Error\n ): void {\n if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.logLevel]) {\n return\n }\n\n const entry: LogEntry = {\n level,\n message,\n context: this.enrichContext(userContext ?? {}),\n error: error ? this.serializeError(error) : undefined,\n }\n\n const formatted = this.formatter.format(entry)\n this.writeToConsole(level, formatted)\n }\n\n private writeToConsole(level: LogLevel, formatted: string): void {\n switch (level) {\n case LogLevel.DEBUG:\n console.debug(formatted)\n break\n case LogLevel.INFO:\n console.info(formatted)\n break\n case LogLevel.WARN:\n console.warn(formatted)\n break\n case LogLevel.ERROR:\n console.error(formatted)\n break\n }\n }\n\n private enrichContext(userContext: LogContext): InternalLogContext {\n return {\n ...userContext,\n timestamp: Date.now(),\n }\n }\n\n private serializeError(error: Error): { message: string; stack?: string; name?: string } {\n return {\n message: error.message,\n stack: error.stack,\n name: error.name,\n }\n }\n}\n","import type { LogEntry } from '../contracts'\nimport type { ILogFormatter } from './formatter.interface'\n\n/**\n * JSON Formatter\n *\n * Produces structured JSON logs for production environments.\n * Optimized for log aggregation systems (Cloudflare Analytics, Datadog, etc.)\n *\n * Output format:\n * {\n * \"level\": \"info\",\n * \"message\": \"User logged in\",\n * \"timestamp\": 1234567890,\n * \"userId\": \"user_456\",\n * \"error\": { \"message\": \"...\", \"stack\": \"...\" }\n * }\n */\nexport class JsonFormatter implements ILogFormatter {\n format(entry: LogEntry): string {\n const output = {\n level: entry.level,\n message: entry.message,\n ...entry.context,\n ...(entry.error && { error: entry.error }),\n }\n\n return JSON.stringify(output)\n }\n}\n","import type { LogEntry } from '../contracts'\nimport { LogLevel } from '../contracts'\nimport type { ILogFormatter } from './formatter.interface'\n\n/**\n * Pretty Formatter\n *\n * Human-readable colored output for development environments.\n * Uses ANSI color codes for terminal output.\n *\n * Output format:\n * [2024-01-15 10:30:45] INFO: User logged in\n * userId: user_456\n */\nexport class PrettyFormatter implements ILogFormatter {\n private readonly colors: Record<LogLevel, string> = {\n [LogLevel.DEBUG]: '\\x1b[36m', // Cyan\n [LogLevel.INFO]: '\\x1b[32m', // Green\n [LogLevel.WARN]: '\\x1b[33m', // Yellow\n [LogLevel.ERROR]: '\\x1b[31m', // Red\n }\n\n private readonly reset = '\\x1b[0m'\n\n format(entry: LogEntry): string {\n const color = this.colors[entry.level]\n const timestamp = new Date(entry.context.timestamp).toISOString()\n const levelStr = entry.level.toUpperCase().padEnd(5)\n\n let output = `${color}[${timestamp}] ${levelStr}${this.reset}: ${entry.message}`\n\n // Add context (exclude timestamp)\n const { timestamp: _, ...contextWithoutTimestamp } = entry.context\n const contextEntries = Object.entries(contextWithoutTimestamp)\n\n if (contextEntries.length > 0) {\n output += '\\n'\n contextEntries.forEach(([key, value]) => {\n output += ` ${key}: ${JSON.stringify(value)}\\n`\n })\n }\n\n // Add error stack if present\n if (entry.error?.stack) {\n output += `\\n${entry.error.stack}\\n`\n }\n\n return output.trimEnd()\n }\n}\n"],"mappings":";;;AAAA,MAAa,gBAAgB;CAC3B,eAAe,OAAO,IAAI,yBAAyB;CACnD,WAAW,OAAO,IAAI,2BAA2B;CACjD,iBAAiB,OAAO,IAAI,mCAAmC;CAChE;;;;;;;ACAD,IAAY,WAAL,yBAAA,UAAA;CACL,SAAA,WAAA;CACA,SAAA,UAAA;CACA,SAAA,UAAA;CACA,SAAA,WAAA;;KACD;;;;;AAMD,MAAa,qBAA+C;YACxC;WACD;WACA;YACC;CACnB;;;ACZM,IAAA,gBAAA,MAAM,cAAc;CAGN;CAGA;CALnB,YACE,UAGA,WAEA;EAJiB,KAAA,WAAA;EAGA,KAAA,YAAA;;CAGnB,MAAM,SAAiB,SAA4B;EACjD,KAAK,IAAA,SAAoB,SAAS,QAAQ;;CAG5C,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,QAAQ;;CAG3C,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,QAAQ;;CAK3C,MAAM,SAAiB,gBAAqC,cAAiC;EAC3F,IAAI;EACJ,IAAI;EAEJ,IAAI,0BAA0B,OAAO;GACnC,QAAQ;GACR,UAAU;SAEV,UAAU;EAGZ,KAAK,IAAA,SAAoB,SAAS,SAAS,MAAM;;CAGnD,IACE,OACA,SACA,aACA,OACM;EACN,IAAI,mBAAmB,SAAS,mBAAmB,KAAK,WACtD;EAGF,MAAM,QAAkB;GACtB;GACA;GACA,SAAS,KAAK,cAAc,eAAe,EAAE,CAAC;GAC9C,OAAO,QAAQ,KAAK,eAAe,MAAM,GAAG,KAAA;GAC7C;EAED,MAAM,YAAY,KAAK,UAAU,OAAO,MAAM;EAC9C,KAAK,eAAe,OAAO,UAAU;;CAGvC,eAAuB,OAAiB,WAAyB;EAC/D,QAAQ,OAAR;GACE,KAAA;IACE,QAAQ,MAAM,UAAU;IACxB;GACF,KAAA;IACE,QAAQ,KAAK,UAAU;IACvB;GACF,KAAA;IACE,QAAQ,KAAK,UAAU;IACvB;GACF,KAAA;IACE,QAAQ,MAAM,UAAU;IACxB;;;CAIN,cAAsB,aAA6C;EACjE,OAAO;GACL,GAAG;GACH,WAAW,KAAK,KAAK;GACtB;;CAGH,eAAuB,OAAkE;EACvF,OAAO;GACL,SAAS,MAAM;GACf,OAAO,MAAM;GACb,MAAM,MAAM;GACb;;;;CAxFJ,WAAW;oBAGP,OAAO,cAAc,gBAAgB,CAAA;oBAGrC,OAAO,cAAc,UAAU,CAAA;;;;;;;;;;;;;;;;;;;ACKpC,IAAa,gBAAb,MAAoD;CAClD,OAAO,OAAyB;EAC9B,MAAM,SAAS;GACb,OAAO,MAAM;GACb,SAAS,MAAM;GACf,GAAG,MAAM;GACT,GAAI,MAAM,SAAS,EAAE,OAAO,MAAM,OAAO;GAC1C;EAED,OAAO,KAAK,UAAU,OAAO;;;;;;;;;;;;;;;ACbjC,IAAa,kBAAb,MAAsD;CACpD,SAAoD;aAChC;YACD;YACA;aACC;EACnB;CAED,QAAyB;CAEzB,OAAO,OAAyB;EAK9B,IAAI,SAAS,GAJC,KAAK,OAAO,MAAM,OAIV,GAHJ,IAAI,KAAK,MAAM,QAAQ,UAAU,CAAC,aAGlB,CAAC,IAFlB,MAAM,MAAM,aAAa,CAAC,OAAO,EAEH,GAAG,KAAK,MAAM,IAAI,MAAM;EAGvE,MAAM,EAAE,WAAW,GAAG,GAAG,4BAA4B,MAAM;EAC3D,MAAM,iBAAiB,OAAO,QAAQ,wBAAwB;EAE9D,IAAI,eAAe,SAAS,GAAG;GAC7B,UAAU;GACV,eAAe,SAAS,CAAC,KAAK,WAAW;IACvC,UAAU,KAAK,IAAI,IAAI,KAAK,UAAU,MAAM,CAAC;KAC7C;;EAIJ,IAAI,MAAM,OAAO,OACf,UAAU,KAAK,MAAM,MAAM,MAAM;EAGnC,OAAO,OAAO,SAAS"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/logger/logger.tokens.ts","../../src/logger/contracts/log-level.ts","../../src/logger/services/logger.service.ts","../../src/logger/formatters/json-formatter.ts","../../src/logger/formatters/pretty-formatter.ts"],"sourcesContent":["export const LOGGER_TOKENS = {\n LoggerService: Symbol.for('stratal:logger:service'),\n Formatter: Symbol.for('stratal:logger:formatter'),\n LogLevelOptions: Symbol.for('stratal:logger:log:level:options'),\n} as const\n","/**\n * Log severity levels\n * Ordered from least to most severe\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Map log levels to numeric priorities (for filtering)\n * Higher numbers = more severe = higher priority\n */\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n [LogLevel.DEBUG]: 0,\n [LogLevel.INFO]: 1,\n [LogLevel.WARN]: 2,\n [LogLevel.ERROR]: 3,\n}\n","import { inject } from '../../di'\nimport { Transient } from '../../di/decorators'\nimport type { InternalLogContext, LogContext, LogEntry } from '../contracts'\nimport { LOG_LEVEL_PRIORITY, LogLevel } from '../contracts/log-level'\nimport type { ILogFormatter } from '../formatters/formatter.interface'\nimport { LOGGER_TOKENS } from '../logger.tokens'\n\n@Transient()\nexport class LoggerService {\n constructor(\n @inject(LOGGER_TOKENS.LogLevelOptions)\n private readonly logLevel: LogLevel,\n\n @inject(LOGGER_TOKENS.Formatter)\n private readonly formatter: ILogFormatter,\n ) { }\n\n debug(message: string, context?: LogContext): void {\n this.log(LogLevel.DEBUG, message, context)\n }\n\n info(message: string, context?: LogContext): void {\n this.log(LogLevel.INFO, message, context)\n }\n\n warn(message: string, context?: LogContext): void {\n this.log(LogLevel.WARN, message, context)\n }\n\n error(message: string, error: Error, context?: LogContext): void\n error(message: string, context?: LogContext): void\n error(message: string, errorOrContext?: Error | LogContext, maybeContext?: LogContext): void {\n let context: LogContext | undefined\n let error: Error | undefined\n\n if (errorOrContext instanceof Error) {\n error = errorOrContext\n context = maybeContext\n } else {\n context = errorOrContext\n }\n\n this.log(LogLevel.ERROR, message, context, error)\n }\n\n private log(\n level: LogLevel,\n message: string,\n userContext?: LogContext,\n error?: Error\n ): void {\n if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.logLevel]) {\n return\n }\n\n const entry: LogEntry = {\n level,\n message,\n context: this.enrichContext(userContext ?? {}),\n error: error ? this.serializeError(error) : undefined,\n }\n\n const formatted = this.formatter.format(entry)\n this.writeToConsole(level, formatted)\n }\n\n private writeToConsole(level: LogLevel, formatted: string): void {\n switch (level) {\n case LogLevel.DEBUG:\n console.debug(formatted)\n break\n case LogLevel.INFO:\n console.info(formatted)\n break\n case LogLevel.WARN:\n console.warn(formatted)\n break\n case LogLevel.ERROR:\n console.error(formatted)\n break\n }\n }\n\n private enrichContext(userContext: LogContext): InternalLogContext {\n return {\n ...userContext,\n timestamp: Date.now(),\n }\n }\n\n private serializeError(error: Error): { message: string; stack?: string; name?: string } {\n return {\n message: error.message,\n stack: error.stack,\n name: error.name,\n }\n }\n}\n","import type { LogEntry } from '../contracts'\nimport type { ILogFormatter } from './formatter.interface'\n\n/**\n * JSON Formatter\n *\n * Produces structured JSON logs for production environments.\n * Optimized for log aggregation systems (Cloudflare Analytics, Datadog, etc.)\n *\n * Output format:\n * {\n * \"level\": \"info\",\n * \"message\": \"User logged in\",\n * \"timestamp\": 1234567890,\n * \"userId\": \"user_456\",\n * \"error\": { \"message\": \"...\", \"stack\": \"...\" }\n * }\n */\nexport class JsonFormatter implements ILogFormatter {\n format(entry: LogEntry): string {\n const output = {\n level: entry.level,\n message: entry.message,\n ...entry.context,\n ...(entry.error && { error: entry.error }),\n }\n\n return JSON.stringify(output)\n }\n}\n","import type { LogEntry } from '../contracts'\nimport { LogLevel } from '../contracts'\nimport type { ILogFormatter } from './formatter.interface'\n\n/**\n * Pretty Formatter\n *\n * Human-readable colored output for development environments.\n * Uses ANSI color codes for terminal output.\n *\n * Output format:\n * [2024-01-15 10:30:45] INFO: User logged in\n * userId: user_456\n */\nexport class PrettyFormatter implements ILogFormatter {\n private readonly colors: Record<LogLevel, string> = {\n [LogLevel.DEBUG]: '\\x1b[36m', // Cyan\n [LogLevel.INFO]: '\\x1b[32m', // Green\n [LogLevel.WARN]: '\\x1b[33m', // Yellow\n [LogLevel.ERROR]: '\\x1b[31m', // Red\n }\n\n private readonly reset = '\\x1b[0m'\n\n format(entry: LogEntry): string {\n const color = this.colors[entry.level]\n const timestamp = new Date(entry.context.timestamp).toISOString()\n const levelStr = entry.level.toUpperCase().padEnd(5)\n\n let output = `${color}[${timestamp}] ${levelStr}${this.reset}: ${entry.message}`\n\n // Add context (exclude timestamp)\n const { timestamp: _, ...contextWithoutTimestamp } = entry.context\n const contextEntries = Object.entries(contextWithoutTimestamp)\n\n if (contextEntries.length > 0) {\n output += '\\n'\n contextEntries.forEach(([key, value]) => {\n output += ` ${key}: ${JSON.stringify(value)}\\n`\n })\n }\n\n // Add error stack if present\n if (entry.error?.stack) {\n output += `\\n${entry.error.stack}\\n`\n }\n\n return output.trimEnd()\n }\n}\n"],"mappings":";;;AAAA,MAAa,gBAAgB;CAC3B,eAAe,OAAO,IAAI,wBAAwB;CAClD,WAAW,OAAO,IAAI,0BAA0B;CAChD,iBAAiB,OAAO,IAAI,kCAAkC;AAChE;;;;;;;ACAA,IAAY,WAAL,yBAAA,UAAA;CACL,SAAA,WAAA;CACA,SAAA,UAAA;CACA,SAAA,UAAA;CACA,SAAA,WAAA;;AACF,EAAA,CAAA,CAAA;;;;;AAMA,MAAa,qBAA+C;YACxC;WACD;WACA;YACC;AACpB;;;ACZO,IAAA,gBAAA,MAAM,cAAc;CAGN;CAGA;CALnB,YACE,UAGA,WAEA;EAJiB,KAAA,WAAA;EAGA,KAAA,YAAA;CACf;CAEJ,MAAM,SAAiB,SAA4B;EACjD,KAAK,IAAA,SAAoB,SAAS,OAAO;CAC3C;CAEA,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,OAAO;CAC1C;CAEA,KAAK,SAAiB,SAA4B;EAChD,KAAK,IAAA,QAAmB,SAAS,OAAO;CAC1C;CAIA,MAAM,SAAiB,gBAAqC,cAAiC;EAC3F,IAAI;EACJ,IAAI;EAEJ,IAAI,0BAA0B,OAAO;GACnC,QAAQ;GACR,UAAU;EACZ,OACE,UAAU;EAGZ,KAAK,IAAA,SAAoB,SAAS,SAAS,KAAK;CAClD;CAEA,IACE,OACA,SACA,aACA,OACM;EACN,IAAI,mBAAmB,SAAS,mBAAmB,KAAK,WACtD;EAGF,MAAM,QAAkB;GACtB;GACA;GACA,SAAS,KAAK,cAAc,eAAe,CAAC,CAAC;GAC7C,OAAO,QAAQ,KAAK,eAAe,KAAK,IAAI,KAAA;EAC9C;EAEA,MAAM,YAAY,KAAK,UAAU,OAAO,KAAK;EAC7C,KAAK,eAAe,OAAO,SAAS;CACtC;CAEA,eAAuB,OAAiB,WAAyB;EAC/D,QAAQ,OAAR;GACE,KAAA;IACE,QAAQ,MAAM,SAAS;IACvB;GACF,KAAA;IACE,QAAQ,KAAK,SAAS;IACtB;GACF,KAAA;IACE,QAAQ,KAAK,SAAS;IACtB;GACF,KAAA;IACE,QAAQ,MAAM,SAAS;IACvB;EACJ;CACF;CAEA,cAAsB,aAA6C;EACjE,OAAO;GACL,GAAG;GACH,WAAW,KAAK,IAAI;EACtB;CACF;CAEA,eAAuB,OAAkE;EACvF,OAAO;GACL,SAAS,MAAM;GACf,OAAO,MAAM;GACb,MAAM,MAAM;EACd;CACF;AACF;;CA1FC,UAAU;oBAGN,OAAO,cAAc,eAAe,CAAA;oBAGpC,OAAO,cAAc,SAAS,CAAA;;;;;;;;;;;;;;;;;;;ACKnC,IAAa,gBAAb,MAAoD;CAClD,OAAO,OAAyB;EAC9B,MAAM,SAAS;GACb,OAAO,MAAM;GACb,SAAS,MAAM;GACf,GAAG,MAAM;GACT,GAAI,MAAM,SAAS,EAAE,OAAO,MAAM,MAAM;EAC1C;EAEA,OAAO,KAAK,UAAU,MAAM;CAC9B;AACF;;;;;;;;;;;;;ACfA,IAAa,kBAAb,MAAsD;CACpD,SAAoD;aAChC;YACD;YACA;aACC;CACpB;CAEA,QAAyB;CAEzB,OAAO,OAAyB;EAK9B,IAAI,SAAS,GAJC,KAAK,OAAO,MAAM,OAIV,GAHJ,IAAI,KAAK,MAAM,QAAQ,SAAS,EAAE,YAGnB,EAAE,IAFlB,MAAM,MAAM,YAAY,EAAE,OAAO,CAEJ,IAAI,KAAK,MAAM,IAAI,MAAM;EAGvE,MAAM,EAAE,WAAW,GAAG,GAAG,4BAA4B,MAAM;EAC3D,MAAM,iBAAiB,OAAO,QAAQ,uBAAuB;EAE7D,IAAI,eAAe,SAAS,GAAG;GAC7B,UAAU;GACV,eAAe,SAAS,CAAC,KAAK,WAAW;IACvC,UAAU,KAAK,IAAI,IAAI,KAAK,UAAU,KAAK,EAAE;GAC/C,CAAC;EACH;EAGA,IAAI,MAAM,OAAO,OACf,UAAU,KAAK,MAAM,MAAM,MAAM;EAGnC,OAAO,OAAO,QAAQ;CACxB;AACF"}
@@ -1,2 +1,2 @@
1
- import { n as MacroFunction, t as Macroable } from "../index-B4UBK-2T.mjs";
2
- export { MacroFunction, Macroable };
1
+ import { n as MacroFunction, t as Macroable } from "../index-0ItCjaqw.mjs";
2
+ export { type MacroFunction, Macroable };
@@ -1,2 +1,2 @@
1
- import { t as Macroable } from "../macroable-DzlfzT50.mjs";
1
+ import { t as Macroable } from "../macroable-cvDTFZ_A.mjs";
2
2
  export { Macroable };
@@ -119,4 +119,4 @@ var Macroable = class {
119
119
  //#endregion
120
120
  export { Macroable as t };
121
121
 
122
- //# sourceMappingURL=macroable-DzlfzT50.mjs.map
122
+ //# sourceMappingURL=macroable-cvDTFZ_A.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"macroable-DzlfzT50.mjs","names":[],"sources":["../src/macroable/macroable.ts"],"sourcesContent":["import type { MacroFunction } from './types'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor = abstract new (...args: any[]) => any\n\n/**\n * Abstract base class for adding macros, instance properties, and getters\n * to classes at runtime.\n *\n * Inspired by [@poppinss/macroable](https://github.com/poppinss/macroable)\n * and Laravel's Macroable trait.\n *\n * @example\n * ```typescript\n * // Register a macro\n * RouterContext.macro('flash', function (this: RouterContext, key: string, value: unknown) {\n * const session = this.getContainer().resolve(SessionService)\n * session.flash(key, value)\n * })\n *\n * // Register a getter\n * RouterContext.getter('requestId', function (this: RouterContext) {\n * return this.header('x-request-id') ?? crypto.randomUUID()\n * }, true)\n *\n * // Register a per-instance property (safe for destructuring)\n * RouterContext.instanceProperty('getUser', function (this: RouterContext) {\n * return this.getContainer().resolve(AuthContext).user\n * })\n * ```\n */\nexport abstract class Macroable {\n [key: string | symbol]: unknown\n /**\n * Per-instance properties. Each entry is applied and bound\n * to `this` inside the constructor so destructuring stays safe.\n */\n protected static instanceMacros = new Set<{ key: string | symbol; value: unknown }>()\n\n /**\n * Names registered via macro() — used by hasMacro() and flushMacros().\n */\n protected static macroNames = new Set<string | symbol>()\n\n /**\n * Names registered via getter() — used by hasMacro() and flushMacros().\n */\n protected static getterNames = new Set<string | symbol>()\n\n /**\n * Original prototype values saved before macro() overrides them.\n * Used by flushMacros() to restore native methods.\n */\n private static _originals = new Map<string | symbol, { existed: boolean; value: unknown }>()\n\n // ── Macros (prototype-level) ──────────────────────────────\n\n /**\n * Register a macro on the class prototype.\n * Can override existing methods.\n *\n * When the name matches an existing property, the value type is auto-derived.\n *\n * @param name - Method or property name\n * @param value - Function or value to assign\n */\n static macro<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n value: InstanceType<T>[K],\n ): void\n static macro(name: string | symbol, value: unknown): void\n static macro(name: string | symbol, value: unknown): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'macroNames')) {\n this.macroNames = new Set(this.macroNames)\n }\n if (!Object.prototype.hasOwnProperty.call(this, '_originals')) {\n this._originals = new Map(this._originals)\n }\n\n // Save the original value before first override so flushMacros() can restore it\n if (!this._originals.has(name)) {\n const existed = Object.prototype.hasOwnProperty.call(this.prototype, name)\n this._originals.set(name, {\n existed,\n value: existed ? (this.prototype as Record<string | symbol, unknown>)[name] : undefined,\n })\n }\n\n this.macroNames.add(name);\n (this.prototype as Record<string | symbol, unknown>)[name] = value\n }\n\n // ── Instance properties (bound per-instance) ─────────────\n\n /**\n * Register a per-instance property that is bound to `this`\n * in the constructor. Safe for destructuring.\n *\n * When the name matches an existing property, the value type is auto-derived.\n *\n * @param name - Property name\n * @param value - Function (will be bound) or value\n */\n static instanceProperty<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n value: InstanceType<T>[K],\n ): void\n static instanceProperty(name: string | symbol, value: unknown): void\n static instanceProperty(name: string | symbol, value: unknown): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'instanceMacros')) {\n this.instanceMacros = new Set(this.instanceMacros)\n }\n this.instanceMacros.add({ key: name, value })\n }\n\n // ── Getters (Object.defineProperty on prototype) ──────────\n\n /**\n * Register a computed getter on the class prototype.\n *\n * @param name - Property name\n * @param accumulator - Function that computes the value (called with instance as `this`)\n * @param singleton - If true, cache the value after first access\n */\n static getter<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n accumulator: (this: InstanceType<T>) => InstanceType<T>[K],\n singleton?: boolean,\n ): void\n static getter(name: string | symbol, accumulator: MacroFunction, singleton?: boolean): void\n static getter(\n name: string | symbol,\n accumulator: MacroFunction,\n singleton = false,\n ): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'getterNames')) {\n this.getterNames = new Set(this.getterNames)\n }\n this.getterNames.add(name)\n\n Object.defineProperty(this.prototype, name, {\n get(): unknown {\n const value: unknown = accumulator.call(this)\n if (singleton) {\n Object.defineProperty(this, name, {\n value,\n configurable: false,\n enumerable: false,\n writable: false,\n })\n }\n return value\n },\n configurable: true,\n enumerable: false,\n })\n }\n\n // ── Introspection ─────────────────────────────────────────\n\n /**\n * Check if a macro, instance property, or getter is registered.\n *\n * @param name - Name to check\n */\n static hasMacro(name: string | symbol): boolean {\n return (\n this.macroNames.has(name) ||\n [...this.instanceMacros].some((m) => m.key === name) ||\n this.getterNames.has(name)\n )\n }\n\n // ── Cleanup ───────────────────────────────────────────────\n\n /**\n * Remove all macros, instance properties, and getters\n * registered on this class. Does not affect parent classes.\n */\n static flushMacros(): void {\n const proto = this.prototype as Record<string | symbol, unknown>\n\n // Restore original prototype values or delete if they didn't exist before\n for (const name of this.macroNames) {\n const original = this._originals.get(name)\n if (original?.existed) {\n proto[name] = original.value\n } else {\n Reflect.deleteProperty(proto, name)\n }\n }\n for (const name of this.getterNames) {\n Reflect.deleteProperty(proto, name)\n }\n\n if (Object.prototype.hasOwnProperty.call(this, 'macroNames')) {\n this.macroNames.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, 'instanceMacros')) {\n this.instanceMacros.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, 'getterNames')) {\n this.getterNames.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, '_originals')) {\n this._originals.clear()\n }\n }\n\n // ── Constructor (applies instance properties) ─────────────\n\n constructor() {\n const Constructor = this.constructor as typeof Macroable\n const self = this as Record<string | symbol, unknown>\n Constructor.instanceMacros.forEach(({ key, value }) => {\n if (typeof value === 'function') {\n self[key] = value.bind(this)\n } else {\n self[key] = value\n }\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAsB,YAAtB,MAAgC;;;;;CAM9B,OAAiB,iCAAiB,IAAI,KAA+C;;;;CAKrF,OAAiB,6BAAa,IAAI,KAAsB;;;;CAKxD,OAAiB,8BAAc,IAAI,KAAsB;;;;;CAMzD,OAAe,6BAAa,IAAI,KAA4D;CAmB5F,OAAO,MAAM,MAAuB,OAAsB;EACxD,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,EAC3D,KAAK,aAAa,IAAI,IAAI,KAAK,WAAW;EAE5C,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,EAC3D,KAAK,aAAa,IAAI,IAAI,KAAK,WAAW;EAI5C,IAAI,CAAC,KAAK,WAAW,IAAI,KAAK,EAAE;GAC9B,MAAM,UAAU,OAAO,UAAU,eAAe,KAAK,KAAK,WAAW,KAAK;GAC1E,KAAK,WAAW,IAAI,MAAM;IACxB;IACA,OAAO,UAAW,KAAK,UAA+C,QAAQ,KAAA;IAC/E,CAAC;;EAGJ,KAAK,WAAW,IAAI,KAAK;EACzB,KAAM,UAA+C,QAAQ;;CAoB/D,OAAO,iBAAiB,MAAuB,OAAsB;EACnE,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,iBAAiB,EAC/D,KAAK,iBAAiB,IAAI,IAAI,KAAK,eAAe;EAEpD,KAAK,eAAe,IAAI;GAAE,KAAK;GAAM;GAAO,CAAC;;CAmB/C,OAAO,OACL,MACA,aACA,YAAY,OACN;EACN,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,cAAc,EAC5D,KAAK,cAAc,IAAI,IAAI,KAAK,YAAY;EAE9C,KAAK,YAAY,IAAI,KAAK;EAE1B,OAAO,eAAe,KAAK,WAAW,MAAM;GAC1C,MAAe;IACb,MAAM,QAAiB,YAAY,KAAK,KAAK;IAC7C,IAAI,WACF,OAAO,eAAe,MAAM,MAAM;KAChC;KACA,cAAc;KACd,YAAY;KACZ,UAAU;KACX,CAAC;IAEJ,OAAO;;GAET,cAAc;GACd,YAAY;GACb,CAAC;;;;;;;CAUJ,OAAO,SAAS,MAAgC;EAC9C,OACE,KAAK,WAAW,IAAI,KAAK,IACzB,CAAC,GAAG,KAAK,eAAe,CAAC,MAAM,MAAM,EAAE,QAAQ,KAAK,IACpD,KAAK,YAAY,IAAI,KAAK;;;;;;CAU9B,OAAO,cAAoB;EACzB,MAAM,QAAQ,KAAK;EAGnB,KAAK,MAAM,QAAQ,KAAK,YAAY;GAClC,MAAM,WAAW,KAAK,WAAW,IAAI,KAAK;GAC1C,IAAI,UAAU,SACZ,MAAM,QAAQ,SAAS;QAEvB,QAAQ,eAAe,OAAO,KAAK;;EAGvC,KAAK,MAAM,QAAQ,KAAK,aACtB,QAAQ,eAAe,OAAO,KAAK;EAGrC,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,EAC1D,KAAK,WAAW,OAAO;EAEzB,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,iBAAiB,EAC9D,KAAK,eAAe,OAAO;EAE7B,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,cAAc,EAC3D,KAAK,YAAY,OAAO;EAE1B,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,EAC1D,KAAK,WAAW,OAAO;;CAM3B,cAAc;EACZ,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO;EACb,YAAY,eAAe,SAAS,EAAE,KAAK,YAAY;GACrD,IAAI,OAAO,UAAU,YACnB,KAAK,OAAO,MAAM,KAAK,KAAK;QAE5B,KAAK,OAAO;IAEd"}
1
+ {"version":3,"file":"macroable-cvDTFZ_A.mjs","names":[],"sources":["../src/macroable/macroable.ts"],"sourcesContent":["import type { MacroFunction } from './types'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor = abstract new (...args: any[]) => any\n\n/**\n * Abstract base class for adding macros, instance properties, and getters\n * to classes at runtime.\n *\n * Inspired by [@poppinss/macroable](https://github.com/poppinss/macroable)\n * and Laravel's Macroable trait.\n *\n * @example\n * ```typescript\n * // Register a macro\n * RouterContext.macro('flash', function (this: RouterContext, key: string, value: unknown) {\n * const session = this.getContainer().resolve(SessionService)\n * session.flash(key, value)\n * })\n *\n * // Register a getter\n * RouterContext.getter('requestId', function (this: RouterContext) {\n * return this.header('x-request-id') ?? crypto.randomUUID()\n * }, true)\n *\n * // Register a per-instance property (safe for destructuring)\n * RouterContext.instanceProperty('getUser', function (this: RouterContext) {\n * return this.getContainer().resolve(AuthContext).user\n * })\n * ```\n */\nexport abstract class Macroable {\n [key: string | symbol]: unknown\n /**\n * Per-instance properties. Each entry is applied and bound\n * to `this` inside the constructor so destructuring stays safe.\n */\n protected static instanceMacros = new Set<{ key: string | symbol; value: unknown }>()\n\n /**\n * Names registered via macro() — used by hasMacro() and flushMacros().\n */\n protected static macroNames = new Set<string | symbol>()\n\n /**\n * Names registered via getter() — used by hasMacro() and flushMacros().\n */\n protected static getterNames = new Set<string | symbol>()\n\n /**\n * Original prototype values saved before macro() overrides them.\n * Used by flushMacros() to restore native methods.\n */\n private static _originals = new Map<string | symbol, { existed: boolean; value: unknown }>()\n\n // ── Macros (prototype-level) ──────────────────────────────\n\n /**\n * Register a macro on the class prototype.\n * Can override existing methods.\n *\n * When the name matches an existing property, the value type is auto-derived.\n *\n * @param name - Method or property name\n * @param value - Function or value to assign\n */\n static macro<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n value: InstanceType<T>[K],\n ): void\n static macro(name: string | symbol, value: unknown): void\n static macro(name: string | symbol, value: unknown): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'macroNames')) {\n this.macroNames = new Set(this.macroNames)\n }\n if (!Object.prototype.hasOwnProperty.call(this, '_originals')) {\n this._originals = new Map(this._originals)\n }\n\n // Save the original value before first override so flushMacros() can restore it\n if (!this._originals.has(name)) {\n const existed = Object.prototype.hasOwnProperty.call(this.prototype, name)\n this._originals.set(name, {\n existed,\n value: existed ? (this.prototype as Record<string | symbol, unknown>)[name] : undefined,\n })\n }\n\n this.macroNames.add(name);\n (this.prototype as Record<string | symbol, unknown>)[name] = value\n }\n\n // ── Instance properties (bound per-instance) ─────────────\n\n /**\n * Register a per-instance property that is bound to `this`\n * in the constructor. Safe for destructuring.\n *\n * When the name matches an existing property, the value type is auto-derived.\n *\n * @param name - Property name\n * @param value - Function (will be bound) or value\n */\n static instanceProperty<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n value: InstanceType<T>[K],\n ): void\n static instanceProperty(name: string | symbol, value: unknown): void\n static instanceProperty(name: string | symbol, value: unknown): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'instanceMacros')) {\n this.instanceMacros = new Set(this.instanceMacros)\n }\n this.instanceMacros.add({ key: name, value })\n }\n\n // ── Getters (Object.defineProperty on prototype) ──────────\n\n /**\n * Register a computed getter on the class prototype.\n *\n * @param name - Property name\n * @param accumulator - Function that computes the value (called with instance as `this`)\n * @param singleton - If true, cache the value after first access\n */\n static getter<T extends Constructor, K extends keyof InstanceType<T>>(\n this: T,\n name: K,\n accumulator: (this: InstanceType<T>) => InstanceType<T>[K],\n singleton?: boolean,\n ): void\n static getter(name: string | symbol, accumulator: MacroFunction, singleton?: boolean): void\n static getter(\n name: string | symbol,\n accumulator: MacroFunction,\n singleton = false,\n ): void {\n if (!Object.prototype.hasOwnProperty.call(this, 'getterNames')) {\n this.getterNames = new Set(this.getterNames)\n }\n this.getterNames.add(name)\n\n Object.defineProperty(this.prototype, name, {\n get(): unknown {\n const value: unknown = accumulator.call(this)\n if (singleton) {\n Object.defineProperty(this, name, {\n value,\n configurable: false,\n enumerable: false,\n writable: false,\n })\n }\n return value\n },\n configurable: true,\n enumerable: false,\n })\n }\n\n // ── Introspection ─────────────────────────────────────────\n\n /**\n * Check if a macro, instance property, or getter is registered.\n *\n * @param name - Name to check\n */\n static hasMacro(name: string | symbol): boolean {\n return (\n this.macroNames.has(name) ||\n [...this.instanceMacros].some((m) => m.key === name) ||\n this.getterNames.has(name)\n )\n }\n\n // ── Cleanup ───────────────────────────────────────────────\n\n /**\n * Remove all macros, instance properties, and getters\n * registered on this class. Does not affect parent classes.\n */\n static flushMacros(): void {\n const proto = this.prototype as Record<string | symbol, unknown>\n\n // Restore original prototype values or delete if they didn't exist before\n for (const name of this.macroNames) {\n const original = this._originals.get(name)\n if (original?.existed) {\n proto[name] = original.value\n } else {\n Reflect.deleteProperty(proto, name)\n }\n }\n for (const name of this.getterNames) {\n Reflect.deleteProperty(proto, name)\n }\n\n if (Object.prototype.hasOwnProperty.call(this, 'macroNames')) {\n this.macroNames.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, 'instanceMacros')) {\n this.instanceMacros.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, 'getterNames')) {\n this.getterNames.clear()\n }\n if (Object.prototype.hasOwnProperty.call(this, '_originals')) {\n this._originals.clear()\n }\n }\n\n // ── Constructor (applies instance properties) ─────────────\n\n constructor() {\n const Constructor = this.constructor as typeof Macroable\n const self = this as Record<string | symbol, unknown>\n Constructor.instanceMacros.forEach(({ key, value }) => {\n if (typeof value === 'function') {\n self[key] = value.bind(this)\n } else {\n self[key] = value\n }\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAsB,YAAtB,MAAgC;;;;;CAM9B,OAAiB,iCAAiB,IAAI,IAA8C;;;;CAKpF,OAAiB,6BAAa,IAAI,IAAqB;;;;CAKvD,OAAiB,8BAAc,IAAI,IAAqB;;;;;CAMxD,OAAe,6BAAa,IAAI,IAA2D;CAmB3F,OAAO,MAAM,MAAuB,OAAsB;EACxD,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,YAAY,GAC1D,KAAK,aAAa,IAAI,IAAI,KAAK,UAAU;EAE3C,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,YAAY,GAC1D,KAAK,aAAa,IAAI,IAAI,KAAK,UAAU;EAI3C,IAAI,CAAC,KAAK,WAAW,IAAI,IAAI,GAAG;GAC9B,MAAM,UAAU,OAAO,UAAU,eAAe,KAAK,KAAK,WAAW,IAAI;GACzE,KAAK,WAAW,IAAI,MAAM;IACxB;IACA,OAAO,UAAW,KAAK,UAA+C,QAAQ,KAAA;GAChF,CAAC;EACH;EAEA,KAAK,WAAW,IAAI,IAAI;EACxB,KAAM,UAA+C,QAAQ;CAC/D;CAmBA,OAAO,iBAAiB,MAAuB,OAAsB;EACnE,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,gBAAgB,GAC9D,KAAK,iBAAiB,IAAI,IAAI,KAAK,cAAc;EAEnD,KAAK,eAAe,IAAI;GAAE,KAAK;GAAM;EAAM,CAAC;CAC9C;CAkBA,OAAO,OACL,MACA,aACA,YAAY,OACN;EACN,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,GAC3D,KAAK,cAAc,IAAI,IAAI,KAAK,WAAW;EAE7C,KAAK,YAAY,IAAI,IAAI;EAEzB,OAAO,eAAe,KAAK,WAAW,MAAM;GAC1C,MAAe;IACb,MAAM,QAAiB,YAAY,KAAK,IAAI;IAC5C,IAAI,WACF,OAAO,eAAe,MAAM,MAAM;KAChC;KACA,cAAc;KACd,YAAY;KACZ,UAAU;IACZ,CAAC;IAEH,OAAO;GACT;GACA,cAAc;GACd,YAAY;EACd,CAAC;CACH;;;;;;CASA,OAAO,SAAS,MAAgC;EAC9C,OACE,KAAK,WAAW,IAAI,IAAI,KACxB,CAAC,GAAG,KAAK,cAAc,EAAE,MAAM,MAAM,EAAE,QAAQ,IAAI,KACnD,KAAK,YAAY,IAAI,IAAI;CAE7B;;;;;CAQA,OAAO,cAAoB;EACzB,MAAM,QAAQ,KAAK;EAGnB,KAAK,MAAM,QAAQ,KAAK,YAAY;GAClC,MAAM,WAAW,KAAK,WAAW,IAAI,IAAI;GACzC,IAAI,UAAU,SACZ,MAAM,QAAQ,SAAS;QAEvB,QAAQ,eAAe,OAAO,IAAI;EAEtC;EACA,KAAK,MAAM,QAAQ,KAAK,aACtB,QAAQ,eAAe,OAAO,IAAI;EAGpC,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,YAAY,GACzD,KAAK,WAAW,MAAM;EAExB,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,gBAAgB,GAC7D,KAAK,eAAe,MAAM;EAE5B,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,GAC1D,KAAK,YAAY,MAAM;EAEzB,IAAI,OAAO,UAAU,eAAe,KAAK,MAAM,YAAY,GACzD,KAAK,WAAW,MAAM;CAE1B;CAIA,cAAc;EACZ,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO;EACb,YAAY,eAAe,SAAS,EAAE,KAAK,YAAY;GACrD,IAAI,OAAO,UAAU,YACnB,KAAK,OAAO,MAAM,KAAK,IAAI;QAE3B,KAAK,OAAO;EAEhB,CAAC;CACH;AACF"}
@@ -36,4 +36,4 @@ function hasMetadata(key, target, propertyKey) {
36
36
  //#endregion
37
37
  export { getMetadata as n, hasMetadata as r, defineMetadata as t };
38
38
 
39
- //# sourceMappingURL=metadata-BVkc4aUu.mjs.map
39
+ //# sourceMappingURL=metadata-DzzprcID.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-BVkc4aUu.mjs","names":[],"sources":["../src/di/metadata.ts"],"sourcesContent":["type MetadataTarget = object | string | symbol\n\nconst STORE_KEY = Symbol.for('stratal:metadata:store')\nconst g = globalThis as Record<symbol, unknown>\nconst store: WeakMap<object, Map<MetadataTarget, unknown>> =\n (g[STORE_KEY] as WeakMap<object, Map<MetadataTarget, unknown>>) ??\n (g[STORE_KEY] = new WeakMap<object, Map<MetadataTarget, unknown>>())\n\nfunction getKeyTarget(target: object, propertyKey?: string | symbol): object {\n if (propertyKey === undefined) return target\n let propMap = store.get(target)\n if (!propMap) {\n propMap = new Map()\n store.set(target, propMap)\n }\n let propTarget = propMap.get(propertyKey) as object | undefined\n if (!propTarget) {\n propTarget = Object.create(null) as object\n propMap.set(propertyKey, propTarget)\n }\n return propTarget\n}\n\nexport function defineMetadata(key: symbol, value: unknown, target: object, propertyKey?: string | symbol): void {\n const resolved = getKeyTarget(target, propertyKey)\n let meta = store.get(resolved)\n if (!meta) {\n meta = new Map()\n store.set(resolved, meta)\n }\n meta.set(key, value)\n}\n\nexport function getMetadata<T = unknown>(key: symbol, target: object, propertyKey?: string | symbol): T | undefined {\n const resolved = getKeyTarget(target, propertyKey)\n return store.get(resolved)?.get(key) as T | undefined\n}\n\nexport function hasMetadata(key: symbol, target: object, propertyKey?: string | symbol): boolean {\n const resolved = getKeyTarget(target, propertyKey)\n return store.get(resolved)?.has(key) ?? false\n}\n"],"mappings":";AAEA,MAAM,YAAY,OAAO,IAAI,yBAAyB;AACtD,MAAM,IAAI;AACV,MAAM,QACH,EAAE,eACF,EAAE,6BAAa,IAAI,SAA+C;AAErE,SAAS,aAAa,QAAgB,aAAuC;CAC3E,IAAI,gBAAgB,KAAA,GAAW,OAAO;CACtC,IAAI,UAAU,MAAM,IAAI,OAAO;CAC/B,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,KAAK;EACnB,MAAM,IAAI,QAAQ,QAAQ;;CAE5B,IAAI,aAAa,QAAQ,IAAI,YAAY;CACzC,IAAI,CAAC,YAAY;EACf,aAAa,OAAO,OAAO,KAAK;EAChC,QAAQ,IAAI,aAAa,WAAW;;CAEtC,OAAO;;AAGT,SAAgB,eAAe,KAAa,OAAgB,QAAgB,aAAqC;CAC/G,MAAM,WAAW,aAAa,QAAQ,YAAY;CAClD,IAAI,OAAO,MAAM,IAAI,SAAS;CAC9B,IAAI,CAAC,MAAM;EACT,uBAAO,IAAI,KAAK;EAChB,MAAM,IAAI,UAAU,KAAK;;CAE3B,KAAK,IAAI,KAAK,MAAM;;AAGtB,SAAgB,YAAyB,KAAa,QAAgB,aAA8C;CAClH,MAAM,WAAW,aAAa,QAAQ,YAAY;CAClD,OAAO,MAAM,IAAI,SAAS,EAAE,IAAI,IAAI;;AAGtC,SAAgB,YAAY,KAAa,QAAgB,aAAwC;CAC/F,MAAM,WAAW,aAAa,QAAQ,YAAY;CAClD,OAAO,MAAM,IAAI,SAAS,EAAE,IAAI,IAAI,IAAI"}
1
+ {"version":3,"file":"metadata-DzzprcID.mjs","names":[],"sources":["../src/di/metadata.ts"],"sourcesContent":["type MetadataTarget = object | string | symbol\n\nconst STORE_KEY = Symbol.for('stratal:metadata:store')\nconst g = globalThis as Record<symbol, unknown>\nconst store: WeakMap<object, Map<MetadataTarget, unknown>> =\n (g[STORE_KEY] as WeakMap<object, Map<MetadataTarget, unknown>>) ??\n (g[STORE_KEY] = new WeakMap<object, Map<MetadataTarget, unknown>>())\n\nfunction getKeyTarget(target: object, propertyKey?: string | symbol): object {\n if (propertyKey === undefined) return target\n let propMap = store.get(target)\n if (!propMap) {\n propMap = new Map()\n store.set(target, propMap)\n }\n let propTarget = propMap.get(propertyKey) as object | undefined\n if (!propTarget) {\n propTarget = Object.create(null) as object\n propMap.set(propertyKey, propTarget)\n }\n return propTarget\n}\n\nexport function defineMetadata(key: symbol, value: unknown, target: object, propertyKey?: string | symbol): void {\n const resolved = getKeyTarget(target, propertyKey)\n let meta = store.get(resolved)\n if (!meta) {\n meta = new Map()\n store.set(resolved, meta)\n }\n meta.set(key, value)\n}\n\nexport function getMetadata<T = unknown>(key: symbol, target: object, propertyKey?: string | symbol): T | undefined {\n const resolved = getKeyTarget(target, propertyKey)\n return store.get(resolved)?.get(key) as T | undefined\n}\n\nexport function hasMetadata(key: symbol, target: object, propertyKey?: string | symbol): boolean {\n const resolved = getKeyTarget(target, propertyKey)\n return store.get(resolved)?.has(key) ?? false\n}\n"],"mappings":";AAEA,MAAM,YAAY,OAAO,IAAI,wBAAwB;AACrD,MAAM,IAAI;AACV,MAAM,QACH,EAAE,eACF,EAAE,6BAAa,IAAI,QAA8C;AAEpE,SAAS,aAAa,QAAgB,aAAuC;CAC3E,IAAI,gBAAgB,KAAA,GAAW,OAAO;CACtC,IAAI,UAAU,MAAM,IAAI,MAAM;CAC9B,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,IAAI;EAClB,MAAM,IAAI,QAAQ,OAAO;CAC3B;CACA,IAAI,aAAa,QAAQ,IAAI,WAAW;CACxC,IAAI,CAAC,YAAY;EACf,aAAa,OAAO,OAAO,IAAI;EAC/B,QAAQ,IAAI,aAAa,UAAU;CACrC;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,KAAa,OAAgB,QAAgB,aAAqC;CAC/G,MAAM,WAAW,aAAa,QAAQ,WAAW;CACjD,IAAI,OAAO,MAAM,IAAI,QAAQ;CAC7B,IAAI,CAAC,MAAM;EACT,uBAAO,IAAI,IAAI;EACf,MAAM,IAAI,UAAU,IAAI;CAC1B;CACA,KAAK,IAAI,KAAK,KAAK;AACrB;AAEA,SAAgB,YAAyB,KAAa,QAAgB,aAA8C;CAClH,MAAM,WAAW,aAAa,QAAQ,WAAW;CACjD,OAAO,MAAM,IAAI,QAAQ,GAAG,IAAI,GAAG;AACrC;AAEA,SAAgB,YAAY,KAAa,QAAgB,aAAwC;CAC/F,MAAM,WAAW,aAAa,QAAQ,WAAW;CACjD,OAAO,MAAM,IAAI,QAAQ,GAAG,IAAI,GAAG,KAAK;AAC1C"}
@@ -1,5 +1,6 @@
1
- import { An as OnException, Cn as ClassProvider, Dn as ModuleClass, En as FactoryProvider, Ln as InjectionToken, Mn as OnShutdown, Nn as Provider, On as ModuleContext, Pn as ValueProvider, Sn as AsyncModuleOptions, Tn as ExistingProvider, an as ModuleRegistry, jn as OnInitialize, kn as ModuleOptions, wn as DynamicModule, xr as ApplicationError } from "../index-DEncMcC6.mjs";
2
- import { t as Constructor } from "../types-BaeHi67f.mjs";
1
+ import { An as ExistingProvider, Dn as AsyncModuleOptions, Dr as ApplicationError, Fn as OnException, Hn as InjectionToken, In as OnInitialize, Ln as OnShutdown, Mn as ModuleClass, Nn as ModuleContext, On as ClassProvider, Pn as ModuleOptions, Rn as Provider, jn as FactoryProvider, kn as DynamicModule, ln as ModuleRegistry, zn as ValueProvider } from "../index-B_JoEl3V.mjs";
2
+ import { t as Constructor } from "../types-CmV_9xBD.mjs";
3
+ import { n as ModuleRef, t as LazyModuleLoader } from "../lazy-module-loader-Ib383jH_.mjs";
3
4
 
4
5
  //#region src/module/module.error.d.ts
5
6
  declare class ModuleError extends ApplicationError {}
@@ -10,5 +11,5 @@ declare function Module(options: ModuleOptions): <TFunction extends abstract new
10
11
  declare function getModuleOptions(target: Constructor): ModuleOptions | undefined;
11
12
  declare function isModuleClass(target: unknown): target is Constructor;
12
13
  //#endregion
13
- export { AsyncModuleOptions, ClassProvider, DynamicModule, ExistingProvider, FactoryProvider, InjectionToken, MODULE_OPTIONS_KEY, Module, ModuleClass, ModuleContext, ModuleError, ModuleOptions, ModuleRegistry, OnException, OnInitialize, OnShutdown, Provider, ValueProvider, getModuleOptions, isModuleClass };
14
+ export { AsyncModuleOptions, ClassProvider, DynamicModule, ExistingProvider, FactoryProvider, type InjectionToken, LazyModuleLoader, MODULE_OPTIONS_KEY, Module, ModuleClass, ModuleContext, ModuleError, ModuleOptions, ModuleRef, ModuleRegistry, OnException, OnInitialize, OnShutdown, Provider, ValueProvider, getModuleOptions, isModuleClass };
14
15
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/module/module.error.ts","../../src/module/module.decorator.ts"],"mappings":";;;;cAEa,WAAA,SAAoB,gBAAA;;;cCEpB,kBAAA;AAAA,iBAEG,MAAA,CAAO,OAAA,EAAS,aAAA,uCACa,IAAA,uBAA2B,MAAA,EAAQ,SAAA,KAAY,SAAA;AAAA,iBAM5E,gBAAA,CAAiB,MAAA,EAAQ,WAAA,GAAc,aAAA;AAAA,iBAIvC,aAAA,CAAc,MAAA,YAAkB,MAAA,IAAU,WAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/module/module.error.ts","../../src/module/module.decorator.ts"],"mappings":";;;;;cAEa,WAAA,SAAoB,gBAAgB;;;cCEpC,kBAAA;AAAA,iBAEG,MAAA,CAAO,OAAA,EAAS,aAAA,uCACa,IAAA,uBAA2B,MAAA,EAAQ,SAAA,KAAY,SAAA;AAAA,iBAM5E,gBAAA,CAAiB,MAAA,EAAQ,WAAA,GAAc,aAAa;AAAA,iBAIpD,aAAA,CAAc,MAAA,YAAkB,MAAA,IAAU,WAAW"}
@@ -1,2 +1,10 @@
1
- import { d as MODULE_OPTIONS_KEY, f as Module, h as ModuleError, m as isModuleClass, p as getModuleOptions, t as ModuleRegistry } from "../module-xYoHba6B.mjs";
2
- export { MODULE_OPTIONS_KEY, Module, ModuleError, ModuleRegistry, getModuleOptions, isModuleClass };
1
+ import { a as ApplicationError } from "../container-storage-BmOJ4_Na.mjs";
2
+ import "../errors-mXYxG0XB.mjs";
3
+ import { i as isModuleClass, n as Module, r as getModuleOptions, t as MODULE_OPTIONS_KEY } from "../module.decorator-CYHY6pG5.mjs";
4
+ import { d as LazyModuleLoader, f as ModuleRef, t as ModuleRegistry } from "../module-registry-Dm-pqHd3.mjs";
5
+ //#region src/module/module.error.ts
6
+ var ModuleError = class extends ApplicationError {};
7
+ //#endregion
8
+ export { LazyModuleLoader, MODULE_OPTIONS_KEY, Module, ModuleError, ModuleRef, ModuleRegistry, getModuleOptions, isModuleClass };
9
+
10
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/module/module.error.ts"],"sourcesContent":["import { ApplicationError } from '../errors'\n\nexport class ModuleError extends ApplicationError {}\n"],"mappings":";;;;;AAEA,IAAa,cAAb,cAAiC,iBAAiB,CAAC"}