stratal 0.0.21 → 0.0.23

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 (296) hide show
  1. package/README.md +2 -2
  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 +84 -160
  5. package/dist/bin/quarry.mjs.map +1 -1
  6. package/dist/cache/index.d.mts +8 -46
  7. package/dist/cache/index.d.mts.map +1 -1
  8. package/dist/cache/index.mjs +134 -97
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-uElmBtdS.d.mts} +29 -39
  11. package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
  12. package/dist/{command-BgSlsS4M.mjs → command-BvmUAPPQ.mjs} +15 -4
  13. package/dist/command-BvmUAPPQ.mjs.map +1 -0
  14. package/dist/{command-Cmmf0oHX.d.mts → command-CPhFHjG3.d.mts} +3 -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 +24 -11
  19. package/dist/config/index.d.mts.map +1 -1
  20. package/dist/config/index.mjs +32 -57
  21. package/dist/config/index.mjs.map +1 -1
  22. package/dist/{consumer-registry-B7yUNh0q.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-BmOJ4_Na.mjs +52 -0
  25. package/dist/container-storage-BmOJ4_Na.mjs.map +1 -0
  26. package/dist/{controller.decorator-B9vwn0zK.mjs → controller.decorator-C5UVeJS3.mjs} +8 -8
  27. package/dist/controller.decorator-C5UVeJS3.mjs.map +1 -0
  28. package/dist/cron/index.d.mts +103 -7
  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-DQSK8uoV.mjs → cron.module-Bgzq5hiT.mjs} +47 -17
  34. package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
  35. package/dist/decorate-CuAoSZvs.mjs +16 -0
  36. package/dist/deep-merge-ByiAOZ3r.mjs +18 -0
  37. package/dist/deep-merge-ByiAOZ3r.mjs.map +1 -0
  38. package/dist/di/index.d.mts +2 -2
  39. package/dist/di/index.mjs +4 -3
  40. package/dist/di-DseMn-z9.mjs +524 -0
  41. package/dist/di-DseMn-z9.mjs.map +1 -0
  42. package/dist/email/index.d.mts +40 -122
  43. package/dist/email/index.d.mts.map +1 -1
  44. package/dist/email/index.mjs +446 -131
  45. package/dist/email/index.mjs.map +1 -1
  46. package/dist/en-CDZBMcc1.mjs +202 -0
  47. package/dist/en-CDZBMcc1.mjs.map +1 -0
  48. package/dist/{env-D1rcZ8_r.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 +2 -2
  51. package/dist/errors/index.mjs +4 -2
  52. package/dist/errors-mXYxG0XB.mjs +333 -0
  53. package/dist/errors-mXYxG0XB.mjs.map +1 -0
  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-CzCV8jI8.mjs → events-BXJGZjpG.mjs} +23 -13
  58. package/dist/events-BXJGZjpG.mjs.map +1 -0
  59. package/dist/exception-context-kEoMFwze.mjs +429 -0
  60. package/dist/exception-context-kEoMFwze.mjs.map +1 -0
  61. package/dist/{gateway-context-CXmXtaUP.mjs → gateway-context-TMu_AlJt.mjs} +38 -31
  62. package/dist/gateway-context-TMu_AlJt.mjs.map +1 -0
  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-DU1_J9YA.mjs → guards-DALPXy3_.mjs} +6 -5
  67. package/dist/guards-DALPXy3_.mjs.map +1 -0
  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-BrgHMdLQ.mjs → http-method.decorator-ByWZb9DO.mjs} +7 -6
  71. package/dist/http-method.decorator-ByWZb9DO.mjs.map +1 -0
  72. package/dist/i18n/index.d.mts +238 -3
  73. package/dist/i18n/index.d.mts.map +1 -0
  74. package/dist/i18n/index.mjs +39 -3
  75. package/dist/i18n/index.mjs.map +1 -0
  76. package/dist/i18n/messages/en/index.d.mts +2 -2
  77. package/dist/i18n/messages/en/index.mjs +2 -2
  78. package/dist/i18n/utils/index.d.mts +4 -26
  79. package/dist/i18n/utils/index.d.mts.map +1 -1
  80. package/dist/i18n/utils/index.mjs +2 -2
  81. package/dist/i18n/validation/index.d.mts +3 -2
  82. package/dist/i18n/validation/index.mjs +4 -2
  83. package/dist/i18n.module-DRQAZoSZ.mjs +222 -0
  84. package/dist/i18n.module-DRQAZoSZ.mjs.map +1 -0
  85. package/dist/i18n.tokens-CZ_v8oyS.mjs +19 -0
  86. package/dist/i18n.tokens-CZ_v8oyS.mjs.map +1 -0
  87. package/dist/{index-7-hU3GTV.d.mts → index-0ItCjaqw.d.mts} +1 -1
  88. package/dist/index-0ItCjaqw.d.mts.map +1 -0
  89. package/dist/index-B5JBRcWD.d.mts +544 -0
  90. package/dist/index-B5JBRcWD.d.mts.map +1 -0
  91. package/dist/index-BUt92sAE.d.mts +124 -0
  92. package/dist/index-BUt92sAE.d.mts.map +1 -0
  93. package/dist/{index-ByOyTmqf.d.mts → index-B_JoEl3V.d.mts} +751 -2229
  94. package/dist/index-B_JoEl3V.d.mts.map +1 -0
  95. package/dist/index-DtBNIFuP.d.mts +42 -0
  96. package/dist/index-DtBNIFuP.d.mts.map +1 -0
  97. package/dist/{index-C1KvMncZ.d.mts → index-HgOLNruQ.d.mts} +3 -108
  98. package/dist/index-HgOLNruQ.d.mts.map +1 -0
  99. package/dist/index.d.mts +6 -43
  100. package/dist/index.mjs +3 -2
  101. package/dist/{is-command-C6a7WTPw.mjs → is-command-CEPO9n8c.mjs} +2 -2
  102. package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
  103. package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
  104. package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
  105. package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
  106. package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
  107. package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
  108. package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
  109. package/dist/locale-url-nZrZxqJP.mjs +44 -0
  110. package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
  111. package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
  112. package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
  113. package/dist/logger/index.d.mts +2 -2
  114. package/dist/logger/index.mjs +170 -2
  115. package/dist/logger/index.mjs.map +1 -0
  116. package/dist/macroable/index.d.mts +2 -2
  117. package/dist/macroable/index.mjs +1 -1
  118. package/dist/{macroable-BmufBshB.mjs → macroable-cvDTFZ_A.mjs} +1 -1
  119. package/dist/{macroable-BmufBshB.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
  120. package/dist/metadata-DzzprcID.mjs +39 -0
  121. package/dist/metadata-DzzprcID.mjs.map +1 -0
  122. package/dist/module/index.d.mts +7 -24
  123. package/dist/module/index.d.mts.map +1 -1
  124. package/dist/module/index.mjs +10 -2
  125. package/dist/module/index.mjs.map +1 -0
  126. package/dist/module-registry-Dm-pqHd3.mjs +554 -0
  127. package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
  128. package/dist/module.decorator-CYHY6pG5.mjs +19 -0
  129. package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
  130. package/dist/openapi/index.d.mts +44 -8
  131. package/dist/openapi/index.d.mts.map +1 -1
  132. package/dist/openapi/index.mjs +3 -3
  133. package/dist/openapi-CstuTM8S.mjs +309 -0
  134. package/dist/openapi-CstuTM8S.mjs.map +1 -0
  135. package/dist/{openapi-tools.service-Zs-Ewv7F.mjs → openapi-tools.service-BC5EC3R3.mjs} +8 -2
  136. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
  137. package/dist/{openapi.service-Bt9bCIrd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
  138. package/dist/openapi.service-YhTiJ1bO.d.mts.map +1 -0
  139. package/dist/quarry/index.d.mts +14 -163
  140. package/dist/quarry/index.d.mts.map +1 -1
  141. package/dist/quarry/index.mjs +6 -5
  142. package/dist/quarry/runner.d.mts +184 -0
  143. package/dist/quarry/runner.d.mts.map +1 -0
  144. package/dist/quarry/runner.mjs +945 -0
  145. package/dist/quarry/runner.mjs.map +1 -0
  146. package/dist/quarry-registry-CXg0RFXq.d.mts +69 -0
  147. package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
  148. package/dist/quarry.module-BuRPGMDm.mjs +312 -0
  149. package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
  150. package/dist/queue/index.d.mts +3 -3
  151. package/dist/queue/index.mjs +57 -48
  152. package/dist/queue/index.mjs.map +1 -1
  153. package/dist/queue.module-nddvxzCB.mjs +613 -0
  154. package/dist/queue.module-nddvxzCB.mjs.map +1 -0
  155. package/dist/queue.tokens-DjHnFmre.mjs +11 -0
  156. package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
  157. package/dist/{r2-storage.provider-DuonKeYm.mjs → r2-storage.provider-DCxQt9dD.mjs} +6 -6
  158. package/dist/r2-storage.provider-DCxQt9dD.mjs.map +1 -0
  159. package/dist/{rate-limit.decorator-6qzNcSOt.mjs → rate-limit.decorator-BPAie_p3.mjs} +6 -11
  160. package/dist/rate-limit.decorator-BPAie_p3.mjs.map +1 -0
  161. package/dist/rate-limiter/index.d.mts +11 -50
  162. package/dist/rate-limiter/index.d.mts.map +1 -1
  163. package/dist/rate-limiter/index.mjs +33 -42
  164. package/dist/rate-limiter/index.mjs.map +1 -1
  165. package/dist/route-name-DGoBOfPg.mjs +171 -0
  166. package/dist/route-name-DGoBOfPg.mjs.map +1 -0
  167. package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
  168. package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
  169. package/dist/route-registry-CYqLp2Nj.mjs +123 -0
  170. package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
  171. package/dist/router/index.d.mts +2 -2
  172. package/dist/router/index.mjs +18 -7
  173. package/dist/router-CWGBD-Bg.mjs +78 -0
  174. package/dist/router-CWGBD-Bg.mjs.map +1 -0
  175. package/dist/router-resolver-D4YlPNlm.mjs +88 -0
  176. package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
  177. package/dist/seeder/index.d.mts +16 -11
  178. package/dist/seeder/index.d.mts.map +1 -1
  179. package/dist/seeder/index.mjs +5 -3
  180. package/dist/seeder-7ubkms-Y.mjs +81 -0
  181. package/dist/seeder-7ubkms-Y.mjs.map +1 -0
  182. package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
  183. package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
  184. package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
  185. package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
  186. package/dist/{signed-url-BQPbv2In.mjs → signed-url-DIU0sK_6.mjs} +1 -1
  187. package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
  188. package/dist/storage/index.d.mts +15 -39
  189. package/dist/storage/index.d.mts.map +1 -1
  190. package/dist/storage/index.mjs +3 -3
  191. package/dist/storage/providers/index.d.mts +2 -2
  192. package/dist/storage/providers/index.d.mts.map +1 -1
  193. package/dist/storage/providers/index.mjs +1 -1
  194. package/dist/{storage-D8CBP72Z.mjs → storage-MDZypIE9.mjs} +66 -59
  195. package/dist/storage-MDZypIE9.mjs.map +1 -0
  196. package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -3
  197. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
  198. package/dist/storage.error-Dnib4VHc.mjs +8 -0
  199. package/dist/storage.error-Dnib4VHc.mjs.map +1 -0
  200. package/dist/stratal-DL9M38_s.mjs +383 -0
  201. package/dist/stratal-DL9M38_s.mjs.map +1 -0
  202. package/dist/stratal-DwDJPY9N.d.mts +43 -0
  203. package/dist/stratal-DwDJPY9N.d.mts.map +1 -0
  204. package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
  205. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
  206. package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
  207. package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
  208. package/dist/{types-cySNS_lp.d.mts → types-CmV_9xBD.d.mts} +1 -1
  209. package/dist/types-CmV_9xBD.d.mts.map +1 -0
  210. package/dist/uri-h7Q8Jug9.mjs +251 -0
  211. package/dist/uri-h7Q8Jug9.mjs.map +1 -0
  212. package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DAWYasuP.mjs} +7 -4
  213. package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
  214. package/dist/validation-CpOjviyT.mjs +49 -0
  215. package/dist/validation-CpOjviyT.mjs.map +1 -0
  216. package/dist/validation.context-CRvmrhq7.mjs +117 -0
  217. package/dist/validation.context-CRvmrhq7.mjs.map +1 -0
  218. package/dist/versioning.service-C6aHky8-.mjs +36 -0
  219. package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
  220. package/dist/websocket/index.d.mts +16 -14
  221. package/dist/websocket/index.d.mts.map +1 -1
  222. package/dist/websocket/index.mjs +2 -2
  223. package/dist/workers/index.d.mts +2 -2
  224. package/dist/workers/index.d.mts.map +1 -1
  225. package/dist/workers/index.mjs +3 -2
  226. package/dist/workers/index.mjs.map +1 -1
  227. package/dist/zod-eKqqhZ5_.mjs +72 -0
  228. package/dist/zod-eKqqhZ5_.mjs.map +1 -0
  229. package/dist/{index-Bnpfq6uk.d.mts → zod-wecrEVAs.d.mts} +63 -133
  230. package/dist/zod-wecrEVAs.d.mts.map +1 -0
  231. package/package.json +28 -39
  232. package/dist/base-email.provider-CfQCA08m.mjs +0 -42
  233. package/dist/base-email.provider-CfQCA08m.mjs.map +0 -1
  234. package/dist/cache.service-DsnKuNyO.d.mts.map +0 -1
  235. package/dist/cache.tokens-B7Rw1C9Q.mjs +0 -6
  236. package/dist/cache.tokens-B7Rw1C9Q.mjs.map +0 -1
  237. package/dist/colors-DJaRDXoS.mjs +0 -16
  238. package/dist/colors-DJaRDXoS.mjs.map +0 -1
  239. package/dist/command-BgSlsS4M.mjs.map +0 -1
  240. package/dist/command-Cmmf0oHX.d.mts.map +0 -1
  241. package/dist/consumer-registry-B7yUNh0q.d.mts.map +0 -1
  242. package/dist/controller.decorator-B9vwn0zK.mjs.map +0 -1
  243. package/dist/cron-manager-CmTimEjf.d.mts +0 -131
  244. package/dist/cron-manager-CmTimEjf.d.mts.map +0 -1
  245. package/dist/cron-manager-DQSK8uoV.mjs.map +0 -1
  246. package/dist/en-DSH_bhh6.mjs +0 -308
  247. package/dist/en-DSH_bhh6.mjs.map +0 -1
  248. package/dist/env-D1rcZ8_r.d.mts.map +0 -1
  249. package/dist/errors-COW9-Mar.mjs +0 -1739
  250. package/dist/errors-COW9-Mar.mjs.map +0 -1
  251. package/dist/errors-ORxu1-Bb.mjs +0 -74
  252. package/dist/errors-ORxu1-Bb.mjs.map +0 -1
  253. package/dist/events-CzCV8jI8.mjs.map +0 -1
  254. package/dist/gateway-context-CXmXtaUP.mjs.map +0 -1
  255. package/dist/guards-DU1_J9YA.mjs.map +0 -1
  256. package/dist/http-method.decorator-BrgHMdLQ.mjs.map +0 -1
  257. package/dist/i18n.module-CzXLW9Hy.mjs +0 -2532
  258. package/dist/i18n.module-CzXLW9Hy.mjs.map +0 -1
  259. package/dist/index-7-hU3GTV.d.mts.map +0 -1
  260. package/dist/index-Bnpfq6uk.d.mts.map +0 -1
  261. package/dist/index-ByOyTmqf.d.mts.map +0 -1
  262. package/dist/index-C1KvMncZ.d.mts.map +0 -1
  263. package/dist/index-DBd_2wv8.d.mts +0 -263
  264. package/dist/index-DBd_2wv8.d.mts.map +0 -1
  265. package/dist/index-DUzWs0z7.d.mts +0 -494
  266. package/dist/index-DUzWs0z7.d.mts.map +0 -1
  267. package/dist/index.d.mts.map +0 -1
  268. package/dist/logger-DlV7NtvD.mjs +0 -440
  269. package/dist/logger-DlV7NtvD.mjs.map +0 -1
  270. package/dist/module-BzLg57FK.mjs +0 -866
  271. package/dist/module-BzLg57FK.mjs.map +0 -1
  272. package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
  273. package/dist/openapi.service-Bt9bCIrd.d.mts.map +0 -1
  274. package/dist/quarry-registry-BwY2hOxm.mjs +0 -699
  275. package/dist/quarry-registry-BwY2hOxm.mjs.map +0 -1
  276. package/dist/queue.module-BhCjZp6H.mjs +0 -409
  277. package/dist/queue.module-BhCjZp6H.mjs.map +0 -1
  278. package/dist/r2-storage.provider-DuonKeYm.mjs.map +0 -1
  279. package/dist/rate-limit.decorator-6qzNcSOt.mjs.map +0 -1
  280. package/dist/resend.provider-DB4IlFjG.mjs +0 -68
  281. package/dist/resend.provider-DB4IlFjG.mjs.map +0 -1
  282. package/dist/seeder-zoEfEw9i.mjs +0 -138
  283. package/dist/seeder-zoEfEw9i.mjs.map +0 -1
  284. package/dist/setup-CefZKV_e.mjs +0 -37
  285. package/dist/setup-CefZKV_e.mjs.map +0 -1
  286. package/dist/smtp.provider-B6D7zuWX.mjs +0 -76
  287. package/dist/smtp.provider-B6D7zuWX.mjs.map +0 -1
  288. package/dist/storage-D8CBP72Z.mjs.map +0 -1
  289. package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
  290. package/dist/stratal-CNwpbSZl.mjs +0 -535
  291. package/dist/stratal-CNwpbSZl.mjs.map +0 -1
  292. package/dist/types-cySNS_lp.d.mts.map +0 -1
  293. package/dist/usage-generator-BUdlhnCK.mjs.map +0 -1
  294. package/dist/validation-DtJwAv7O.mjs +0 -248
  295. package/dist/validation-DtJwAv7O.mjs.map +0 -1
  296. /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
@@ -0,0 +1,79 @@
1
+ import { t as CacheService } from "./cache.service-uElmBtdS.mjs";
2
+
3
+ //#region src/cache/services/tiered-cache.service.d.ts
4
+ /**
5
+ * Tiered Cache Service
6
+ *
7
+ * Layers an **isolate-local in-memory L1** over {@link CacheService} (KV, the
8
+ * L2). Opt-in — inject `CACHE_TOKENS.TieredCacheService` instead of
9
+ * `CACHE_TOKENS.CacheService` when you want it.
10
+ *
11
+ * **Why:** KV reads are eventually consistent (a `get` can return an
12
+ * edge-cached value for up to ~60s after a `put`). The L1 makes writes made
13
+ * through *this isolate* immediately and consistently visible to subsequent
14
+ * reads on the same isolate — closing the read-after-write gap KV alone cannot.
15
+ * This is what makes set-once patterns (e.g. queue idempotency markers) reliable
16
+ * within an isolate, even inside KV's consistency window.
17
+ *
18
+ * **Use it for:** set-once / read-mostly values (idempotency claims, immutable
19
+ * lookups). **Do not use it for** read-modify-write counters that need
20
+ * cross-edge freshness (e.g. rate limiting): an isolate that wrote a key reads
21
+ * its own value until the L1 entry expires, so concurrent increments from other
22
+ * isolates are missed and overwritten. Use plain {@link CacheService} (KV) or a
23
+ * Durable-Object store for those.
24
+ *
25
+ * **Semantics:**
26
+ * - L1 caches string-backed values only (`text`/`json`). `arrayBuffer`/`stream`
27
+ * reads and non-string writes bypass and invalidate L1.
28
+ * - `put`/`delete` are write-through: KV and L1 update in lock-step, honoring
29
+ * `expirationTtl`/`expiration` for the L1 entry's own expiry.
30
+ * - `get` populates L1 from `text` reads (the only path that yields the raw
31
+ * string). `json` reads are served from L1 when the string was cached by a
32
+ * prior `put`/`text` read, otherwise they go straight to KV.
33
+ * - `getWithMetadata` and `list` always read KV directly (metadata is not held
34
+ * in L1).
35
+ *
36
+ * **Cross-isolate caveat:** the L1 only observes writes made through its own
37
+ * isolate. A value mutated by another isolate is not seen until the local entry
38
+ * expires or is invalidated by a local write/delete.
39
+ *
40
+ * **Bindings:** `binding(name)` returns a memoized tiered instance per binding,
41
+ * so each KV namespace has its own stable, isolate-lifetime L1.
42
+ */
43
+ declare class TieredCacheService {
44
+ private readonly cache;
45
+ /** Isolate-local L1 tier. Per-instance, so each binding has its own. */
46
+ private readonly l1;
47
+ /** Memoized tiered instances per binding name (each with its own L1). */
48
+ private readonly children;
49
+ constructor(cache: CacheService);
50
+ /**
51
+ * Get the tiered cache bound to a KV namespace by its binding name. Memoized:
52
+ * repeated calls with the same name return the same instance, preserving its
53
+ * isolate-local L1 across requests/messages.
54
+ *
55
+ * @param name - KV namespace binding name (e.g. `'UPLOADS_CACHE'`)
56
+ * @throws {CacheError} If no binding with that name exists in the environment
57
+ */
58
+ binding(name: string): TieredCacheService;
59
+ get(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<string | null>;
60
+ get<ExpectedValue = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<ExpectedValue | null>;
61
+ get(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<ArrayBuffer | null>;
62
+ get(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<ReadableStream | null>;
63
+ getWithMetadata<Metadata = unknown>(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<KVNamespaceGetWithMetadataResult<string, Metadata>>;
64
+ getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<KVNamespaceGetWithMetadataResult<ExpectedValue, Metadata>>;
65
+ getWithMetadata<Metadata = unknown>(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<KVNamespaceGetWithMetadataResult<ArrayBuffer, Metadata>>;
66
+ getWithMetadata<Metadata = unknown>(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<KVNamespaceGetWithMetadataResult<ReadableStream, Metadata>>;
67
+ put(key: string, value: string | ArrayBuffer | ArrayBufferView | ReadableStream, options?: KVNamespacePutOptions): Promise<void>;
68
+ delete(key: string): Promise<void>;
69
+ list<Metadata = unknown>(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult<Metadata>>;
70
+ /** Read a fresh L1 entry, evicting it if expired. Returns `null` on miss. */
71
+ private l1Read;
72
+ /** Write an L1 entry, refreshing its recency and evicting the oldest at cap. */
73
+ private l1Write;
74
+ /** Compute an absolute L1 expiry (epoch ms) from KV put options. */
75
+ private l1ExpiresAt;
76
+ }
77
+ //#endregion
78
+ export { TieredCacheService as t };
79
+ //# sourceMappingURL=tiered-cache.service-Dv3BhxxE.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiered-cache.service-Dv3BhxxE.d.mts","names":[],"sources":["../src/cache/services/tiered-cache.service.ts"],"mappings":";;;;;AA0DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cACa,kBAAA;EAAA,iBAO2C,KAAA;EA4FnD;EAAA,iBAjGc,EAAA;EAsHL;EAAA,iBApHK,QAAA;cAGqC,KAAA,EAAO,YAAA;EAkH1D;;;;;;;;EAvGH,OAAA,CAAQ,IAAA,WAAe,kBAAA;EAWjB,GAAA,CAAI,GAAA,UAAa,aAAA,YAAyB,qBAAA,WAAgC,OAAA;EAC1E,GAAA,0BAA6B,GAAA,UAAa,aAAA,WAAwB,qBAAA,WAAgC,OAAA,CAAQ,aAAA;EAC1G,GAAA,CAAI,GAAA,UAAa,aAAA,kBAA+B,qBAAA,kBAAuC,OAAA,CAAQ,WAAA;EAC/F,GAAA,CAAI,GAAA,UAAa,aAAA,aAA0B,qBAAA,aAAkC,OAAA,CAAQ,cAAA;EA+BrF,eAAA,qBACJ,GAAA,UACA,aAAA,YAAyB,qBAAA,WACxB,OAAA,CAAQ,gCAAA,SAAyC,QAAA;EAC9C,eAAA,8CACJ,GAAA,UACA,aAAA,WAAwB,qBAAA,WACvB,OAAA,CAAQ,gCAAA,CAAiC,aAAA,EAAe,QAAA;EACrD,eAAA,qBACJ,GAAA,UACA,aAAA,kBAA+B,qBAAA,kBAC9B,OAAA,CAAQ,gCAAA,CAAiC,WAAA,EAAa,QAAA;EACnD,eAAA,qBACJ,GAAA,UACA,aAAA,aAA0B,qBAAA,aACzB,OAAA,CAAQ,gCAAA,CAAiC,cAAA,EAAgB,QAAA;EAiBtD,GAAA,CACJ,GAAA,UACA,KAAA,WAAgB,WAAA,GAAc,eAAA,GAAkB,cAAA,EAChD,OAAA,GAAU,qBAAA,GACT,OAAA;EAaG,MAAA,CAAO,GAAA,WAAc,OAAA;EAOrB,IAAA,qBACJ,OAAA,GAAU,sBAAA,GACT,OAAA,CAAQ,qBAAA,CAAsB,QAAA;EA3FuC;EAAA,QAkGhE,MAAA;EAlGgG;EAAA,QA6GhG,OAAA;EA5GF;EAAA,QAuHE,WAAA;AAAA"}
@@ -0,0 +1,34 @@
1
+ //#region src/router/trailing-slash.ts
2
+ /**
3
+ * Apply a trailing-slash mode to a URL or path.
4
+ *
5
+ * - `'ignore'` — return as-is.
6
+ * - `'always'` — append `/` to the pathname unless it already has one.
7
+ * Skipped when the last segment contains `.` (file-like paths) and for the
8
+ * root `/` path.
9
+ * - `'never'` — strip a trailing `/` from the pathname. Skipped for root.
10
+ *
11
+ * Preserves query string and hash. Handles both relative paths
12
+ * (`/foo?x=1`) and absolute URLs (`https://host/foo?x=1`).
13
+ *
14
+ * Used by URL-generation helpers and the redirect middleware so canonical
15
+ * form is computed in one place.
16
+ */
17
+ function applyTrailingSlash(url, mode) {
18
+ if (mode === "ignore") return url;
19
+ const isAbsolute = /^https?:\/\//i.test(url);
20
+ const parsed = isAbsolute ? new URL(url) : new URL(url, "http://placeholder.local");
21
+ const path = parsed.pathname;
22
+ if (path === "/") return url;
23
+ const hasTrailing = path.endsWith("/");
24
+ if (mode === "always" && !hasTrailing) {
25
+ if (path.slice(path.lastIndexOf("/") + 1).includes(".")) return url;
26
+ parsed.pathname = `${path}/`;
27
+ } else if (mode === "never" && hasTrailing) parsed.pathname = path.slice(0, -1);
28
+ else return url;
29
+ return isAbsolute ? parsed.toString() : `${parsed.pathname}${parsed.search}${parsed.hash}`;
30
+ }
31
+ //#endregion
32
+ export { applyTrailingSlash as t };
33
+
34
+ //# sourceMappingURL=trailing-slash-CFyw8nYu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trailing-slash-CFyw8nYu.mjs","names":[],"sources":["../src/router/trailing-slash.ts"],"sourcesContent":["import type { TrailingSlashMode } from './types'\n\n/**\n * Apply a trailing-slash mode to a URL or path.\n *\n * - `'ignore'` — return as-is.\n * - `'always'` — append `/` to the pathname unless it already has one.\n * Skipped when the last segment contains `.` (file-like paths) and for the\n * root `/` path.\n * - `'never'` — strip a trailing `/` from the pathname. Skipped for root.\n *\n * Preserves query string and hash. Handles both relative paths\n * (`/foo?x=1`) and absolute URLs (`https://host/foo?x=1`).\n *\n * Used by URL-generation helpers and the redirect middleware so canonical\n * form is computed in one place.\n */\nexport function applyTrailingSlash(url: string, mode: TrailingSlashMode): string {\n if (mode === 'ignore') return url\n\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const parsed = isAbsolute\n ? new URL(url)\n : new URL(url, 'http://placeholder.local')\n\n const path = parsed.pathname\n if (path === '/') return url\n\n const hasTrailing = path.endsWith('/')\n\n if (mode === 'always' && !hasTrailing) {\n const lastSegment = path.slice(path.lastIndexOf('/') + 1)\n if (lastSegment.includes('.')) return url\n parsed.pathname = `${path}/`\n } else if (mode === 'never' && hasTrailing) {\n parsed.pathname = path.slice(0, -1)\n } else {\n return url\n }\n\n return isAbsolute\n ? parsed.toString()\n : `${parsed.pathname}${parsed.search}${parsed.hash}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,SAAgB,mBAAmB,KAAa,MAAiC;CAC/E,IAAI,SAAS,UAAU,OAAO;CAE9B,MAAM,aAAa,gBAAgB,KAAK,GAAG;CAC3C,MAAM,SAAS,aACX,IAAI,IAAI,GAAG,IACX,IAAI,IAAI,KAAK,0BAA0B;CAE3C,MAAM,OAAO,OAAO;CACpB,IAAI,SAAS,KAAK,OAAO;CAEzB,MAAM,cAAc,KAAK,SAAS,GAAG;CAErC,IAAI,SAAS,YAAY,CAAC,aAAa;EAErC,IADoB,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CACzC,EAAE,SAAS,GAAG,GAAG,OAAO;EACtC,OAAO,WAAW,GAAG,KAAK;CAC5B,OAAO,IAAI,SAAS,WAAW,aAC7B,OAAO,WAAW,KAAK,MAAM,GAAG,EAAE;MAElC,OAAO;CAGT,OAAO,aACH,OAAO,SAAS,IAChB,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO;AAClD"}
@@ -16,4 +16,4 @@
16
16
  type Constructor<T = object> = new (...args: any[]) => T;
17
17
  //#endregion
18
18
  export { Constructor as t };
19
- //# sourceMappingURL=types-cySNS_lp.d.mts.map
19
+ //# sourceMappingURL=types-CmV_9xBD.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-CmV_9xBD.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;AAeA;;;;;;;;AAA+D;;;;;KAAnD,WAAA,uBAAkC,IAAA,YAAgB,CAAC"}
@@ -0,0 +1,251 @@
1
+ import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
+ import { d as inject, o as Request, r as DI_TOKENS, v as ROUTER_TOKENS } from "./di-DseMn-z9.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
4
+ import { o as RouterError } from "./module-registry-Dm-pqHd3.mjs";
5
+ import { t as applyTrailingSlash } from "./trailing-slash-CFyw8nYu.mjs";
6
+ import { t as applyLocalePrefix } from "./locale-url-nZrZxqJP.mjs";
7
+ import { n as verifySignedUrl, t as signUrl } from "./signed-url-DIU0sK_6.mjs";
8
+ //#region src/router/uri.ts
9
+ var uri_exports = /* @__PURE__ */ __exportAll({
10
+ Uri: () => Uri,
11
+ buildRouteUrl: () => buildRouteUrl
12
+ });
13
+ /**
14
+ * Encode a value for use as a path parameter.
15
+ *
16
+ * Splits on `/` and encodes each segment with `encodeURIComponent`, so callers
17
+ * can pass slash-containing values for catch-all params (e.g. `:slug{.+}`) and
18
+ * still get a usable URL — `'auth/login'` becomes `'auth/login'`, not
19
+ * `'auth%2Flogin'`. Single segments behave exactly like `encodeURIComponent`.
20
+ */
21
+ function encodePathParam(value) {
22
+ return value.split("/").map(encodeURIComponent).join("/");
23
+ }
24
+ /**
25
+ * Build a URL from a registered route, filling path/domain params and appending extras as query string.
26
+ *
27
+ * Pure function — no request context needed. Used by both the `Uri` class and the standalone `route()` function.
28
+ *
29
+ * @param route - The registered route to build a URL for
30
+ * @param name - Route name (used in error messages)
31
+ * @param params - Path params, domain params, and extra query params
32
+ * @returns Relative URL string (or absolute with domain prefix if route has a domain pattern)
33
+ *
34
+ * @throws RouterError if a required path or domain param is missing
35
+ */
36
+ function buildRouteUrl(route, name, params, localeConfig) {
37
+ const allParams = { ...params };
38
+ const consumedKeys = /* @__PURE__ */ new Set();
39
+ let url = route.path;
40
+ if (allParams.locale && route.localePaths?.length) {
41
+ url = applyLocalePrefix(url, allParams.locale, localeConfig);
42
+ consumedKeys.add("locale");
43
+ }
44
+ for (const paramName of route.paramNames) {
45
+ const value = allParams[paramName];
46
+ if (value === void 0) throw new RouterError(`Missing required route parameter "${paramName}" for route "${name}" (path: ${route.path})`);
47
+ url = url.replace(new RegExp(`:${paramName}(\\{[^}]*\\})?`), encodePathParam(value));
48
+ consumedKeys.add(paramName);
49
+ }
50
+ let domain;
51
+ if (route.domain) {
52
+ domain = route.domain;
53
+ for (const domainParam of route.domainParamNames) {
54
+ const value = allParams[domainParam];
55
+ if (value === void 0) throw new RouterError(`Missing required domain parameter "${domainParam}" for route "${name}" (domain: ${route.domain})`);
56
+ domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value));
57
+ consumedKeys.add(domainParam);
58
+ }
59
+ }
60
+ const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key));
61
+ if (queryEntries.length > 0) {
62
+ const queryString = queryEntries.filter(([, value]) => Boolean(value)).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
63
+ url = `${url}${queryString.length ? `?${queryString}` : ""}`;
64
+ }
65
+ if (domain) url = `https://${domain}${url}`;
66
+ return url;
67
+ }
68
+ let Uri = class Uri {
69
+ registry;
70
+ routerContext;
71
+ _defaults = {};
72
+ trailingSlash;
73
+ localeConfig;
74
+ constructor(registry, routerContext, application, localePathService) {
75
+ this.registry = registry;
76
+ this.routerContext = routerContext;
77
+ this.trailingSlash = application.config.trailingSlash ?? "ignore";
78
+ this.localeConfig = {
79
+ defaultLocale: localePathService.localePathConfig?.defaultLocale ?? null,
80
+ prefixDefaultLocale: localePathService.prefixDefaultLocale
81
+ };
82
+ }
83
+ /**
84
+ * Set default URL parameters for this request.
85
+ * Applied to all subsequent `route()` calls — explicit params override defaults.
86
+ *
87
+ * @param params - Default parameters (e.g., `{ locale: 'en' }`)
88
+ */
89
+ defaults(params) {
90
+ this._defaults = {
91
+ ...this._defaults,
92
+ ...params
93
+ };
94
+ }
95
+ /**
96
+ * Read the currently configured default URL parameters.
97
+ *
98
+ * Used by frameworks that need to share these with the client (e.g. the
99
+ * Inertia adapter ships them as a shared prop so `route()` calls in the
100
+ * browser auto-fill the same sticky params as the server).
101
+ */
102
+ getDefaults() {
103
+ return { ...this._defaults };
104
+ }
105
+ /**
106
+ * Generate a URL from a named route.
107
+ *
108
+ * Keys matching `:param` placeholders fill the path.
109
+ * Domain params (`{tenant}`) are consumed from the same object.
110
+ * Extra keys become query string parameters.
111
+ * Default params (from `defaults()`) are merged — explicit params override.
112
+ *
113
+ * @param name - Named route identifier
114
+ * @param params - Route params + domain params + extra query params
115
+ * @param options - URL generation options
116
+ * @returns Generated URL string
117
+ *
118
+ * @throws RouterError if route name not found or required params missing
119
+ */
120
+ route(name, params, options) {
121
+ const registeredRoute = this.registry.get(name);
122
+ if (!registeredRoute) throw new RouterError(`Route name "${name}" was not found in the registry`);
123
+ let url = applyTrailingSlash(buildRouteUrl(registeredRoute, name, {
124
+ ...this._defaults,
125
+ ...params
126
+ }, this.localeConfig), this.trailingSlash);
127
+ if (options?.absolute && !url.startsWith("http")) url = `${new URL(this.routerContext.c.req.url).origin}${url}`;
128
+ return url;
129
+ }
130
+ /**
131
+ * Generate a signed URL from a named route.
132
+ *
133
+ * @param name - Named route identifier
134
+ * @param params - Route params + domain params + extra query params
135
+ * @param options - Signing options (e.g., expiresIn) and URL options
136
+ * @returns Signed URL string with signature query param
137
+ *
138
+ * @throws Error if APP_SECRET environment variable is not set
139
+ */
140
+ async signedRoute(name, params, options) {
141
+ return signUrl(this.route(name, params, options), this.getAppSecret(), options);
142
+ }
143
+ /**
144
+ * Generate a temporary signed URL from a named route.
145
+ *
146
+ * @param name - Named route identifier
147
+ * @param expiresIn - Time-to-live in seconds
148
+ * @param params - Route params + domain params + extra query params
149
+ * @param options - URL generation options
150
+ * @returns Signed URL string with signature and expires query params
151
+ *
152
+ * @throws Error if APP_SECRET environment variable is not set
153
+ */
154
+ async temporarySignedRoute(name, expiresIn, params, options) {
155
+ return this.signedRoute(name, params, {
156
+ ...options,
157
+ expiresIn
158
+ });
159
+ }
160
+ /**
161
+ * Check if the current request has a valid signature.
162
+ *
163
+ * @returns true if the URL signature is valid and not expired
164
+ */
165
+ async hasValidSignature() {
166
+ const secret = this.routerContext.c.env.APP_SECRET;
167
+ if (!secret) return false;
168
+ return verifySignedUrl(this.routerContext.c.req.url, secret);
169
+ }
170
+ /**
171
+ * Get the current request URL pathname (without query string).
172
+ */
173
+ current() {
174
+ return applyTrailingSlash(new URL(this.routerContext.c.req.url).pathname, this.trailingSlash);
175
+ }
176
+ /**
177
+ * Get the current request URL with query string (pathname + search).
178
+ */
179
+ full() {
180
+ const parsed = new URL(this.routerContext.c.req.url);
181
+ return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash);
182
+ }
183
+ /**
184
+ * Get the previous request URL from the Referer header.
185
+ *
186
+ * @param fallback - URL to return if no Referer header (default: '/')
187
+ */
188
+ previous(fallback = "/") {
189
+ return this.routerContext.c.req.header("referer") ?? fallback;
190
+ }
191
+ /**
192
+ * Get the previous request URL pathname (no query string or host) from the Referer header.
193
+ *
194
+ * @param fallback - Path to return if no Referer header (default: '/')
195
+ */
196
+ previousPath(fallback = "/") {
197
+ const referer = this.routerContext.c.req.header("referer");
198
+ if (!referer) return fallback;
199
+ try {
200
+ return new URL(referer).pathname;
201
+ } catch {
202
+ return referer;
203
+ }
204
+ }
205
+ /**
206
+ * Build a URL to a raw path (not a named route) with optional query params.
207
+ *
208
+ * @param path - URL path (e.g., '/users')
209
+ * @param queryParams - Query parameters to append
210
+ * @param options - URL generation options
211
+ */
212
+ to(path, queryParams, options) {
213
+ let url = applyTrailingSlash(path, this.trailingSlash);
214
+ if (queryParams) {
215
+ const entries = Object.entries(queryParams);
216
+ if (entries.length > 0) {
217
+ const queryString = entries.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
218
+ url = url.includes("?") ? `${url}&${queryString}` : `${url}?${queryString}`;
219
+ }
220
+ }
221
+ if (options?.absolute && !url.startsWith("http")) url = `${new URL(this.routerContext.c.req.url).origin}${url}`;
222
+ return url;
223
+ }
224
+ /**
225
+ * Build a URL with query string parameters. Merges with existing query params in path.
226
+ *
227
+ * @param path - URL path, may already contain query params
228
+ * @param queryParams - Query parameters to merge (new values override existing)
229
+ */
230
+ query(path, queryParams) {
231
+ const parsed = new URL(path, "https://placeholder.local");
232
+ for (const [key, value] of Object.entries(queryParams)) parsed.searchParams.set(key, value);
233
+ return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash);
234
+ }
235
+ getAppSecret() {
236
+ const secret = this.routerContext.c.env.APP_SECRET;
237
+ if (!secret) throw new Error("APP_SECRET environment variable is required for signed URLs");
238
+ return secret;
239
+ }
240
+ };
241
+ Uri = __decorate([
242
+ Request(ROUTER_TOKENS.Uri),
243
+ __decorateParam(0, inject(ROUTER_TOKENS.RouteRegistry)),
244
+ __decorateParam(1, inject(ROUTER_TOKENS.RouterContext)),
245
+ __decorateParam(2, inject(DI_TOKENS.Application)),
246
+ __decorateParam(3, inject(ROUTER_TOKENS.LocalePathService))
247
+ ], Uri);
248
+ //#endregion
249
+ export { buildRouteUrl as n, uri_exports as r, Uri as t };
250
+
251
+ //# sourceMappingURL=uri-h7Q8Jug9.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uri-h7Q8Jug9.mjs","names":[],"sources":["../src/router/uri.ts"],"sourcesContent":["import type { Application } from '../application';\nimport { inject } from '../di';\nimport { Request } from '../di/decorators';\nimport { DI_TOKENS } from '../di/tokens';\nimport { applyLocalePrefix } from './locale-url';\nimport type { RouteName, RouteParams } from './route-map';\nimport type { RegisteredRoute, RouteRegistry } from './route-registry';\nimport type { RouterContext } from './router-context';\nimport { RouterError } from './router.error';\nimport { ROUTER_TOKENS } from './router.tokens';\nimport type { LocalePathService } from './services/locale-path.service';\nimport { signUrl, verifySignedUrl, type SignedUrlOptions } from './signed-url';\nimport { applyTrailingSlash } from './trailing-slash';\nimport type { LocaleUrlConfig, TrailingSlashMode } from './types';\n\n/**\n * Options for URL generation methods.\n */\nexport interface UriOptions {\n /** Generate absolute URL (scheme + host). Defaults to false. */\n absolute?: boolean\n}\n\n/**\n * Options for signed URL generation methods.\n */\nexport interface SignedUriOptions extends UriOptions, SignedUrlOptions { }\n\n/**\n * Encode a value for use as a path parameter.\n *\n * Splits on `/` and encodes each segment with `encodeURIComponent`, so callers\n * can pass slash-containing values for catch-all params (e.g. `:slug{.+}`) and\n * still get a usable URL — `'auth/login'` becomes `'auth/login'`, not\n * `'auth%2Flogin'`. Single segments behave exactly like `encodeURIComponent`.\n */\nfunction encodePathParam(value: string): string {\n return value.split('/').map(encodeURIComponent).join('/')\n}\n\n/**\n * Build a URL from a registered route, filling path/domain params and appending extras as query string.\n *\n * Pure function — no request context needed. Used by both the `Uri` class and the standalone `route()` function.\n *\n * @param route - The registered route to build a URL for\n * @param name - Route name (used in error messages)\n * @param params - Path params, domain params, and extra query params\n * @returns Relative URL string (or absolute with domain prefix if route has a domain pattern)\n *\n * @throws RouterError if a required path or domain param is missing\n */\nexport function buildRouteUrl(\n route: RegisteredRoute,\n name: string,\n params?: Record<string, string>,\n localeConfig?: LocaleUrlConfig,\n): string {\n const allParams = { ...params }\n const consumedKeys = new Set<string>()\n let url = route.path\n\n if (allParams.locale && route.localePaths?.length) {\n url = applyLocalePrefix(url, allParams.locale, localeConfig)\n consumedKeys.add('locale')\n }\n\n // Fill path :param placeholders (handles optional regex constraints like :locale{en|de|fr})\n for (const paramName of route.paramNames) {\n const value = allParams[paramName]\n if (value === undefined) {\n throw new RouterError(`Missing required route parameter \"${paramName}\" for route \"${name}\" (path: ${route.path})`)\n }\n url = url.replace(\n new RegExp(`:${paramName}(\\\\{[^}]*\\\\})?`),\n encodePathParam(value),\n )\n consumedKeys.add(paramName)\n }\n\n // Build domain if present\n let domain: string | undefined\n if (route.domain) {\n domain = route.domain\n for (const domainParam of route.domainParamNames) {\n const value = allParams[domainParam]\n if (value === undefined) {\n throw new RouterError(`Missing required domain parameter \"${domainParam}\" for route \"${name}\" (domain: ${route.domain})`)\n }\n domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value))\n consumedKeys.add(domainParam)\n }\n }\n\n // Remaining params (not consumed by path or domain) become query string\n const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key))\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .filter(([, value]) => Boolean(value))\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = `${url}${queryString.length ? `?${queryString}` : ''}`\n }\n\n // Prepend domain if present\n if (domain) {\n url = `https://${domain}${url}`\n }\n\n return url\n}\n\n/**\n * URL generation service for named routes, signed URLs, and request URL access.\n *\n * Registered as request-scoped in the container — has access to the current request\n * via RouterContext for features like `current()`, `full()`, and signed URLs.\n *\n * @example\n * ```typescript\n * // In a controller:\n * const uri = ctx.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n * uri.route('users.show', { id: '1' })\n * uri.current()\n * await uri.signedRoute('unsubscribe', { user: '1' }, { expiresIn: 3600 })\n *\n * // Set defaults (e.g., in middleware):\n * uri.defaults({ locale: 'en' })\n * uri.route('posts.index') // auto-fills :locale param\n * ```\n */\n@Request(ROUTER_TOKENS.Uri)\nexport class Uri {\n private _defaults: Record<string, string> = {}\n private readonly trailingSlash: TrailingSlashMode\n private readonly localeConfig: LocaleUrlConfig\n\n constructor(\n @inject(ROUTER_TOKENS.RouteRegistry) private readonly registry: RouteRegistry,\n @inject(ROUTER_TOKENS.RouterContext) private readonly routerContext: RouterContext,\n @inject(DI_TOKENS.Application) application: Application,\n @inject(ROUTER_TOKENS.LocalePathService) localePathService: LocalePathService,\n ) {\n this.trailingSlash = application.config.trailingSlash ?? 'ignore'\n this.localeConfig = {\n defaultLocale: localePathService.localePathConfig?.defaultLocale ?? null,\n prefixDefaultLocale: localePathService.prefixDefaultLocale,\n }\n }\n\n /**\n * Set default URL parameters for this request.\n * Applied to all subsequent `route()` calls — explicit params override defaults.\n *\n * @param params - Default parameters (e.g., `{ locale: 'en' }`)\n */\n defaults(params: Record<string, string>): void {\n this._defaults = { ...this._defaults, ...params }\n }\n\n /**\n * Read the currently configured default URL parameters.\n *\n * Used by frameworks that need to share these with the client (e.g. the\n * Inertia adapter ships them as a shared prop so `route()` calls in the\n * browser auto-fill the same sticky params as the server).\n */\n getDefaults(): Record<string, string> {\n return { ...this._defaults }\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are consumed from the same object.\n * Extra keys become query string parameters.\n * Default params (from `defaults()`) are merged — explicit params override.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Generated URL string\n *\n * @throws RouterError if route name not found or required params missing\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n const registeredRoute = this.registry.get(name)\n if (!registeredRoute) {\n throw new RouterError(`Route name \"${name}\" was not found in the registry`)\n }\n\n const mergedParams = { ...this._defaults, ...params } as Record<string, string>\n let url = applyTrailingSlash(buildRouteUrl(registeredRoute, name, mergedParams, this.localeConfig), this.trailingSlash)\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async signedRoute<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n const url = this.route(name, params, options)\n const secret = this.getAppSecret()\n return signUrl(url, secret, options)\n }\n\n /**\n * Generate a temporary signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param expiresIn - Time-to-live in seconds\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Signed URL string with signature and expires query params\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async temporarySignedRoute<N extends RouteName>(name: N, expiresIn: number, params?: RouteParams<N>, options?: UriOptions): Promise<string> {\n return this.signedRoute(name, params, { ...options, expiresIn })\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n const secret = (this.routerContext.c.env as unknown as Record<string, string>).APP_SECRET\n if (!secret) return false\n return verifySignedUrl(this.routerContext.c.req.url, secret)\n }\n\n /**\n * Get the current request URL pathname (without query string).\n */\n current(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return applyTrailingSlash(parsed.pathname, this.trailingSlash)\n }\n\n /**\n * Get the current request URL with query string (pathname + search).\n */\n full(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash)\n }\n\n /**\n * Get the previous request URL from the Referer header.\n *\n * @param fallback - URL to return if no Referer header (default: '/')\n */\n previous(fallback = '/'): string {\n return this.routerContext.c.req.header('referer') ?? fallback\n }\n\n /**\n * Get the previous request URL pathname (no query string or host) from the Referer header.\n *\n * @param fallback - Path to return if no Referer header (default: '/')\n */\n previousPath(fallback = '/'): string {\n const referer = this.routerContext.c.req.header('referer')\n if (!referer) return fallback\n\n try {\n const parsed = new URL(referer)\n return parsed.pathname\n } catch {\n return referer\n }\n }\n\n /**\n * Build a URL to a raw path (not a named route) with optional query params.\n *\n * @param path - URL path (e.g., '/users')\n * @param queryParams - Query parameters to append\n * @param options - URL generation options\n */\n to(path: string, queryParams?: Record<string, string>, options?: UriOptions): string {\n let url = applyTrailingSlash(path, this.trailingSlash)\n\n if (queryParams) {\n const entries = Object.entries(queryParams)\n if (entries.length > 0) {\n const queryString = entries\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`\n }\n }\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Build a URL with query string parameters. Merges with existing query params in path.\n *\n * @param path - URL path, may already contain query params\n * @param queryParams - Query parameters to merge (new values override existing)\n */\n query(path: string, queryParams: Record<string, string>): string {\n const parsed = new URL(path, 'https://placeholder.local')\n for (const [key, value] of Object.entries(queryParams)) {\n parsed.searchParams.set(key, value)\n }\n return applyTrailingSlash(`${parsed.pathname}${parsed.search}`, this.trailingSlash)\n }\n\n private getAppSecret(): string {\n const secret = this.routerContext.c.env.APP_SECRET\n if (!secret) {\n throw new Error('APP_SECRET environment variable is required for signed URLs')\n }\n return secret\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as __exportAll } from "./chunk-D1SwGrFN.mjs";
2
- import { i as dimWhite, n as cyan, r as dim, s as yellow, t as bold } from "./colors-DJaRDXoS.mjs";
1
+ import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
+ import { a as cyan, i as bold, o as dim, s as dimWhite, u as yellow } from "./command-BvmUAPPQ.mjs";
3
3
  //#region src/quarry/usage-generator.ts
4
4
  var usage_generator_exports = /* @__PURE__ */ __exportAll({
5
5
  generateListing: () => generateListing,
@@ -63,7 +63,10 @@ function generateListing(commands, signatures, options) {
63
63
  lines.push(bold(`${label}${version ? ` v${version}` : ""}`));
64
64
  lines.push("");
65
65
  lines.push(bold(yellow("Usage")));
66
- lines.push(` $ ${bin} <command> [options]`);
66
+ lines.push(` $ ${bin} [--env <name>] <command> [options]`);
67
+ lines.push("");
68
+ lines.push(bold(yellow("Global Options")));
69
+ lines.push(...formatTable([[`-e, --env ${cyan("<name>")}`, `Select a wrangler config environment (e.g. staging, production)`]]));
67
70
  lines.push("");
68
71
  if (commands.length === 0) {
69
72
  lines.push("No registered commands.");
@@ -155,4 +158,4 @@ function formatTable(rows) {
155
158
  //#endregion
156
159
  export { usage_generator_exports as n, generateUsage as t };
157
160
 
158
- //# sourceMappingURL=usage-generator-BUdlhnCK.mjs.map
161
+ //# sourceMappingURL=usage-generator-DAWYasuP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-generator-DAWYasuP.mjs","names":[],"sources":["../src/quarry/usage-generator.ts"],"sourcesContent":["import { bold, cyan, dim, dimWhite, yellow } from './colors'\nimport type { ParsedSignature } from './types'\n\n/**\n * Generate formatted help/usage text from a parsed signature.\n *\n * Pure function, edge-compatible.\n */\nexport function generateUsage(signature: ParsedSignature, description?: string): string {\n const lines: string[] = []\n\n // Usage line\n lines.push(`${bold('Usage:')} ${bold(cyan('quarry ' + buildUsageLine(signature)))}`)\n\n // Description\n if (description) {\n lines.push('')\n lines.push(description)\n }\n\n // Arguments section\n if (signature.arguments.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Arguments:')))\n const argRows = signature.arguments.map((arg) => {\n const label = arg.name\n const parts: string[] = []\n\n if (arg.description) parts.push(arg.description)\n\n if (arg.isArray) {\n parts.push('(variadic)')\n } else if (arg.required) {\n parts.push('(required)')\n } else if (arg.default !== undefined) {\n parts.push(dim(`(default: ${arg.default})`))\n } else {\n parts.push('(optional)')\n }\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(argRows))\n }\n\n // Options section\n if (signature.options.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Options:')))\n const optRows = signature.options.map((opt) => {\n const flagParts: string[] = []\n if (opt.alias) flagParts.push(`-${opt.alias},`)\n flagParts.push(`--${opt.name}`)\n\n const label = flagParts.join(' ')\n const parts: string[] = []\n\n if (opt.description) parts.push(opt.description)\n if (!opt.isFlag && !opt.description) parts.push('Accepts a value')\n if (opt.isFlag && !opt.description) parts.push('Boolean flag')\n if (opt.isArray) parts.push('(multiple)')\n if (opt.default !== undefined) parts.push(dim(`(default: ${opt.default})`))\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(optRows))\n }\n\n return lines.join('\\n')\n}\n\nexport interface ListingOptions {\n binaryName?: string\n binaryLabel?: string\n binaryVersion?: string\n}\n\n/**\n * Generate a compact command listing with visual hierarchy.\n */\nexport function generateListing(\n commands: { name: string; description?: string; aliases: string[] }[],\n signatures: Map<string, ParsedSignature>,\n options?: ListingOptions,\n): string {\n const bin = options?.binaryName ?? 'quarry'\n const label = options?.binaryLabel ?? 'Quarry CLI'\n const version = options?.binaryVersion\n\n const lines: string[] = []\n\n // Header\n lines.push(bold(`${label}${version ? ` v${version}` : ''}`))\n lines.push('')\n\n // Usage\n lines.push(bold(yellow('Usage')))\n lines.push(` $ ${bin} [--env <name>] <command> [options]`)\n lines.push('')\n\n // Global Options\n lines.push(bold(yellow('Global Options')))\n lines.push(...formatTable([\n [`-e, --env ${cyan('<name>')}`, `Select a wrangler config environment (e.g. staging, production)`],\n ]))\n lines.push('')\n\n // Commands\n if (commands.length === 0) {\n lines.push('No registered commands.')\n return lines.join('\\n')\n }\n\n lines.push(bold(yellow('Commands')))\n\n const termWidth = typeof process !== 'undefined'\n ? (process.stdout.columns as number | undefined) ?? 80\n : 80\n\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i]\n const sig = signatures.get(cmd.name)\n const sigParts: string[] = [cyan(cmd.name)]\n\n if (cmd.aliases.length > 0) {\n sigParts.push(cyan(`(alias: ${cmd.aliases.join(', ')})`))\n }\n\n if (sig) {\n const inlineParts: string[] = []\n for (const arg of sig.arguments) {\n inlineParts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of sig.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n inlineParts.push(`[${flagStr}]`)\n }\n\n if (inlineParts.length > 0) {\n sigParts.push(dim(inlineParts.join(' ')))\n }\n }\n\n const sigLine = ' ' + sigParts.join(' ')\n lines.push(...wrapLine(sigLine, termWidth, ' '))\n\n if (cmd.description) {\n lines.push(` ${dimWhite(cmd.description)}`)\n }\n\n if (i < commands.length - 1) {\n lines.push('')\n }\n }\n\n lines.push('')\n\n // Footer\n lines.push(dimWhite(`Run ${bin} help <command> for detailed information.`))\n\n return lines.join('\\n')\n}\n\n/** Format a single argument into its placeholder representation (e.g. `<name>`, `[name=default]`). */\nfunction formatArgPlaceholder(arg: ParsedSignature['arguments'][number]): string {\n if (arg.isArray) return `<${arg.name}...>`\n if (arg.required) return `<${arg.name}>`\n if (arg.default !== undefined) return `[${arg.name}=${arg.default}]`\n return `[${arg.name}]`\n}\n\n/** Build the inline usage line showing the command name with argument and option placeholders. */\nfunction buildUsageLine(signature: ParsedSignature): string {\n const parts = [signature.name]\n\n for (const arg of signature.arguments) {\n parts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of signature.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n\n if (opt.isFlag) {\n parts.push(`[${flagStr}]`)\n } else if (opt.isArray) {\n parts.push(`[${flagStr} <value...>]`)\n } else {\n parts.push(`[${flagStr} <value>]`)\n }\n }\n\n return parts.join(' ')\n}\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g\n\n/** Remove ANSI escape sequences from a string. */\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '')\n}\n\n// eslint-disable-next-line no-control-regex\nconst TOKEN_RE = /(?:\\x1b\\[[0-9;]*m)*[^\\s\\x1b]+(?:\\x1b\\[[0-9;]*m)*/g\n\n/** Wrap a single line at word boundaries, preserving ANSI codes across wrapped segments. */\nfunction wrapLine(text: string, maxWidth: number, continuationIndent: string): string[] {\n const visibleLen = stripAnsi(text).length\n if (visibleLen <= maxWidth) return [text]\n\n const tokens = text.match(TOKEN_RE) ?? [text]\n\n const lines: string[] = []\n let currentLine = ''\n let currentVisibleLen = 0\n\n for (const token of tokens) {\n const tokenVisible = stripAnsi(token).length\n const separator = currentLine === '' ? '' : ' '\n const separatorLen = separator.length\n\n if (currentLine !== '' && currentVisibleLen + separatorLen + tokenVisible > maxWidth) {\n lines.push(currentLine)\n currentLine = continuationIndent + token\n currentVisibleLen = continuationIndent.length + tokenVisible\n } else {\n currentLine += separator + token\n currentVisibleLen += separatorLen + tokenVisible\n }\n }\n\n if (currentLine !== '') {\n lines.push(currentLine)\n }\n\n return lines\n}\n\n/** Format label/description pairs into aligned two-column table rows. */\nfunction formatTable(rows: readonly (readonly [string, string])[]): string[] {\n if (rows.length === 0) return []\n\n const maxLabel = Math.max(...rows.map(([label]) => stripAnsi(label).length))\n const padding = 4\n\n return rows.map(([label, desc]) => {\n const visibleLen = stripAnsi(label).length\n const pad = ' '.repeat(maxLabel - visibleLen + padding)\n return ` ${label}${pad}${desc}`\n })\n}\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { n as __reExport, t as __exportAll } from "./chunk-BBjsoOtd.mjs";
2
+ import { n as getContainer } from "./container-storage-BmOJ4_Na.mjs";
3
+ import { t as I18N_TOKENS } from "./i18n.tokens-CZ_v8oyS.mjs";
4
+ import { a as CUID2_REGEX, i as zod_exports, n as ZodError, o as cuid2, r as z, t as OpenAPIHono } from "./zod-eKqqhZ5_.mjs";
5
+ import { t as zodErrorMap } from "./validation.context-CRvmrhq7.mjs";
6
+ //#region src/i18n/validation/with-zod-i18n.ts
7
+ /**
8
+ * Type-safe helper for creating custom Zod error messages with i18n support
9
+ *
10
+ * Usage with .refine():
11
+ * ```typescript
12
+ * const schema = z.string().refine(
13
+ * (val) => val.length > 5,
14
+ * withZodI18n('validation.minLength', { min: 5 })
15
+ * )
16
+ * ```
17
+ *
18
+ * Usage with built-in validators:
19
+ * ```typescript
20
+ * const schema = z.string().min(5, withZodI18n('validation.minLength', { min: 5 }))
21
+ * const schema = z.string().email(withZodI18n('validation.email'))
22
+ * ```
23
+ *
24
+ * @param key - Message key from shared i18n messages (type-safe via MessageKeys)
25
+ * @param params - Optional interpolation parameters for the message
26
+ * @returns Zod error configuration object with translated message
27
+ */
28
+ function withZodI18n(key, params) {
29
+ return { error: (_issue) => {
30
+ try {
31
+ return getContainer().resolve(I18N_TOKENS.I18nService).t(key, params);
32
+ } catch {
33
+ return "Invalid input";
34
+ }
35
+ } };
36
+ }
37
+ __reExport(/* @__PURE__ */ __exportAll({
38
+ CUID2_REGEX: () => CUID2_REGEX,
39
+ OpenAPIHono: () => OpenAPIHono,
40
+ ZodError: () => ZodError,
41
+ cuid2: () => cuid2,
42
+ withZodI18n: () => withZodI18n,
43
+ z: () => z,
44
+ zodErrorMap: () => zodErrorMap
45
+ }), zod_exports);
46
+ //#endregion
47
+ export { withZodI18n as t };
48
+
49
+ //# sourceMappingURL=validation-CpOjviyT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-CpOjviyT.mjs","names":[],"sources":["../src/i18n/validation/with-zod-i18n.ts","../src/i18n/validation/index.ts"],"sourcesContent":["import { type $ZodRawIssue } from 'zod/v4/core'\nimport { getContainer } from '../../di/container-storage'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport type { II18nService, MessageKeys } from '../i18n.types'\n\n/**\n * Type-safe helper for creating custom Zod error messages with i18n support\n *\n * Usage with .refine():\n * ```typescript\n * const schema = z.string().refine(\n * (val) => val.length > 5,\n * withZodI18n('validation.minLength', { min: 5 })\n * )\n * ```\n *\n * Usage with built-in validators:\n * ```typescript\n * const schema = z.string().min(5, withZodI18n('validation.minLength', { min: 5 }))\n * const schema = z.string().email(withZodI18n('validation.email'))\n * ```\n *\n * @param key - Message key from shared i18n messages (type-safe via MessageKeys)\n * @param params - Optional interpolation parameters for the message\n * @returns Zod error configuration object with translated message\n */\nexport function withZodI18n(\n key: MessageKeys,\n params?: Record<string, unknown>\n): { error: (_issue: $ZodRawIssue) => string } {\n return {\n error: (_issue: $ZodRawIssue) => {\n try {\n const container = getContainer()\n const i18n = container.resolve<II18nService>(I18N_TOKENS.I18nService)\n return i18n.t(key, params as Record<string, string | number> | undefined)\n } catch {\n return 'Invalid input'\n }\n },\n }\n}\n","export * from './zod'\nexport { withZodI18n } from './with-zod-i18n'\nexport { zodErrorMap } from './validation.context'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,YACd,KACA,QAC6C;CAC7C,OAAO,EACL,QAAQ,WAAyB;EAC/B,IAAI;GAGF,OAFkB,aACG,EAAE,QAAsB,YAAY,WAC/C,EAAE,EAAE,KAAK,MAAqD;EAC1E,QAAQ;GACN,OAAO;EACT;CACF,EACF;AACF"}
@@ -0,0 +1,117 @@
1
+ import { n as getContainer } from "./container-storage-BmOJ4_Na.mjs";
2
+ import { t as I18N_TOKENS } from "./i18n.tokens-CZ_v8oyS.mjs";
3
+ //#region src/i18n/validation/validation.error-map.ts
4
+ /**
5
+ * Type guards for narrowing Zod v4 issue types
6
+ */
7
+ function isInvalidType(issue) {
8
+ return issue.code === "invalid_type";
9
+ }
10
+ function isTooBig(issue) {
11
+ return issue.code === "too_big";
12
+ }
13
+ function isTooSmall(issue) {
14
+ return issue.code === "too_small";
15
+ }
16
+ function isInvalidFormat(issue) {
17
+ return issue.code === "invalid_format";
18
+ }
19
+ function isNotMultipleOf(issue) {
20
+ return issue.code === "not_multiple_of";
21
+ }
22
+ function isUnrecognizedKeys(issue) {
23
+ return issue.code === "unrecognized_keys";
24
+ }
25
+ function isInvalidUnion(issue) {
26
+ return issue.code === "invalid_union";
27
+ }
28
+ function isInvalidKey(issue) {
29
+ return issue.code === "invalid_key";
30
+ }
31
+ /**
32
+ * Maps Zod issue codes to zodI18n message keys
33
+ * Adapted for Zod v4's simpler issue code system
34
+ */
35
+ function getMessageKey(issue) {
36
+ if (isInvalidType(issue)) {
37
+ if (issue.input === void 0) return "zodI18n.errors.required";
38
+ return "zodI18n.errors.invalid_type";
39
+ }
40
+ if (isTooSmall(issue)) return `zodI18n.errors.too_small.${issue.origin || "string"}.${issue.exact ? "exact" : issue.inclusive ? "inclusive" : "not_inclusive"}`;
41
+ if (isTooBig(issue)) return `zodI18n.errors.too_big.${issue.origin || "string"}.${issue.exact ? "exact" : issue.inclusive ? "inclusive" : "not_inclusive"}`;
42
+ if (isInvalidFormat(issue)) return `zodI18n.errors.invalid_string.${issue.format}`;
43
+ if (isNotMultipleOf(issue)) return "zodI18n.errors.not_multiple_of";
44
+ if (isUnrecognizedKeys(issue)) return "zodI18n.errors.unrecognized_keys";
45
+ if (isInvalidUnion(issue)) return "zodI18n.errors.invalid_union";
46
+ if (isInvalidKey(issue)) return "zodI18n.errors.invalid_enum_value";
47
+ return "zodI18n.errors.custom.default";
48
+ }
49
+ /**
50
+ * Extracts interpolation parameters from Zod issue
51
+ * Uses proper type narrowing for v4
52
+ */
53
+ function getMessageParams(issue) {
54
+ const params = {};
55
+ if (isInvalidType(issue)) {
56
+ params.expected = issue.expected;
57
+ params.received = String(issue.input);
58
+ return params;
59
+ }
60
+ if (isUnrecognizedKeys(issue)) {
61
+ params.keys = issue.keys.join(", ");
62
+ return params;
63
+ }
64
+ if (isInvalidKey(issue)) return params;
65
+ if (isInvalidFormat(issue)) {
66
+ params.validation = issue.format;
67
+ if ("prefix" in issue && typeof issue.prefix === "string") params.startsWith = issue.prefix;
68
+ if ("suffix" in issue && typeof issue.suffix === "string") params.endsWith = issue.suffix;
69
+ if ("includes" in issue && typeof issue.includes === "string") params.includes = issue.includes;
70
+ if (issue.pattern) params.pattern = issue.pattern;
71
+ return params;
72
+ }
73
+ if (isTooSmall(issue)) {
74
+ params.minimum = Number(issue.minimum);
75
+ params.type = issue.origin;
76
+ if (issue.origin === "date") params.minimum = new Date(Number(issue.minimum)).toLocaleDateString();
77
+ return params;
78
+ }
79
+ if (isTooBig(issue)) {
80
+ params.maximum = Number(issue.maximum);
81
+ params.type = issue.origin;
82
+ if (issue.origin === "date") params.maximum = new Date(Number(issue.maximum)).toLocaleDateString();
83
+ return params;
84
+ }
85
+ if (isNotMultipleOf(issue)) {
86
+ params.multipleOf = issue.divisor;
87
+ return params;
88
+ }
89
+ return params;
90
+ }
91
+ /**
92
+ * Creates a Zod error map that uses i18n for translation
93
+ * Uses Zod v4 native $ZodErrorMap signature (no ctx parameter)
94
+ */
95
+ function createI18nErrorMap() {
96
+ return (issue) => {
97
+ const messageKey = getMessageKey(issue);
98
+ const messageParams = getMessageParams(issue);
99
+ try {
100
+ return { message: getContainer().resolve(I18N_TOKENS.I18nService).t(messageKey, messageParams) };
101
+ } catch {
102
+ return { message: "Invalid input" };
103
+ }
104
+ };
105
+ }
106
+ //#endregion
107
+ //#region src/i18n/validation/validation.context.ts
108
+ /**
109
+ * Zod error map that resolves I18nService from the DI container.
110
+ * Falls back to 'Invalid input' when called outside the container scope
111
+ * (e.g., config validation at startup, tests).
112
+ */
113
+ const zodErrorMap = createI18nErrorMap();
114
+ //#endregion
115
+ export { zodErrorMap as t };
116
+
117
+ //# sourceMappingURL=validation.context-CRvmrhq7.mjs.map