stratal 0.0.21 → 0.0.22

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 (246) hide show
  1. package/README.md +1 -1
  2. package/dist/{base-email.provider-CfQCA08m.mjs → base-email.provider-BWZHIjt8.mjs} +1 -1
  3. package/dist/{base-email.provider-CfQCA08m.mjs.map → base-email.provider-BWZHIjt8.mjs.map} +1 -1
  4. package/dist/bin/quarry.mjs +46 -109
  5. package/dist/bin/quarry.mjs.map +1 -1
  6. package/dist/cache/index.d.mts +6 -46
  7. package/dist/cache/index.d.mts.map +1 -1
  8. package/dist/cache/index.mjs +20 -67
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-e34gV6tz.d.mts} +8 -8
  11. package/dist/{cache.service-DsnKuNyO.d.mts.map → cache.service-e34gV6tz.d.mts.map} +1 -1
  12. package/dist/{cache.tokens-B7Rw1C9Q.mjs → cache.tokens-ovi_c52J.mjs} +1 -1
  13. package/dist/{cache.tokens-B7Rw1C9Q.mjs.map → cache.tokens-ovi_c52J.mjs.map} +1 -1
  14. package/dist/{colors-DJaRDXoS.mjs → colors-axmupKdp.mjs} +1 -1
  15. package/dist/{colors-DJaRDXoS.mjs.map → colors-axmupKdp.mjs.map} +1 -1
  16. package/dist/{command-BgSlsS4M.mjs → command-BU4ApTo5.mjs} +2 -3
  17. package/dist/command-BU4ApTo5.mjs.map +1 -0
  18. package/dist/{command-Cmmf0oHX.d.mts → command-wXfvHbBZ.d.mts} +3 -2
  19. package/dist/command-wXfvHbBZ.d.mts.map +1 -0
  20. package/dist/config/index.d.mts +24 -11
  21. package/dist/config/index.d.mts.map +1 -1
  22. package/dist/config/index.mjs +31 -57
  23. package/dist/config/index.mjs.map +1 -1
  24. package/dist/{consumer-registry-B7yUNh0q.d.mts → consumer-registry-DHQtypr1.d.mts} +1 -1
  25. package/dist/{consumer-registry-B7yUNh0q.d.mts.map → consumer-registry-DHQtypr1.d.mts.map} +1 -1
  26. package/dist/container-storage-GpNNz79X.mjs +52 -0
  27. package/dist/container-storage-GpNNz79X.mjs.map +1 -0
  28. package/dist/{controller.decorator-B9vwn0zK.mjs → controller.decorator-DIUazNU7.mjs} +8 -8
  29. package/dist/controller.decorator-DIUazNU7.mjs.map +1 -0
  30. package/dist/cron/index.d.mts +26 -5
  31. package/dist/cron/index.d.mts.map +1 -1
  32. package/dist/cron/index.mjs +1 -1
  33. package/dist/{cron-manager-DQSK8uoV.mjs → cron-manager-9bpN9bu4.mjs} +35 -15
  34. package/dist/cron-manager-9bpN9bu4.mjs.map +1 -0
  35. package/dist/{cron-manager-CmTimEjf.d.mts → cron-manager-CSTIBPcM.d.mts} +6 -13
  36. package/dist/cron-manager-CSTIBPcM.d.mts.map +1 -0
  37. package/dist/decorate-HgTKAYK8.mjs +16 -0
  38. package/dist/deep-merge-C8NgcXw4.mjs +18 -0
  39. package/dist/deep-merge-C8NgcXw4.mjs.map +1 -0
  40. package/dist/di/index.d.mts +2 -2
  41. package/dist/di/index.mjs +4 -3
  42. package/dist/di-BO1QIb5H.mjs +415 -0
  43. package/dist/di-BO1QIb5H.mjs.map +1 -0
  44. package/dist/email/index.d.mts +14 -89
  45. package/dist/email/index.d.mts.map +1 -1
  46. package/dist/email/index.mjs +25 -125
  47. package/dist/email/index.mjs.map +1 -1
  48. package/dist/en-BPP6h6y5.mjs +202 -0
  49. package/dist/en-BPP6h6y5.mjs.map +1 -0
  50. package/dist/{env-D1rcZ8_r.d.mts → env-DKSbuBi5.d.mts} +1 -1
  51. package/dist/env-DKSbuBi5.d.mts.map +1 -0
  52. package/dist/errors/index.d.mts +2 -2
  53. package/dist/errors/index.mjs +4 -2
  54. package/dist/errors-BBZTnjdq.mjs +333 -0
  55. package/dist/errors-BBZTnjdq.mjs.map +1 -0
  56. package/dist/events/index.d.mts +2 -2
  57. package/dist/events/index.d.mts.map +1 -1
  58. package/dist/events/index.mjs +1 -1
  59. package/dist/{events-CzCV8jI8.mjs → events-D1KdDaiP.mjs} +11 -11
  60. package/dist/events-D1KdDaiP.mjs.map +1 -0
  61. package/dist/exception-context-B4kM-M53.mjs +429 -0
  62. package/dist/exception-context-B4kM-M53.mjs.map +1 -0
  63. package/dist/{gateway-context-CXmXtaUP.mjs → gateway-context-CFe6a9gz.mjs} +19 -31
  64. package/dist/gateway-context-CFe6a9gz.mjs.map +1 -0
  65. package/dist/guards/index.d.mts +3 -3
  66. package/dist/guards/index.d.mts.map +1 -1
  67. package/dist/guards/index.mjs +1 -1
  68. package/dist/{guards-DU1_J9YA.mjs → guards-Ced-uNIF.mjs} +6 -5
  69. package/dist/guards-Ced-uNIF.mjs.map +1 -0
  70. package/dist/{http-method.decorator-BrgHMdLQ.mjs → http-method.decorator-CdjKFJZZ.mjs} +7 -6
  71. package/dist/http-method.decorator-CdjKFJZZ.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-BlXrtAlV.mjs +219 -0
  84. package/dist/i18n.module-BlXrtAlV.mjs.map +1 -0
  85. package/dist/i18n.tokens-hwRpmjRq.mjs +19 -0
  86. package/dist/i18n.tokens-hwRpmjRq.mjs.map +1 -0
  87. package/dist/{index-7-hU3GTV.d.mts → index-B4UBK-2T.d.mts} +1 -1
  88. package/dist/{index-7-hU3GTV.d.mts.map → index-B4UBK-2T.d.mts.map} +1 -1
  89. package/dist/index-BtlE9RuO.d.mts +124 -0
  90. package/dist/index-BtlE9RuO.d.mts.map +1 -0
  91. package/dist/{index-DUzWs0z7.d.mts → index-CW1YHSft.d.mts} +71 -167
  92. package/dist/index-CW1YHSft.d.mts.map +1 -0
  93. package/dist/{index-ByOyTmqf.d.mts → index-DEncMcC6.d.mts} +554 -2237
  94. package/dist/index-DEncMcC6.d.mts.map +1 -0
  95. package/dist/index-Dj5IMwtr.d.mts +44 -0
  96. package/dist/index-Dj5IMwtr.d.mts.map +1 -0
  97. package/dist/{index-C1KvMncZ.d.mts → index-KMgSCSM7.d.mts} +3 -108
  98. package/dist/index-KMgSCSM7.d.mts.map +1 -0
  99. package/dist/index.d.mts +5 -43
  100. package/dist/index.mjs +1 -1
  101. package/dist/{is-command-C6a7WTPw.mjs → is-command-CX5rAfZW.mjs} +2 -2
  102. package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CX5rAfZW.mjs.map} +1 -1
  103. package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-CYCtELlm.mjs} +1 -1
  104. package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-CYCtELlm.mjs.map} +1 -1
  105. package/dist/logger/index.d.mts +2 -2
  106. package/dist/logger/index.mjs +170 -2
  107. package/dist/logger/index.mjs.map +1 -0
  108. package/dist/macroable/index.d.mts +1 -1
  109. package/dist/macroable/index.mjs +1 -1
  110. package/dist/{macroable-BmufBshB.mjs → macroable-DzlfzT50.mjs} +1 -1
  111. package/dist/{macroable-BmufBshB.mjs.map → macroable-DzlfzT50.mjs.map} +1 -1
  112. package/dist/metadata-BVkc4aUu.mjs +39 -0
  113. package/dist/metadata-BVkc4aUu.mjs.map +1 -0
  114. package/dist/module/index.d.mts +6 -24
  115. package/dist/module/index.d.mts.map +1 -1
  116. package/dist/module/index.mjs +2 -2
  117. package/dist/module-xYoHba6B.mjs +422 -0
  118. package/dist/module-xYoHba6B.mjs.map +1 -0
  119. package/dist/openapi/index.d.mts +3 -3
  120. package/dist/openapi/index.d.mts.map +1 -1
  121. package/dist/openapi/index.mjs +1 -2
  122. package/dist/openapi-C6lm0RmV.mjs +483 -0
  123. package/dist/openapi-C6lm0RmV.mjs.map +1 -0
  124. package/dist/{openapi.service-Bt9bCIrd.d.mts → openapi.service-CrLlsXAd.d.mts} +3 -3
  125. package/dist/openapi.service-CrLlsXAd.d.mts.map +1 -0
  126. package/dist/quarry/index.d.mts +5 -163
  127. package/dist/quarry/index.d.mts.map +1 -1
  128. package/dist/quarry/index.mjs +5 -5
  129. package/dist/quarry/runner.d.mts +184 -0
  130. package/dist/quarry/runner.d.mts.map +1 -0
  131. package/dist/quarry/runner.mjs +775 -0
  132. package/dist/quarry/runner.mjs.map +1 -0
  133. package/dist/quarry-registry-D4hIGScf.d.mts +69 -0
  134. package/dist/quarry-registry-D4hIGScf.d.mts.map +1 -0
  135. package/dist/quarry-registry-DkraZNwn.mjs +311 -0
  136. package/dist/quarry-registry-DkraZNwn.mjs.map +1 -0
  137. package/dist/queue/index.d.mts +3 -3
  138. package/dist/queue/index.mjs +26 -28
  139. package/dist/queue/index.mjs.map +1 -1
  140. package/dist/{queue.module-BhCjZp6H.mjs → queue.module-DeWJ0tQM.mjs} +59 -113
  141. package/dist/queue.module-DeWJ0tQM.mjs.map +1 -0
  142. package/dist/{r2-storage.provider-DuonKeYm.mjs → r2-storage.provider-Hfm6LdZQ.mjs} +5 -5
  143. package/dist/r2-storage.provider-Hfm6LdZQ.mjs.map +1 -0
  144. package/dist/{rate-limit.decorator-6qzNcSOt.mjs → rate-limit.decorator-D69zdZbp.mjs} +6 -11
  145. package/dist/rate-limit.decorator-D69zdZbp.mjs.map +1 -0
  146. package/dist/rate-limiter/index.d.mts +11 -50
  147. package/dist/rate-limiter/index.d.mts.map +1 -1
  148. package/dist/rate-limiter/index.mjs +16 -30
  149. package/dist/rate-limiter/index.mjs.map +1 -1
  150. package/dist/{resend.provider-DB4IlFjG.mjs → resend.provider-Ur6tU7fK.mjs} +7 -7
  151. package/dist/resend.provider-Ur6tU7fK.mjs.map +1 -0
  152. package/dist/router/index.d.mts +2 -2
  153. package/dist/router/index.mjs +8 -7
  154. package/dist/{i18n.module-CzXLW9Hy.mjs → router-Cy6DjkvP.mjs} +171 -851
  155. package/dist/router-Cy6DjkvP.mjs.map +1 -0
  156. package/dist/seeder/index.d.mts +6 -11
  157. package/dist/seeder/index.d.mts.map +1 -1
  158. package/dist/seeder/index.mjs +3 -3
  159. package/dist/{seeder-zoEfEw9i.mjs → seeder-BADTig4n.mjs} +14 -22
  160. package/dist/seeder-BADTig4n.mjs.map +1 -0
  161. package/dist/{signed-url-BQPbv2In.mjs → signed-url-BqUqt5dF.mjs} +1 -1
  162. package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-BqUqt5dF.mjs.map} +1 -1
  163. package/dist/{smtp.provider-B6D7zuWX.mjs → smtp.provider-C129sNBT.mjs} +6 -6
  164. package/dist/smtp.provider-C129sNBT.mjs.map +1 -0
  165. package/dist/storage/index.d.mts +15 -39
  166. package/dist/storage/index.d.mts.map +1 -1
  167. package/dist/storage/index.mjs +3 -3
  168. package/dist/storage/providers/index.d.mts +2 -2
  169. package/dist/storage/providers/index.mjs +1 -1
  170. package/dist/{storage-D8CBP72Z.mjs → storage-BA3ppVYM.mjs} +65 -59
  171. package/dist/storage-BA3ppVYM.mjs.map +1 -0
  172. package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-DQMtT42e.d.mts} +2 -3
  173. package/dist/storage-provider.interface-DQMtT42e.d.mts.map +1 -0
  174. package/dist/storage.error-C6FY037a.mjs +8 -0
  175. package/dist/storage.error-C6FY037a.mjs.map +1 -0
  176. package/dist/{stratal-CNwpbSZl.mjs → stratal-Bdq4IdB3.mjs} +31 -185
  177. package/dist/stratal-Bdq4IdB3.mjs.map +1 -0
  178. package/dist/stratal-BsKmvP6J.d.mts +43 -0
  179. package/dist/stratal-BsKmvP6J.d.mts.map +1 -0
  180. package/dist/{types-cySNS_lp.d.mts → types-BaeHi67f.d.mts} +1 -1
  181. package/dist/types-BaeHi67f.d.mts.map +1 -0
  182. package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DTqaUMR9.mjs} +6 -3
  183. package/dist/usage-generator-DTqaUMR9.mjs.map +1 -0
  184. package/dist/validation-DUzcjb8Q.mjs +49 -0
  185. package/dist/validation-DUzcjb8Q.mjs.map +1 -0
  186. package/dist/validation.context-XTysWJ3b.mjs +117 -0
  187. package/dist/validation.context-XTysWJ3b.mjs.map +1 -0
  188. package/dist/websocket/index.d.mts +7 -14
  189. package/dist/websocket/index.d.mts.map +1 -1
  190. package/dist/websocket/index.mjs +2 -2
  191. package/dist/workers/index.d.mts +2 -2
  192. package/dist/workers/index.mjs +3 -2
  193. package/dist/workers/index.mjs.map +1 -1
  194. package/dist/{index-Bnpfq6uk.d.mts → zod-DvWTfRpI.d.mts} +58 -133
  195. package/dist/zod-DvWTfRpI.d.mts.map +1 -0
  196. package/dist/zod-hMa3rSHV.mjs +72 -0
  197. package/dist/zod-hMa3rSHV.mjs.map +1 -0
  198. package/package.json +10 -10
  199. package/dist/command-BgSlsS4M.mjs.map +0 -1
  200. package/dist/command-Cmmf0oHX.d.mts.map +0 -1
  201. package/dist/controller.decorator-B9vwn0zK.mjs.map +0 -1
  202. package/dist/cron-manager-CmTimEjf.d.mts.map +0 -1
  203. package/dist/cron-manager-DQSK8uoV.mjs.map +0 -1
  204. package/dist/en-DSH_bhh6.mjs +0 -308
  205. package/dist/en-DSH_bhh6.mjs.map +0 -1
  206. package/dist/env-D1rcZ8_r.d.mts.map +0 -1
  207. package/dist/errors-COW9-Mar.mjs +0 -1739
  208. package/dist/errors-COW9-Mar.mjs.map +0 -1
  209. package/dist/errors-ORxu1-Bb.mjs +0 -74
  210. package/dist/errors-ORxu1-Bb.mjs.map +0 -1
  211. package/dist/events-CzCV8jI8.mjs.map +0 -1
  212. package/dist/gateway-context-CXmXtaUP.mjs.map +0 -1
  213. package/dist/guards-DU1_J9YA.mjs.map +0 -1
  214. package/dist/http-method.decorator-BrgHMdLQ.mjs.map +0 -1
  215. package/dist/i18n.module-CzXLW9Hy.mjs.map +0 -1
  216. package/dist/index-Bnpfq6uk.d.mts.map +0 -1
  217. package/dist/index-ByOyTmqf.d.mts.map +0 -1
  218. package/dist/index-C1KvMncZ.d.mts.map +0 -1
  219. package/dist/index-DBd_2wv8.d.mts +0 -263
  220. package/dist/index-DBd_2wv8.d.mts.map +0 -1
  221. package/dist/index-DUzWs0z7.d.mts.map +0 -1
  222. package/dist/index.d.mts.map +0 -1
  223. package/dist/logger-DlV7NtvD.mjs +0 -440
  224. package/dist/logger-DlV7NtvD.mjs.map +0 -1
  225. package/dist/module-BzLg57FK.mjs +0 -866
  226. package/dist/module-BzLg57FK.mjs.map +0 -1
  227. package/dist/openapi-tools.service-Zs-Ewv7F.mjs +0 -200
  228. package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
  229. package/dist/openapi.service-Bt9bCIrd.d.mts.map +0 -1
  230. package/dist/quarry-registry-BwY2hOxm.mjs +0 -699
  231. package/dist/quarry-registry-BwY2hOxm.mjs.map +0 -1
  232. package/dist/queue.module-BhCjZp6H.mjs.map +0 -1
  233. package/dist/r2-storage.provider-DuonKeYm.mjs.map +0 -1
  234. package/dist/rate-limit.decorator-6qzNcSOt.mjs.map +0 -1
  235. package/dist/resend.provider-DB4IlFjG.mjs.map +0 -1
  236. package/dist/seeder-zoEfEw9i.mjs.map +0 -1
  237. package/dist/setup-CefZKV_e.mjs +0 -37
  238. package/dist/setup-CefZKV_e.mjs.map +0 -1
  239. package/dist/smtp.provider-B6D7zuWX.mjs.map +0 -1
  240. package/dist/storage-D8CBP72Z.mjs.map +0 -1
  241. package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
  242. package/dist/stratal-CNwpbSZl.mjs.map +0 -1
  243. package/dist/types-cySNS_lp.d.mts.map +0 -1
  244. package/dist/usage-generator-BUdlhnCK.mjs.map +0 -1
  245. package/dist/validation-DtJwAv7O.mjs +0 -248
  246. package/dist/validation-DtJwAv7O.mjs.map +0 -1
@@ -1,1739 +0,0 @@
1
- import { a as __decorate, d as CONTAINER_TOKEN, f as DI_TOKENS, o as __decorateParam, p as Transient, s as __decorateMetadata, u as LOGGER_TOKENS } from "./logger-DlV7NtvD.mjs";
2
- import { t as Macroable } from "./macroable-BmufBshB.mjs";
3
- import { Lifecycle, container as container$1, delay, inject, inject as inject$1, injectable as injectable$1, instancePerContainerCachingFactory as instancePerContainerCachingFactory$1, predicateAwareClassFactory, singleton } from "tsyringe";
4
- import { AsyncLocalStorage } from "node:async_hooks";
5
- import { stream, streamSSE, streamText } from "hono/streaming";
6
- //#region src/errors/application-error.ts
7
- /**
8
- * ApplicationError
9
- *
10
- * Abstract base class for all application errors.
11
- *
12
- * @deprecated Use {@link HttpException} for new error classes. `HttpException` provides
13
- * a simpler constructor that takes `(httpStatus, message?)` and derives the error code
14
- * automatically. Existing subclasses will continue to work but should be migrated over time.
15
- *
16
- * Features:
17
- * - Type-safe error codes from ERROR_CODES registry
18
- * - Type-safe message keys from i18n module
19
- * - Localized message keys (translated by ExceptionHandler)
20
- * - Structured metadata for logging and interpolation
21
- * - Proper Error prototype chain
22
- * - Automatic timestamp generation
23
- * - Serialization for RPC transmission
24
- * - Optional self-reporting via `report()` method
25
- * - Optional self-rendering via `render()` method
26
- *
27
- * Message Localization:
28
- * - Each error class passes an i18n key (e.g., 'errors.userNotFound') to super()
29
- * - `Error.message` contains the i18n key for useful stack traces and fallback display
30
- * - Metadata provides interpolation parameters (e.g., { userId: '123' })
31
- * - ExceptionHandler translates the message key using I18nService before sending response
32
- * - This ensures errors are localized based on the user's locale
33
- */
34
- var ApplicationError = class ApplicationError extends Error {
35
- /**
36
- * Controls whether stack traces are captured.
37
- * Set to false in production to skip the expensive Error.captureStackTrace() call,
38
- * since stack traces are stripped from responses in production anyway.
39
- */
40
- static captureStackTraces = true;
41
- /**
42
- * Type-safe error code from ERROR_CODES registry
43
- * See error-codes.ts for the complete registry
44
- */
45
- code;
46
- /**
47
- * ISO timestamp when the error was created
48
- */
49
- timestamp;
50
- /**
51
- * Additional structured data about the error
52
- * Used for:
53
- * 1. Logging and debugging
54
- * 2. Message interpolation (e.g., { userId: '123', email: 'user@example.com' })
55
- */
56
- metadata;
57
- /**
58
- * @param i18nKey - Type-safe i18n message key (e.g., 'errors.userNotFound')
59
- * @param code - Type-safe error code from ERROR_CODES registry
60
- * @param metadata - Optional data for logging and interpolation
61
- */
62
- constructor(i18nKey, code, metadata) {
63
- super(i18nKey);
64
- Object.setPrototypeOf(this, new.target.prototype);
65
- this.name = this.constructor.name;
66
- this.code = code;
67
- this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
68
- this.metadata = metadata;
69
- if (ApplicationError.captureStackTraces && Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
70
- }
71
- /**
72
- * Filter metadata to include only user-facing properties
73
- *
74
- * User-facing properties (validation/constraint errors):
75
- * - issues: Validation errors from SchemaValidationError
76
- * - fields: Constraint violation fields
77
- * - field: Single field constraint/foreign key
78
- *
79
- * Internal properties (excluded from response):
80
- * - path, method: Route debugging
81
- * - controllerName, reason: Controller errors
82
- * - details, etc.: Internal debugging info
83
- *
84
- * @param metadata - Raw metadata object
85
- * @returns Filtered metadata with only whitelisted properties
86
- */
87
- static filterMetadata(metadata) {
88
- if (!metadata) return void 0;
89
- const whitelist = [
90
- "issues",
91
- "fields",
92
- "field"
93
- ];
94
- const filtered = {};
95
- let hasUserFacingData = false;
96
- for (const key of whitelist) if (key in metadata && metadata[key] !== void 0) {
97
- filtered[key] = metadata[key];
98
- hasUserFacingData = true;
99
- }
100
- return hasUserFacingData ? filtered : void 0;
101
- }
102
- /**
103
- * Serialize error to ErrorResponse format for RPC transmission
104
- *
105
- * @param env - Environment (development | production)
106
- * @param translatedMessage - Optional translated message (from ExceptionHandler)
107
- * @returns ErrorResponse object suitable for JSON serialization
108
- */
109
- toErrorResponse(env, translatedMessage) {
110
- const message = translatedMessage ?? this.message;
111
- return {
112
- code: this.code,
113
- message,
114
- timestamp: this.timestamp,
115
- metadata: ApplicationError.filterMetadata(this.metadata),
116
- stack: env === "development" ? this.stack?.replace(this.message, message) : void 0
117
- };
118
- }
119
- /**
120
- * JSON serialization (used by JSON.stringify)
121
- * Defaults to development mode for backward compatibility
122
- * Note: This will use the untranslated message key - use ExceptionHandler for proper localization
123
- */
124
- toJSON() {
125
- return this.toErrorResponse("development");
126
- }
127
- };
128
- //#endregion
129
- //#region src/router/router.tokens.ts
130
- /**
131
- * Dependency injection tokens for the router system
132
- */
133
- const ROUTER_TOKENS = {
134
- /**
135
- * Token for RouterContext (request-scoped)
136
- * Contains Hono context wrapper with helper methods
137
- */
138
- RouterContext: Symbol.for("stratal:router:context"),
139
- /**
140
- * Token for RouteRegistry (singleton)
141
- * Central registry of all application routes — source of truth for route:list, route:types, URL generation
142
- */
143
- RouteRegistry: Symbol.for("stratal:router:route-registry"),
144
- /**
145
- * Token for VersioningService (singleton)
146
- * Resolves version prefixes for route paths
147
- */
148
- VersioningService: Symbol.for("stratal:router:versioning-service"),
149
- /**
150
- * Token for LocalePathService (singleton)
151
- * Resolves locale path variants and computes LocalePathConfig
152
- */
153
- LocalePathService: Symbol.for("stratal:router:locale-path-service"),
154
- /**
155
- * Token for RouterResolver (singleton, may be null)
156
- * Internal resolver that computes effective Router config per controller
157
- */
158
- RouterResolver: Symbol.for("stratal:router:router-resolver"),
159
- /**
160
- * Token for HonoApp (singleton)
161
- * The Hono application instance with Stratal-specific setup
162
- */
163
- HonoApp: Symbol.for("stratal:router:hono-app"),
164
- /**
165
- * Token for Uri (request-scoped)
166
- * URL generation service — route URLs, signed URLs, current/previous URL access
167
- */
168
- Uri: Symbol.for("stratal:router:uri")
169
- };
170
- //#endregion
171
- //#region src/di/errors/conditional-binding-fallback.error.ts
172
- /**
173
- * ConditionalBindingFallbackError
174
- *
175
- * Thrown when a conditional binding predicate returns false but no fallback
176
- * implementation was provided and no existing registration exists for the token.
177
- *
178
- * This typically indicates a misconfiguration in the DI setup where:
179
- * - A `when().use().give()` chain was used without `otherwise()`
180
- * - AND the token wasn't previously registered
181
- * - AND the predicate evaluated to false at resolution time
182
- */
183
- var ConditionalBindingFallbackError = class extends ApplicationError {
184
- constructor(token) {
185
- super("errors.conditionalBindingFallback", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { token });
186
- }
187
- };
188
- //#endregion
189
- //#region src/di/errors/request-scope-operation-not-allowed.error.ts
190
- /**
191
- * RequestScopeOperationNotAllowedError
192
- *
193
- * Thrown when attempting to call a method that is not allowed on the current container scope.
194
- * - `createRequestScope()` and `runInRequestScope()` can only be called on global containers
195
- */
196
- var RequestScopeOperationNotAllowedError = class extends ApplicationError {
197
- constructor(methodName) {
198
- super("errors.requestScopeOperationNotAllowed", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { methodName });
199
- }
200
- };
201
- //#endregion
202
- //#region src/di/conditional-binding-builder.ts
203
- /**
204
- * Implementation of ConditionalBindingBuilder
205
- *
206
- * @internal
207
- */
208
- var ConditionalBindingBuilderImpl = class {
209
- tsyringeContainer;
210
- predicateContainer;
211
- predicate;
212
- options;
213
- constructor(tsyringeContainer, predicateContainer, predicate, options) {
214
- this.tsyringeContainer = tsyringeContainer;
215
- this.predicateContainer = predicateContainer;
216
- this.predicate = predicate;
217
- this.options = options;
218
- }
219
- use(token) {
220
- return new ConditionalBindingUseImpl(this.tsyringeContainer, this.predicateContainer, this.predicate, this.options, token);
221
- }
222
- };
223
- /**
224
- * Implementation of ConditionalBindingUse
225
- *
226
- * @internal
227
- */
228
- var ConditionalBindingUseImpl = class {
229
- tsyringeContainer;
230
- predicateContainer;
231
- predicate;
232
- options;
233
- token;
234
- constructor(tsyringeContainer, predicateContainer, predicate, options, token) {
235
- this.tsyringeContainer = tsyringeContainer;
236
- this.predicateContainer = predicateContainer;
237
- this.predicate = predicate;
238
- this.options = options;
239
- this.token = token;
240
- }
241
- give(trueImplementation) {
242
- const falseImplementation = this.getFallbackImplementation();
243
- this.registerWithPredicate(trueImplementation, falseImplementation);
244
- return { otherwise: (implementation) => {
245
- this.registerWithPredicate(trueImplementation, implementation);
246
- } };
247
- }
248
- /**
249
- * Get fallback implementation: existing registration or throw-on-resolve class
250
- */
251
- getFallbackImplementation() {
252
- if (this.tsyringeContainer.isRegistered(this.token)) {
253
- const existingInstance = this.tsyringeContainer.resolve(this.token);
254
- return class ExistingInstanceWrapper {
255
- static instance = existingInstance;
256
- constructor() {
257
- return ExistingInstanceWrapper.instance;
258
- }
259
- };
260
- }
261
- const tokenStr = typeof this.token === "symbol" ? this.token.description ?? "unknown" : typeof this.token === "function" ? this.token.name : String(this.token);
262
- return class NoFallbackError {
263
- constructor() {
264
- throw new ConditionalBindingFallbackError(tokenStr);
265
- }
266
- };
267
- }
268
- registerWithPredicate(trueImplementation, falseImplementation) {
269
- const { predicate, predicateContainer, options } = this;
270
- this.tsyringeContainer.register(this.token, { useFactory: predicateAwareClassFactory(() => predicate(predicateContainer), trueImplementation, falseImplementation, options.cache ?? false) });
271
- }
272
- };
273
- //#endregion
274
- //#region src/di/container.ts
275
- /**
276
- * Unified Container for DI management
277
- *
278
- * Manages the two-tier container hierarchy:
279
- * - Global scope: Singletons, base instances of request-scoped services
280
- * - Request scope: Context-enriched instances per HTTP request
281
- *
282
- * @example Basic registration
283
- * ```typescript
284
- * import { container as tsyringeRootContainer } from 'tsyringe'
285
- *
286
- * const container = new Container({
287
- * container: tsyringeRootContainer.createChildContainer()
288
- * })
289
- *
290
- * container.register(I18nService)
291
- * container.register(MY_TOKEN, MyService)
292
- * container.registerSingleton(ConfigService)
293
- * container.registerValue(MY_TOKEN, myInstance)
294
- * ```
295
- *
296
- * @example Request scope (automatic lifecycle)
297
- * ```typescript
298
- * await container.runInRequestScope(routerContext, async (requestContainer) => {
299
- * const i18n = requestContainer.resolve(I18N_TOKEN)
300
- * })
301
- * ```
302
- */
303
- var Container = class Container {
304
- container;
305
- isRequestScoped;
306
- constructor(options) {
307
- this.isRequestScoped = options.isRequestScoped ?? false;
308
- this.container = options.container;
309
- if (!this.isRequestScoped) this.container.register(CONTAINER_TOKEN, { useValue: this });
310
- }
311
- register(tokenOrClass, serviceClassOrScope, scope) {
312
- let token;
313
- let serviceClass;
314
- let lifecycle;
315
- if (typeof serviceClassOrScope === "function") {
316
- token = tokenOrClass;
317
- serviceClass = serviceClassOrScope;
318
- lifecycle = scope;
319
- } else {
320
- token = tokenOrClass;
321
- serviceClass = tokenOrClass;
322
- lifecycle = serviceClassOrScope;
323
- }
324
- if (lifecycle !== void 0) this.container.register(token, { useClass: serviceClass }, { lifecycle });
325
- else this.container.register(token, { useClass: serviceClass });
326
- }
327
- registerSingleton(tokenOrClass, serviceClass) {
328
- if (serviceClass !== void 0) this.container.registerSingleton(tokenOrClass, serviceClass);
329
- else {
330
- const targetClass = tokenOrClass;
331
- this.container.registerSingleton(targetClass, targetClass);
332
- }
333
- }
334
- /**
335
- * Register a value (instance) directly
336
- */
337
- registerValue(token, value) {
338
- this.container.register(token, { useValue: value });
339
- }
340
- /**
341
- * Register with factory function
342
- */
343
- registerFactory(token, factory) {
344
- this.container.register(token, { useFactory: () => factory(this) });
345
- }
346
- /**
347
- * Register an alias to an existing token
348
- */
349
- registerExisting(alias, target) {
350
- this.container.register(alias, { useToken: target });
351
- }
352
- /**
353
- * Resolve a service from the container
354
- */
355
- resolve(token) {
356
- return this.container.resolve(token);
357
- }
358
- /**
359
- * Check if a token is registered
360
- */
361
- isRegistered(token) {
362
- return this.container.isRegistered(token);
363
- }
364
- /**
365
- * Start a conditional binding with predicate evaluation
366
- */
367
- when(predicate, options = {}) {
368
- return new ConditionalBindingBuilderImpl(this.container, this, predicate, options);
369
- }
370
- /**
371
- * Replace a service registration with a decorated version
372
- */
373
- extend(token, decorator) {
374
- const decoratedInstance = decorator(this.container.resolve(token), this);
375
- this.container.register(token, { useValue: decoratedInstance });
376
- }
377
- /**
378
- * Run callback within request scope
379
- *
380
- * Creates a child container with fresh instances for services registered with `scope: Scope.Request`.
381
- * Callback receives the request-scoped container as argument.
382
- *
383
- * Can only be called on global container (not request-scoped).
384
- */
385
- async runInRequestScope(routerContext, callback) {
386
- if (this.isRequestScoped) throw new RequestScopeOperationNotAllowedError("runInRequestScope");
387
- const requestContainer = this.createRequestScope(routerContext);
388
- try {
389
- return await callback(requestContainer);
390
- } finally {
391
- await requestContainer.dispose();
392
- }
393
- }
394
- /**
395
- * Create request scope container
396
- *
397
- * Can only be called on global container (not request-scoped).
398
- */
399
- createRequestScope(routerContext) {
400
- if (this.isRequestScoped) throw new RequestScopeOperationNotAllowedError("createRequestScope");
401
- const childContainer = this.container.createChildContainer();
402
- childContainer.register(ROUTER_TOKENS.RouterContext, { useValue: routerContext });
403
- return new Container({
404
- container: childContainer,
405
- isRequestScoped: true
406
- });
407
- }
408
- /**
409
- * Get underlying tsyringe container
410
- */
411
- getTsyringeContainer() {
412
- return this.container;
413
- }
414
- dispose() {
415
- return this.container.dispose();
416
- }
417
- };
418
- //#endregion
419
- //#region src/di/types.ts
420
- /**
421
- * DI Type Definitions
422
- *
423
- * Core type definitions for the dependency injection system.
424
- * Simplified after removing LazyProxy - no more type wrappers needed.
425
- */
426
- /**
427
- * Service scope for DI registration
428
- *
429
- * Maps directly to tsyringe's Lifecycle enum.
430
- * Scope is specified at registration time via provider configuration,
431
- * not at class decoration time.
432
- *
433
- * @example
434
- * ```typescript
435
- * // In module providers:
436
- * { provide: MY_TOKEN, useClass: MyService, scope: Scope.Singleton }
437
- *
438
- * // In Application.ts:
439
- * container.register(MY_TOKEN, MyService, Scope.Request)
440
- * ```
441
- */
442
- let Scope = /* @__PURE__ */ function(Scope) {
443
- /** New instance per resolution (default) */
444
- Scope[Scope["Transient"] = Lifecycle.Transient] = "Transient";
445
- /** Single instance shared globally */
446
- Scope[Scope["Singleton"] = Lifecycle.Singleton] = "Singleton";
447
- /** New instance per child container (per request) */
448
- Scope[Scope["Request"] = Lifecycle.ContainerScoped] = "Request";
449
- return Scope;
450
- }({});
451
- //#endregion
452
- //#region src/errors/error-codes.ts
453
- /**
454
- * Centralized Error Code Registry
455
- *
456
- * Error codes are organized by category with specific ranges:
457
- * - 1000-1999: Validation errors
458
- * - 2000-2999: Database errors (generic)
459
- * - 3000-3999: Authentication & Authorization
460
- * - 4000-4999: Resource errors
461
- * - 5000-5999: Domain-specific business logic (per module)
462
- * - 9000-9999: System/Internal errors
463
- * - 9000-9099: Router errors
464
- * - 9100-9199: Configuration errors
465
- * - 9200-9299: Infrastructure errors
466
- * - 9300-9399: I18n errors
467
- */
468
- const ERROR_CODES = {
469
- /**
470
- * Database Errors (2000-2999)
471
- * Generic database errors thrown by Prisma client extensions
472
- */
473
- DATABASE: {
474
- /** Generic database error */
475
- GENERIC: 2e3,
476
- /** Record not found in database */
477
- RECORD_NOT_FOUND: 2001,
478
- /** Unique constraint violation */
479
- UNIQUE_CONSTRAINT: 2002,
480
- /** Foreign key constraint violation */
481
- FOREIGN_KEY_CONSTRAINT: 2003,
482
- /** Database connection failed */
483
- CONNECTION_FAILED: 2004,
484
- /** Database timeout */
485
- TIMEOUT: 2005,
486
- /** Null constraint violation */
487
- NULL_CONSTRAINT: 2006,
488
- /** Too many database connections */
489
- TOO_MANY_CONNECTIONS: 2007,
490
- /** Transaction conflict or deadlock */
491
- TRANSACTION_CONFLICT: 2008
492
- },
493
- /**
494
- * Authentication Errors (3000-3099)
495
- * Authentication-related failures
496
- */
497
- AUTH: {
498
- /** Invalid credentials provided */
499
- INVALID_CREDENTIALS: 3e3,
500
- /** Session expired or invalid */
501
- SESSION_EXPIRED: 3001,
502
- /** Account locked or disabled */
503
- ACCOUNT_LOCKED: 3002,
504
- /** Invalid or expired token */
505
- INVALID_TOKEN: 3003,
506
- /** Context not initialized */
507
- CONTEXT_NOT_INITIALIZED: 3004,
508
- /** User not authenticated */
509
- USER_NOT_AUTHENTICATED: 3005,
510
- /** Email verification required before login */
511
- EMAIL_NOT_VERIFIED: 3007,
512
- /** Password doesn't meet minimum length */
513
- PASSWORD_TOO_SHORT: 3008,
514
- /** Password exceeds maximum length */
515
- PASSWORD_TOO_LONG: 3009,
516
- /** Account with email already exists */
517
- ACCOUNT_ALREADY_EXISTS: 3010,
518
- /** User creation failed */
519
- FAILED_TO_CREATE_USER: 3011,
520
- /** Session creation failed */
521
- FAILED_TO_CREATE_SESSION: 3012,
522
- /** User update failed */
523
- FAILED_TO_UPDATE_USER: 3013,
524
- /** Social account already linked */
525
- SOCIAL_ACCOUNT_LINKED: 3014,
526
- /** Last account cannot be unlinked */
527
- CANNOT_UNLINK_LAST_ACCOUNT: 3015,
528
- /** Organization not found */
529
- ORGANIZATION_NOT_FOUND: 3020,
530
- /** Organization member not found */
531
- MEMBER_NOT_FOUND: 3021,
532
- /** Organization invitation not found */
533
- INVITATION_NOT_FOUND: 3022,
534
- /** Invitation recipient mismatch */
535
- INVITATION_RECIPIENT_MISMATCH: 3023,
536
- /** Organization limit reached */
537
- ORGANIZATION_LIMIT_REACHED: 3024,
538
- /** Organization membership constraint violation */
539
- ORGANIZATION_MEMBERSHIP_REQUIRED: 3025
540
- },
541
- /**
542
- * Authorization Errors (3100-3199)
543
- * Permission and access control failures
544
- */
545
- AUTHZ: {
546
- /** Insufficient permissions */
547
- FORBIDDEN: 3100,
548
- /** Resource access denied */
549
- ACCESS_DENIED: 3101,
550
- /** User lacks required role */
551
- INSUFFICIENT_PERMISSIONS: 3102
552
- },
553
- /**
554
- * Resource Errors (4000-4999)
555
- * Generic resource-related errors
556
- */
557
- RESOURCE: {
558
- /** Generic resource not found */
559
- NOT_FOUND: 4e3,
560
- /** Route/endpoint not found */
561
- ROUTE_NOT_FOUND: 4004,
562
- /** Resource conflict or duplicate */
563
- CONFLICT: 4100,
564
- /** Resource already exists */
565
- ALREADY_EXISTS: 4101,
566
- /** Rate limit exceeded */
567
- TOO_MANY_REQUESTS: 4290
568
- },
569
- /**
570
- * Validation Errors (1000-1999)
571
- * Input validation failures
572
- */
573
- VALIDATION: {
574
- /** Generic validation error */
575
- GENERIC: 1e3,
576
- /** Required field missing */
577
- REQUIRED_FIELD: 1001,
578
- /** Invalid format */
579
- INVALID_FORMAT: 1002,
580
- /** Schema validation failed */
581
- SCHEMA_VALIDATION: 1003,
582
- /** Request validation failed (OpenAPI, etc.) */
583
- REQUEST_VALIDATION: 1004,
584
- /** Response validation failed (response body doesn't match declared schema) */
585
- RESPONSE_VALIDATION: 1005
586
- },
587
- /**
588
- * Router Errors (9000-9099)
589
- * Router and controller-related INTERNAL errors
590
- */
591
- ROUTER: {
592
- /** Controller registration error */
593
- CONTROLLER_REGISTRATION_ERROR: 9005,
594
- /** Controller method not found */
595
- CONTROLLER_METHOD_NOT_FOUND: 9006,
596
- /** OpenAPI route registration failed */
597
- OPENAPI_ROUTE_REGISTRATION: 9008,
598
- /** Duplicate route name in RouteRegistry */
599
- DUPLICATE_ROUTE_NAME: 9010,
600
- /** Named route not found in RouteRegistry */
601
- ROUTE_NAME_NOT_FOUND: 9011,
602
- /** Required route parameter missing during URL generation */
603
- MISSING_ROUTE_PARAM: 9012,
604
- /** router.use() called inside group() callback */
605
- USE_SCOPE_VIOLATION: 9013,
606
- /** next() called more than once in a middleware */
607
- MIDDLEWARE_NEXT_CALLED_MULTIPLE_TIMES: 9014
608
- },
609
- /**
610
- * I18n Errors (9300-9399)
611
- * Internationalization and localization errors
612
- */
613
- I18N: {
614
- /** Translation key missing from all locales */
615
- TRANSLATION_MISSING: 9300,
616
- /** Requested locale not supported */
617
- LOCALE_NOT_SUPPORTED: 9301
618
- },
619
- /**
620
- * System Errors (9000-9999)
621
- * Internal system errors and unexpected failures
622
- */
623
- SYSTEM: {
624
- /** Internal server error */
625
- INTERNAL_ERROR: 9e3,
626
- /** Generic configuration error */
627
- CONFIGURATION_ERROR: 9100,
628
- /** ConfigService not initialized */
629
- CONFIG_NOT_INITIALIZED: 9101,
630
- /** Module already registered */
631
- MODULE_ALREADY_REGISTERED: 9102,
632
- /** Circular module dependency detected */
633
- MODULE_CIRCULAR_DEPENDENCY: 9103,
634
- /** Module dependency not found */
635
- MODULE_DEPENDENCY_NOT_FOUND: 9104,
636
- /** Invalid error code range */
637
- INVALID_ERROR_CODE_RANGE: 9105,
638
- /** Invalid module provider configuration */
639
- INVALID_MODULE_PROVIDER: 9106,
640
- /** ConfigModule.forRoot() was not called */
641
- CONFIG_MODULE_NOT_INITIALIZED: 9107,
642
- /** Generic infrastructure error */
643
- INFRASTRUCTURE_ERROR: 9200,
644
- /** Execution context not initialized */
645
- EXECUTION_CONTEXT_NOT_INITIALIZED: 9201,
646
- /** Request container not initialized */
647
- REQUEST_CONTAINER_NOT_INITIALIZED: 9202,
648
- /** Queue binding not found */
649
- QUEUE_BINDING_NOT_FOUND: 9203,
650
- /** Cron job execution failed */
651
- CRON_EXECUTION_FAILED: 9204,
652
- /** Queue provider not supported */
653
- QUEUE_PROVIDER_NOT_SUPPORTED: 9205,
654
- /** body() called on WebSocket gateway context */
655
- WEBSOCKET_BODY_NOT_AVAILABLE: 9206,
656
- /** Duplicate WebSocket event decorator on a gateway */
657
- WEBSOCKET_DUPLICATE_EVENT_HANDLER: 9207,
658
- /** Seeder name collision — two seeders share the same class name */
659
- SEEDER_NAME_COLLISION: 9208,
660
- /** Seeder not registered in the SeederRegistry */
661
- SEEDER_NOT_REGISTERED: 9209,
662
- /** Application container not initialized (AsyncLocalStorage) */
663
- CONTAINER_NOT_INITIALIZED: 9210,
664
- /** Required environment variable not set */
665
- MISSING_ENVIRONMENT_VARIABLE: 9211
666
- }
667
- };
668
- //#endregion
669
- //#region src/errors/container-not-initialized.error.ts
670
- /**
671
- * Thrown when attempting to access the application container via AsyncLocalStorage
672
- * before `Application.initialize()` has been called.
673
- *
674
- * This typically means `route()` or another standalone function is being called
675
- * outside the application lifecycle.
676
- */
677
- var ContainerNotInitializedError = class extends ApplicationError {
678
- constructor() {
679
- super("errors.containerNotInitialized", ERROR_CODES.SYSTEM.CONTAINER_NOT_INITIALIZED);
680
- }
681
- };
682
- //#endregion
683
- //#region src/di/container-storage.ts
684
- /**
685
- * AsyncLocalStorage for the application container.
686
- *
687
- * Set by `Application.initialize()` — all code from that point onward
688
- * (Stratal handlers, TestingModuleBuilder, standalone functions like `route()`)
689
- * can access the container without DI or static singletons.
690
- *
691
- * Follows the same pattern as `errorMapContextStorage` in `i18n/validation/validation.context.ts`.
692
- */
693
- const containerStorage = new AsyncLocalStorage();
694
- /**
695
- * Get the application container from AsyncLocalStorage.
696
- *
697
- * @throws ContainerNotInitializedError if called outside `Application.initialize()` scope
698
- */
699
- function getContainer() {
700
- const container = containerStorage.getStore();
701
- if (!container) throw new ContainerNotInitializedError();
702
- return container;
703
- }
704
- /**
705
- * Run a function within a container context.
706
- *
707
- * @param container - The application container to store
708
- * @param fn - The function to execute with container access
709
- */
710
- function runWithContainer(container, fn) {
711
- return containerStorage.run(container, fn);
712
- }
713
- //#endregion
714
- //#region src/i18n/i18n.tokens.ts
715
- /**
716
- * I18n Module DI Tokens
717
- * Symbol-based tokens to avoid string collisions
718
- */
719
- const I18N_TOKENS = {
720
- /** MessageLoaderService - loads and caches locale messages */
721
- MessageLoader: Symbol.for("stratal:i18n:message:loader"),
722
- /** I18nService - request-scoped translation service */
723
- I18nService: Symbol.for("stratal:i18n:service"),
724
- /** I18nModuleOptions - configuration options from forRoot() */
725
- Options: Symbol.for("stratal:i18n:options"),
726
- /** MessageRegistry - singleton accumulator for registerMessages() contributions */
727
- MessageRegistry: Symbol.for("stratal:i18n:message:registry")
728
- };
729
- //#endregion
730
- //#region src/errors/http-exception.ts
731
- /**
732
- * Maps common HTTP status codes to their default error codes.
733
- * Used by {@link HttpException} to derive the error code automatically.
734
- */
735
- const HTTP_STATUS_TO_ERROR_CODE = {
736
- 400: ERROR_CODES.VALIDATION.GENERIC,
737
- 401: ERROR_CODES.AUTH.USER_NOT_AUTHENTICATED,
738
- 403: ERROR_CODES.AUTHZ.FORBIDDEN,
739
- 404: ERROR_CODES.RESOURCE.NOT_FOUND,
740
- 409: ERROR_CODES.RESOURCE.CONFLICT,
741
- 422: ERROR_CODES.VALIDATION.GENERIC,
742
- 429: ERROR_CODES.RESOURCE.TOO_MANY_REQUESTS,
743
- 500: ERROR_CODES.SYSTEM.INTERNAL_ERROR
744
- };
745
- /**
746
- * Default human-readable messages for common HTTP status codes.
747
- * Used as fallback when no message is provided to {@link HttpException}.
748
- */
749
- const HTTP_STATUS_MESSAGES = {
750
- 400: "Bad Request",
751
- 401: "Unauthorized",
752
- 403: "Forbidden",
753
- 404: "Not Found",
754
- 409: "Conflict",
755
- 422: "Unprocessable Entity",
756
- 429: "Too Many Requests",
757
- 500: "Internal Server Error"
758
- };
759
- /**
760
- * HTTP-centric exception base class.
761
- *
762
- * Unlike {@link ApplicationError} which requires `(i18nKey, code, metadata)`,
763
- * `HttpException` takes just `(httpStatus, message?)` and derives the error code
764
- * from the HTTP status automatically.
765
- *
766
- * The message can be a plain string or an i18n key — the {@link ExceptionHandler}
767
- * tries to translate it via `i18n.t()`, falling back to the raw string if the
768
- * key is not found.
769
- *
770
- * Existing {@link ApplicationError} subclasses can be migrated to this gradually.
771
- *
772
- * @example
773
- * ```typescript
774
- * // Simple usage with plain message
775
- * throw new HttpException(404, 'User not found')
776
- *
777
- * // With i18n key (auto-translated if key exists)
778
- * throw new HttpException(422, 'errors.invalidInput')
779
- *
780
- * // Default message for status code
781
- * throw new HttpException(500)
782
- *
783
- * // Subclass for domain-specific errors
784
- * class PaymentDeclinedError extends HttpException {
785
- * constructor() {
786
- * super(402, 'errors.paymentDeclined')
787
- * }
788
- * }
789
- * ```
790
- */
791
- var HttpException = class extends ApplicationError {
792
- /**
793
- * The HTTP status code for this exception.
794
- * Used by the {@link ExceptionHandler} to set the response status.
795
- */
796
- httpStatus;
797
- /**
798
- * @param httpStatus - HTTP status code (e.g., 404, 422, 500)
799
- * @param message - Optional message string or i18n key. Defaults to the
800
- * standard HTTP status message (e.g., "Not Found" for 404).
801
- */
802
- constructor(httpStatus, message) {
803
- const code = HTTP_STATUS_TO_ERROR_CODE[httpStatus] ?? ERROR_CODES.SYSTEM.INTERNAL_ERROR;
804
- const messageStr = message ?? HTTP_STATUS_MESSAGES[httpStatus] ?? "Internal Server Error";
805
- super(messageStr, code);
806
- this.httpStatus = httpStatus;
807
- }
808
- };
809
- /**
810
- * Throw an HTTP exception from anywhere in the application.
811
- *
812
- * The message can be a plain string or an i18n key — the {@link ExceptionHandler}
813
- * translates it automatically, falling back to the raw string if the key is not found.
814
- *
815
- * @param status - HTTP status code
816
- * @param message - Optional message (plain string or i18n key)
817
- * @throws {@link HttpException} — always throws, never returns
818
- *
819
- * @example
820
- * ```typescript
821
- * // With plain message
822
- * abort(404, 'User not found')
823
- *
824
- * // Default message for status
825
- * abort(403)
826
- *
827
- * // With i18n key
828
- * abort(422, 'errors.invalidInput')
829
- * ```
830
- */
831
- function abort(status, message) {
832
- throw new HttpException(status, message);
833
- }
834
- //#endregion
835
- //#region src/errors/get-http-status.ts
836
- /**
837
- * Maps error codes to HTTP status codes
838
- *
839
- * This utility is used by the frontend to set appropriate HTTP status codes
840
- * when returning errors from API routes.
841
- *
842
- * @param code - Numeric error code from ERROR_CODES registry
843
- * @returns HTTP status code (200-599)
844
- */
845
- function getHttpStatus(code) {
846
- if (code >= 1e3 && code < 2e3) return 400;
847
- if (code >= 2e3 && code < 3e3) {
848
- if (code === ERROR_CODES.DATABASE.RECORD_NOT_FOUND) return 404;
849
- if (code === ERROR_CODES.DATABASE.UNIQUE_CONSTRAINT) return 409;
850
- return 500;
851
- }
852
- if (code >= 3e3 && code < 3100) return 401;
853
- if (code >= 3100 && code < 3200) return 403;
854
- if (code >= 4e3 && code < 4100) return 404;
855
- if (code >= 4100 && code < 4200) return 409;
856
- if (code >= 4290 && code < 4300) return 429;
857
- if (code >= 5e3 && code < 6e3) {
858
- if (code === 5e3 || code === 5100 || code === 5200) return 404;
859
- return 422;
860
- }
861
- if (code >= 9e3) return 500;
862
- return 500;
863
- }
864
- /**
865
- * Resolve the HTTP status code for an ApplicationError.
866
- *
867
- * If the error is an {@link HttpException}, its `httpStatus` property takes precedence.
868
- * Otherwise, falls back to the code-range-based mapping via {@link getHttpStatus}.
869
- *
870
- * @param error - The application error to resolve the status for
871
- * @returns HTTP status code
872
- */
873
- function resolveHttpStatus(error) {
874
- if (error instanceof HttpException) return error.httpStatus;
875
- const httpStatus = error.httpStatus;
876
- if (typeof httpStatus === "number") return httpStatus;
877
- return getHttpStatus(error.code);
878
- }
879
- //#endregion
880
- //#region src/errors/internal-error.ts
881
- /**
882
- * InternalError
883
- *
884
- * Represents an unexpected internal server error.
885
- * Used to wrap unknown errors that don't fit into specific error categories.
886
- *
887
- * This error is thrown when:
888
- * - An unexpected exception occurs
889
- * - An error type is not recognized
890
- * - A system-level failure happens
891
- */
892
- var InternalError = class extends ApplicationError {
893
- constructor(metadata) {
894
- super("errors.internalError", ERROR_CODES.SYSTEM.INTERNAL_ERROR, metadata);
895
- }
896
- };
897
- //#endregion
898
- //#region src/errors/is-application-error.ts
899
- /**
900
- * Type guard to check if an error is an ApplicationError.
901
- *
902
- * Uses `instanceof` first, then falls back to a structural check
903
- * for the `code` and `timestamp` properties that all ApplicationError
904
- * instances have. This handles cross-module boundary cases where
905
- * `instanceof` fails due to duplicate class identities (e.g., Vite's
906
- * module graph in workerd).
907
- *
908
- * @param error - The error to check
909
- * @returns True if the error is an ApplicationError instance
910
- */
911
- function isApplicationError(error) {
912
- if (error instanceof ApplicationError) return true;
913
- return error instanceof Error && typeof error.code === "number" && typeof error.timestamp === "string";
914
- }
915
- //#endregion
916
- //#region src/errors/exception-handler.ts
917
- let ExceptionHandler = class ExceptionHandler {
918
- logger;
919
- env;
920
- container;
921
- executionContext;
922
- reportables = [];
923
- renderables = [];
924
- dontReportSet = /* @__PURE__ */ new Set();
925
- levelOverrides = /* @__PURE__ */ new Map();
926
- contextCallbacks = [];
927
- respondCallbacks = [];
928
- environment;
929
- constructor(logger, env, container, executionContext) {
930
- this.logger = logger;
931
- this.env = env;
932
- this.container = container;
933
- this.executionContext = executionContext;
934
- this.environment = this.env.ENVIRONMENT;
935
- }
936
- /**
937
- * Register a custom reporting callback for a specific exception type.
938
- *
939
- * The callback is invoked when an error matching `errorClass` (via `instanceof`)
940
- * is thrown. Chain `.stop()` to prevent the default logger from also reporting.
941
- *
942
- * @typeParam T - The exception type to match
943
- * @param errorClass - Constructor of the exception to match
944
- * @param callback - Reporting function receiving the typed error and context
945
- * @returns A {@link Reportable} with a `stop()` method
946
- *
947
- * @example
948
- * ```typescript
949
- * this.reportable(PaymentError, (e, ctx) => {
950
- * sentry.captureException(e)
951
- * }).stop() // skip default logging
952
- * ```
953
- */
954
- reportable(errorClass, callback) {
955
- const entry = {
956
- errorClass,
957
- callback,
958
- shouldStop: false
959
- };
960
- this.reportables.push(entry);
961
- return { stop: () => {
962
- entry.shouldStop = true;
963
- } };
964
- }
965
- /**
966
- * Register a custom rendering callback for a specific exception type.
967
- *
968
- * The callback should return a `Response` (for HTTP contexts), an `ErrorResponse`,
969
- * or `undefined` to fall through to the default renderer.
970
- *
971
- * @typeParam T - The exception type to match
972
- * @param errorClass - Constructor of the exception to match
973
- * @param callback - Rendering function receiving the typed error and context
974
- *
975
- * @example
976
- * ```typescript
977
- * this.renderable(MaintenanceError, (e, ctx) => {
978
- * if (ctx.type === 'http') {
979
- * return ctx.ctx.html('<h1>Down for maintenance</h1>', 503)
980
- * }
981
- * })
982
- * ```
983
- */
984
- renderable(errorClass, callback) {
985
- this.renderables.push({
986
- errorClass,
987
- callback
988
- });
989
- }
990
- /**
991
- * Suppress reporting (logging) for the given exception types.
992
- *
993
- * Errors matching these classes will still be rendered into responses
994
- * but will not be logged or sent to external reporters.
995
- *
996
- * @param errorClasses - Array of exception constructors to suppress
997
- *
998
- * @example
999
- * ```typescript
1000
- * this.dontReport([RouteNotFoundError, SchemaValidationError])
1001
- * ```
1002
- */
1003
- dontReport(errorClasses) {
1004
- for (const cls of errorClasses) this.dontReportSet.add(cls);
1005
- }
1006
- /**
1007
- * Override the log severity for a specific exception type.
1008
- *
1009
- * By default, severity is derived from the error code range.
1010
- * Use this to promote or demote specific errors.
1011
- *
1012
- * @param errorClass - Constructor of the exception to override
1013
- * @param severity - The log severity to use
1014
- *
1015
- * @example
1016
- * ```typescript
1017
- * this.level(RecordNotFoundError, 'warn')
1018
- * ```
1019
- */
1020
- level(errorClass, severity) {
1021
- this.levelOverrides.set(errorClass, severity);
1022
- }
1023
- /**
1024
- * Add global context data to all exception log entries.
1025
- *
1026
- * The callback is invoked on every reported error and its return value
1027
- * is merged into the log data.
1028
- *
1029
- * @param callback - Function returning key-value pairs to include in logs
1030
- *
1031
- * @example
1032
- * ```typescript
1033
- * this.context(() => ({
1034
- * appVersion: '1.2.3',
1035
- * region: env.CF_REGION,
1036
- * }))
1037
- * ```
1038
- */
1039
- context(callback) {
1040
- this.contextCallbacks.push(callback);
1041
- }
1042
- /**
1043
- * Register a callback to post-process every error Response before it is returned.
1044
- *
1045
- * Use this to add headers, modify the body, change content type, or
1046
- * transform the response in any way.
1047
- *
1048
- * @param callback - Function receiving (response, error, context) and returning a Response
1049
- *
1050
- * @example
1051
- * ```typescript
1052
- * this.respond((response, error, ctx) => {
1053
- * response.headers.set('X-Error-Code', String(error.code))
1054
- * return response
1055
- * })
1056
- * ```
1057
- */
1058
- respond(callback) {
1059
- this.respondCallbacks.push(callback);
1060
- }
1061
- /**
1062
- * Resolve a service from the DI container.
1063
- *
1064
- * Useful inside `register()` callbacks for accessing injected services
1065
- * (e.g., Sentry, analytics, custom loggers).
1066
- *
1067
- * @typeParam T - The type of the service to resolve
1068
- * @param token - DI token (symbol or constructor)
1069
- * @returns The resolved service instance
1070
- *
1071
- * @example
1072
- * ```typescript
1073
- * this.reportable(CriticalError, (e) => {
1074
- * this.resolve(SentryService).captureException(e)
1075
- * })
1076
- * ```
1077
- */
1078
- resolve(token) {
1079
- return this.container.resolve(token);
1080
- }
1081
- /**
1082
- * Handle an error through the full exception pipeline.
1083
- *
1084
- * This is the single entry point used by all contexts (HTTP, queue, cron, CLI).
1085
- * It normalizes the error, reports it (non-blocking via `waitUntil`),
1086
- * renders it into a Response, and applies post-processing.
1087
- *
1088
- * @param error - The thrown error (may or may not be an ApplicationError)
1089
- * @param context - The execution context where the error occurred
1090
- * @returns A Response (JSON by default, customizable via renderable/respond)
1091
- */
1092
- async handle(error, context) {
1093
- const appError = this.normalizeError(error);
1094
- this.executionContext.waitUntil(this.performReport(appError, context));
1095
- const response = await this.performRender(appError, context);
1096
- return this.applyRespondCallbacks(response, appError, context);
1097
- }
1098
- /**
1099
- * Normalize an unknown error into an ApplicationError.
1100
- * Non-ApplicationError values are wrapped in InternalError.
1101
- */
1102
- normalizeError(error) {
1103
- if (isApplicationError(error)) return error;
1104
- const originalMessage = error instanceof Error ? error.message : String(error);
1105
- const internalError = new InternalError({
1106
- originalError: originalMessage,
1107
- stack: error instanceof Error ? error.stack : void 0
1108
- });
1109
- if (this.environment === "development") {
1110
- internalError.message = originalMessage;
1111
- if (error instanceof Error && error.stack) internalError.stack = error.stack;
1112
- }
1113
- return internalError;
1114
- }
1115
- /**
1116
- * Run the reporting pipeline for an error.
1117
- */
1118
- async performReport(error, context) {
1119
- if (typeof error.report === "function") {
1120
- if (error.report() !== false) return;
1121
- }
1122
- if (this.shouldNotReport(error)) return;
1123
- const entry = this.findReportable(error);
1124
- if (entry) {
1125
- await entry.callback(error, context);
1126
- if (entry.shouldStop) return;
1127
- }
1128
- this.defaultReport(error, context);
1129
- }
1130
- /**
1131
- * Run the rendering pipeline for an error, producing a Response.
1132
- */
1133
- async performRender(error, context) {
1134
- if (typeof error.render === "function") {
1135
- const result = error.render(context);
1136
- if (result !== void 0) return this.toResponse(result, error);
1137
- }
1138
- const entry = this.findRenderable(error);
1139
- if (entry) {
1140
- const result = entry.callback(error, context);
1141
- if (result !== void 0) return this.toResponse(await result, error);
1142
- }
1143
- return this.defaultRender(error, context);
1144
- }
1145
- /**
1146
- * Apply all respond() callbacks to post-process a Response.
1147
- */
1148
- applyRespondCallbacks(response, error, context) {
1149
- let result = response;
1150
- for (const callback of this.respondCallbacks) result = callback(result, error, context);
1151
- return result;
1152
- }
1153
- /**
1154
- * Check if an error is in the dontReport set.
1155
- */
1156
- shouldNotReport(error) {
1157
- for (const cls of this.dontReportSet) if (error instanceof cls) return true;
1158
- return false;
1159
- }
1160
- /**
1161
- * Find the most-specific reportable entry for an error.
1162
- * Walks entries in registration order; picks the most-specific `instanceof` match.
1163
- */
1164
- findReportable(error) {
1165
- let best;
1166
- for (const entry of this.reportables) if (error instanceof entry.errorClass) {
1167
- if (!best || !(error instanceof best.errorClass) || entry.errorClass.prototype instanceof best.errorClass) best = entry;
1168
- }
1169
- return best;
1170
- }
1171
- /**
1172
- * Find the most-specific renderable entry for an error.
1173
- */
1174
- findRenderable(error) {
1175
- let best;
1176
- for (const entry of this.renderables) if (error instanceof entry.errorClass) {
1177
- if (!best || !(error instanceof best.errorClass) || entry.errorClass.prototype instanceof best.errorClass) best = entry;
1178
- }
1179
- return best;
1180
- }
1181
- /**
1182
- * Default reporting — log with appropriate severity and i18n translation.
1183
- */
1184
- defaultReport(error, context) {
1185
- const translatedMessage = this.translateError(error, context);
1186
- const severity = this.resolveSeverity(error);
1187
- const globalContext = this.gatherContext();
1188
- const logData = {
1189
- code: error.code,
1190
- message: translatedMessage,
1191
- timestamp: error.timestamp,
1192
- metadata: error.metadata,
1193
- name: error.name,
1194
- ...globalContext
1195
- };
1196
- switch (severity) {
1197
- case "debug":
1198
- this.logger.debug("[ApplicationError]", logData);
1199
- break;
1200
- case "info":
1201
- this.logger.info("[ApplicationError]", logData);
1202
- break;
1203
- case "warn":
1204
- this.logger.warn("[ApplicationError]", logData);
1205
- break;
1206
- case "error":
1207
- this.logger.error("[ApplicationError]", logData);
1208
- break;
1209
- }
1210
- }
1211
- /**
1212
- * Default rendering — content-negotiated.
1213
- *
1214
- * For HTTP requests that accept HTML: renders a minimal branded HTML page.
1215
- * For everything else (API, queue, cron, CLI): returns JSON.
1216
- *
1217
- * Errors are always logged via `performReport` (non-blocking waitUntil),
1218
- * so they appear in the console regardless of the rendered response format.
1219
- */
1220
- defaultRender(error, context) {
1221
- const translatedMessage = this.translateError(error, context);
1222
- const errorResponse = error.toErrorResponse(this.environment, translatedMessage);
1223
- const status = resolveHttpStatus(error);
1224
- if (context.type === "http" && this.wantsHtml(context)) return this.renderDefaultHtml(errorResponse, status);
1225
- return Response.json(errorResponse, { status });
1226
- }
1227
- /**
1228
- * Check if the HTTP request prefers an HTML response.
1229
- *
1230
- * Uses the `Accept` header to determine format. Inertia v3 XHR requests
1231
- * send `Accept: text/html, application/xhtml+xml`, so they naturally
1232
- * receive HTML error pages (displayed in Inertia's error modal in dev).
1233
- *
1234
- * Override in a subclass to customize content negotiation logic.
1235
- */
1236
- wantsHtml(context) {
1237
- return (context.ctx.c.req.header("accept") ?? "").includes("text/html");
1238
- }
1239
- /**
1240
- * Minimal production HTML error page with inline styles.
1241
- */
1242
- renderDefaultHtml(errorResponse, status) {
1243
- const title = this.escapeHtml(errorResponse.message);
1244
- const html = `<!DOCTYPE html>
1245
- <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
1246
- <title>${status} - ${title}</title>
1247
- <style>*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,-apple-system,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f8fafc;color:#334155}.container{text-align:center;padding:2rem}.status{font-size:6rem;font-weight:800;color:#13c397;line-height:1}.message{font-size:1.25rem;color:#64748b;margin-top:1rem}</style>
1248
- </head><body><div class="container"><div class="status">${status}</div><div class="message">${title}</div></div></body></html>`;
1249
- return new Response(html, {
1250
- status,
1251
- headers: { "content-type": "text/html; charset=utf-8" }
1252
- });
1253
- }
1254
- escapeHtml(str) {
1255
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1256
- }
1257
- /**
1258
- * Convert a render result (Response or ErrorResponse) into a Response.
1259
- */
1260
- toResponse(result, error) {
1261
- if (result instanceof Response) return result;
1262
- const status = resolveHttpStatus(error);
1263
- return Response.json(result, { status });
1264
- }
1265
- /**
1266
- * Translate an error's message key via i18n.
1267
- * Uses the request container (from HTTP context) for correct locale,
1268
- * falling back to the global container or raw message string.
1269
- */
1270
- translateError(error, context) {
1271
- try {
1272
- const i18n = (context.type === "http" ? context.ctx.getContainer() : this.container).resolve(I18N_TOKENS.I18nService);
1273
- const params = error.metadata;
1274
- return i18n.t(error.message, params);
1275
- } catch {
1276
- return error.message;
1277
- }
1278
- }
1279
- /**
1280
- * Resolve the log severity for an error.
1281
- * Checks level overrides first, then falls back to code-range-based severity.
1282
- */
1283
- resolveSeverity(error) {
1284
- let bestClass;
1285
- let bestSeverity;
1286
- for (const [cls, severity] of this.levelOverrides) if (error instanceof cls) {
1287
- if (!bestClass || cls.prototype instanceof bestClass) {
1288
- bestClass = cls;
1289
- bestSeverity = severity;
1290
- }
1291
- }
1292
- return bestSeverity ?? this.getDefaultSeverity(error.code);
1293
- }
1294
- /**
1295
- * Determine default log severity based on error code range.
1296
- */
1297
- getDefaultSeverity(code) {
1298
- if (code >= 9e3) return "error";
1299
- if (code >= 2e3 && code < 3e3) return "error";
1300
- if (code >= 5e3 && code < 6e3) return "warn";
1301
- if (code >= 1e3 && code < 2e3) return "info";
1302
- if (code >= 3e3 && code < 5e3) return "warn";
1303
- return "error";
1304
- }
1305
- /**
1306
- * Gather all global context data from registered callbacks.
1307
- */
1308
- gatherContext() {
1309
- if (this.contextCallbacks.length === 0) return {};
1310
- const merged = {};
1311
- for (const callback of this.contextCallbacks) Object.assign(merged, callback());
1312
- return merged;
1313
- }
1314
- };
1315
- ExceptionHandler = __decorate([
1316
- Transient(),
1317
- __decorateParam(0, inject(LOGGER_TOKENS.LoggerService)),
1318
- __decorateParam(1, inject(DI_TOKENS.CloudflareEnv)),
1319
- __decorateParam(2, inject(CONTAINER_TOKEN)),
1320
- __decorateParam(3, inject(DI_TOKENS.ExecutionContext)),
1321
- __decorateMetadata("design:paramtypes", [
1322
- Object,
1323
- Object,
1324
- Object,
1325
- Object
1326
- ])
1327
- ], ExceptionHandler);
1328
- //#endregion
1329
- //#region src/errors/default-exception-handler.ts
1330
- let DefaultExceptionHandler = class DefaultExceptionHandler extends ExceptionHandler {
1331
- register() {}
1332
- };
1333
- DefaultExceptionHandler = __decorate([Transient()], DefaultExceptionHandler);
1334
- //#endregion
1335
- //#region src/errors/error-response.ts
1336
- /**
1337
- * Type guard to check if an object is an ErrorResponse
1338
- */
1339
- function isErrorResponse(obj) {
1340
- return typeof obj === "object" && obj !== null && "code" in obj && typeof obj.code === "number" && "message" in obj && typeof obj.message === "string" && "timestamp" in obj && typeof obj.timestamp === "string";
1341
- }
1342
- //#endregion
1343
- //#region src/router/constants.ts
1344
- /**
1345
- * Type-safe context keys for Hono router variables
1346
- * Using symbols to avoid string collisions
1347
- */
1348
- const ROUTER_CONTEXT_KEYS = {
1349
- REQUEST_CONTAINER: "requestContainer",
1350
- LOCALE: "locale"
1351
- };
1352
- /**
1353
- * Metadata keys for storing route and controller configuration
1354
- * Using symbols to avoid collisions with other decorators
1355
- */
1356
- const ROUTE_METADATA_KEYS = {
1357
- CONTROLLER_ROUTE: Symbol.for("stratal:controller:route"),
1358
- CONTROLLER_OPTIONS: Symbol.for("stratal:controller:options"),
1359
- CONTROLLER_MIDDLEWARES: Symbol.for("stratal:controller:middlewares"),
1360
- ROUTE_CONFIG: Symbol.for("stratal:route:config"),
1361
- DECORATED_METHODS: Symbol.for("stratal:decorated:methods"),
1362
- AUTH_GUARD: Symbol.for("stratal:auth:guard"),
1363
- GATEWAY_MARKER: Symbol.for("stratal:gateway:marker"),
1364
- WS_ON_MESSAGE: Symbol.for("stratal:ws:on-message"),
1365
- WS_ON_CLOSE: Symbol.for("stratal:ws:on-close"),
1366
- WS_ON_ERROR: Symbol.for("stratal:ws:on-error"),
1367
- RATE_LIMIT: Symbol.for("stratal:route:rate-limit")
1368
- };
1369
- /**
1370
- * Security scheme identifiers for OpenAPI
1371
- * These reference the security scheme definitions in security.schemas.ts
1372
- */
1373
- const SECURITY_SCHEMES = {
1374
- BEARER_AUTH: "bearerAuth",
1375
- API_KEY: "apiKey",
1376
- SESSION_COOKIE: "sessionCookie"
1377
- };
1378
- /**
1379
- * HTTP method mapping for RESTful controller methods
1380
- * Maps controller method names to HTTP verbs and path patterns
1381
- */
1382
- const HTTP_METHODS = {
1383
- index: {
1384
- method: "get",
1385
- path: ""
1386
- },
1387
- show: {
1388
- method: "get",
1389
- path: "/:id"
1390
- },
1391
- create: {
1392
- method: "post",
1393
- path: ""
1394
- },
1395
- update: {
1396
- method: "put",
1397
- path: "/:id"
1398
- },
1399
- patch: {
1400
- method: "patch",
1401
- path: "/:id"
1402
- },
1403
- destroy: {
1404
- method: "delete",
1405
- path: "/:id"
1406
- }
1407
- };
1408
- /**
1409
- * Default success status codes for RESTful controller methods
1410
- * Used by @Route() decorator to auto-derive response status
1411
- */
1412
- const METHOD_STATUS_CODES = {
1413
- index: 200,
1414
- show: 200,
1415
- create: 201,
1416
- update: 200,
1417
- patch: 200,
1418
- destroy: 200
1419
- };
1420
- /**
1421
- * Sentinel symbol to opt a controller out of versioning.
1422
- * When used as the version, no prefix is applied even when defaultVersion is set.
1423
- */
1424
- const VERSION_NEUTRAL = Symbol.for("stratal:version:neutral");
1425
- /**
1426
- * Default content type for request bodies and responses
1427
- */
1428
- const DEFAULT_CONTENT_TYPE = "application/json";
1429
- //#endregion
1430
- //#region src/router/router-context.ts
1431
- /**
1432
- * Router context wrapper with helper methods
1433
- *
1434
- * Provides convenient access to Hono's context and common request/response operations.
1435
- * The native Hono context is available via the `c` property for advanced use cases.
1436
- *
1437
- * @example
1438
- * ```typescript
1439
- * async index(ctx: RouterContext): Promise<Response> {
1440
- * // Use helper methods
1441
- * const users = await this.service.findAll()
1442
- * return ctx.json(users)
1443
- * }
1444
- *
1445
- * async show(ctx: RouterContext): Promise<Response> {
1446
- * // Access route params
1447
- * const id = ctx.param('id')
1448
- * const user = await this.service.findById(id)
1449
- * return ctx.json(user)
1450
- * }
1451
- *
1452
- * async create(ctx: RouterContext): Promise<Response> {
1453
- * // Parse request body
1454
- * const body = await ctx.body<CreateUserInput>()
1455
- * const user = await this.service.create(body)
1456
- * return ctx.json(user, 201)
1457
- * }
1458
- * ```
1459
- */
1460
- var RouterContext = class extends Macroable {
1461
- c;
1462
- /**
1463
- * Native Hono context
1464
- * Access for advanced use cases not covered by helper methods
1465
- */
1466
- constructor(c) {
1467
- super();
1468
- this.c = c;
1469
- }
1470
- /**
1471
- * Cloudflare-provided request properties (geo, TLS, bot management, etc.).
1472
- * Always available on Cloudflare Workers requests via `c.req.raw.cf`.
1473
- */
1474
- get cf() {
1475
- return this.c.req.raw.cf;
1476
- }
1477
- /**
1478
- * Get request-scoped DI container
1479
- * Contains request-specific services and context (AuthContext)
1480
- *
1481
- * @throws Error if container not initialized
1482
- */
1483
- getContainer() {
1484
- const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER);
1485
- if (!container) throw new RequestContainerNotInitializedError();
1486
- return container;
1487
- }
1488
- /**
1489
- * Set locale for the current request
1490
- *
1491
- * @param locale - Locale code (e.g., 'en', 'fr')
1492
- */
1493
- setLocale(locale) {
1494
- this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale);
1495
- }
1496
- /**
1497
- * Get locale for the current request
1498
- *
1499
- * @returns Current locale code
1500
- */
1501
- getLocale() {
1502
- return this.c.get(ROUTER_CONTEXT_KEYS.LOCALE) || "en";
1503
- }
1504
- /**
1505
- * Return JSON response
1506
- *
1507
- * When data is null, automatically returns 204 No Content (configurable via status param).
1508
- *
1509
- * @param data - Data to serialize as JSON, or null for 204
1510
- * @param status - HTTP status code (default: 200, or 204 when data is null)
1511
- */
1512
- json(data, status) {
1513
- if (data === null) return this.c.body(null, status ?? 204);
1514
- return this.c.json(data, status);
1515
- }
1516
- param(key) {
1517
- const all = this.c.req.valid("param") ?? {};
1518
- return key === void 0 ? all : all[key];
1519
- }
1520
- /**
1521
- * Get query parameter value
1522
- *
1523
- * @param key - Query parameter name
1524
- */
1525
- query(key) {
1526
- const validated = this.c.req.valid("query");
1527
- return key ? validated[key] : validated;
1528
- }
1529
- /**
1530
- * Get request header value
1531
- *
1532
- * @param name - Header name (case-insensitive)
1533
- */
1534
- header(name) {
1535
- return this.c.req.header(name);
1536
- }
1537
- /**
1538
- * Get validated request body from OpenAPI route
1539
- * Returns pre-validated data that has passed schema validation
1540
- *
1541
- * @returns Validated JSON body
1542
- */
1543
- body() {
1544
- return this.c.req.valid("json");
1545
- }
1546
- /**
1547
- * Return text response
1548
- *
1549
- * @param text - Text content
1550
- * @param status - HTTP status code (default: 200)
1551
- */
1552
- text(text, status) {
1553
- return this.c.text(text, status);
1554
- }
1555
- /**
1556
- * Return HTML response
1557
- *
1558
- * @param html - HTML content
1559
- * @param status - HTTP status code (default: 200)
1560
- */
1561
- html(html, status) {
1562
- return this.c.html(html, status);
1563
- }
1564
- /**
1565
- * Generate a URL from a named route.
1566
- *
1567
- * Keys matching `:param` placeholders fill the path.
1568
- * Domain params are consumed from the same object.
1569
- * Extra keys become query string parameters.
1570
- *
1571
- * @param name - Named route identifier
1572
- * @param params - Route params + domain params + extra query params
1573
- * @param options - URL generation options (e.g., `{ absolute: true }`)
1574
- *
1575
- * @example
1576
- * ```typescript
1577
- * ctx.route('users.show', { id: '1' }) // '/v1/users/1'
1578
- * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'
1579
- * ```
1580
- */
1581
- route(name, params, options) {
1582
- return this.resolveUri().route(name, params, options);
1583
- }
1584
- /**
1585
- * Get a domain parameter value from the current request.
1586
- * Domain params are set by the domain matching middleware.
1587
- *
1588
- * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')
1589
- *
1590
- * @example
1591
- * ```typescript
1592
- * const tenant = ctx.domain('tenant')
1593
- * ```
1594
- */
1595
- domain(key) {
1596
- return this.c.get(`domain:${key}`);
1597
- }
1598
- /**
1599
- * Generate a signed URL from a named route.
1600
- *
1601
- * @param name - Named route identifier
1602
- * @param params - Route params (same as route())
1603
- * @param options - Signing options (e.g., expiresIn) and URL options
1604
- * @returns Signed URL string with signature query param
1605
- */
1606
- async signedUrl(name, params, options) {
1607
- return this.resolveUri().signedRoute(name, params, options);
1608
- }
1609
- /**
1610
- * Check if the current request has a valid signature.
1611
- *
1612
- * @returns true if the URL signature is valid and not expired
1613
- */
1614
- async hasValidSignature() {
1615
- return this.resolveUri().hasValidSignature();
1616
- }
1617
- /**
1618
- * Redirect to another URL
1619
- *
1620
- * @param url - Target URL
1621
- * @param status - HTTP status code (default: 302)
1622
- */
1623
- redirect(url, status) {
1624
- return this.c.redirect(url, status);
1625
- }
1626
- /**
1627
- * Return a streaming response (binary/generic)
1628
- *
1629
- * @param callback - Async function that writes to the stream
1630
- * @param onError - Optional error handler called if an error occurs during streaming
1631
- */
1632
- stream(callback, onError) {
1633
- return stream(this.c, callback, onError);
1634
- }
1635
- /**
1636
- * Return a streaming text response
1637
- *
1638
- * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.
1639
- *
1640
- * @param callback - Async function that writes text to the stream
1641
- * @param onError - Optional error handler called if an error occurs during streaming
1642
- */
1643
- streamText(callback, onError) {
1644
- this.c.header("Content-Encoding", "Identity");
1645
- return streamText(this.c, callback, onError);
1646
- }
1647
- /**
1648
- * Return a Server-Sent Events (SSE) streaming response
1649
- *
1650
- * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.
1651
- *
1652
- * @param callback - Async function that writes SSE events to the stream
1653
- * @param onError - Optional error handler called if an error occurs during streaming
1654
- */
1655
- streamSSE(callback, onError) {
1656
- this.c.header("Content-Encoding", "Identity");
1657
- return streamSSE(this.c, callback, onError);
1658
- }
1659
- resolveUri() {
1660
- return this.getContainer().resolve(ROUTER_TOKENS.Uri);
1661
- }
1662
- };
1663
- //#endregion
1664
- //#region src/errors/exception-context.ts
1665
- /**
1666
- * Create an HTTP exception context from a Hono context.
1667
- *
1668
- * @param c - The raw Hono context from the request
1669
- * @returns An {@link HttpExceptionContext} wrapping a RouterContext
1670
- */
1671
- function createHttpExceptionContext(c) {
1672
- return {
1673
- type: "http",
1674
- ctx: new RouterContext(c)
1675
- };
1676
- }
1677
- /**
1678
- * Create a queue exception context.
1679
- *
1680
- * @param queueName - The name of the queue being processed
1681
- * @returns A {@link QueueExceptionContext}
1682
- */
1683
- function createQueueExceptionContext(queueName) {
1684
- return {
1685
- type: "queue",
1686
- queueName
1687
- };
1688
- }
1689
- /**
1690
- * Create a cron exception context.
1691
- *
1692
- * @returns A {@link CronExceptionContext}
1693
- */
1694
- function createCronExceptionContext() {
1695
- return { type: "cron" };
1696
- }
1697
- /**
1698
- * Create a CLI command exception context.
1699
- *
1700
- * @param commandName - The name of the command that threw
1701
- * @returns A {@link CliExceptionContext}
1702
- */
1703
- function createCliExceptionContext(commandName) {
1704
- return {
1705
- type: "cli",
1706
- commandName
1707
- };
1708
- }
1709
- //#endregion
1710
- //#region src/errors/request-container-not-initialized.error.ts
1711
- /**
1712
- * RequestContainerNotInitializedError
1713
- *
1714
- * Thrown when attempting to access the request-scoped container before it has been initialized.
1715
- * This typically indicates that the RouterService middleware hasn't run yet,
1716
- * or the router context is being accessed outside of a request lifecycle.
1717
- */
1718
- var RequestContainerNotInitializedError = class extends ApplicationError {
1719
- constructor() {
1720
- super("errors.requestContainerNotInitialized", ERROR_CODES.SYSTEM.REQUEST_CONTAINER_NOT_INITIALIZED);
1721
- }
1722
- };
1723
- //#endregion
1724
- //#region src/errors/stratal-not-initialized.error.ts
1725
- /**
1726
- * StratalNotInitializedError
1727
- *
1728
- * Thrown when attempting to resolve the Application instance before Stratal has been instantiated.
1729
- * This typically indicates that the Stratal instance is not exported as the default export.
1730
- */
1731
- var StratalNotInitializedError = class extends ApplicationError {
1732
- constructor() {
1733
- super("errors.stratalNotInitialized", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR);
1734
- }
1735
- };
1736
- //#endregion
1737
- export { Scope as A, ConditionalBindingFallbackError as B, abort as C, runWithContainer as D, getContainer as E, injectable$1 as F, ApplicationError as H, instancePerContainerCachingFactory$1 as I, singleton as L, container$1 as M, delay as N, ContainerNotInitializedError as O, inject$1 as P, ConditionalBindingBuilderImpl as R, HttpException as S, containerStorage as T, ROUTER_TOKENS as V, ExceptionHandler as _, createHttpExceptionContext as a, getHttpStatus as b, DEFAULT_CONTENT_TYPE as c, ROUTER_CONTEXT_KEYS as d, ROUTE_METADATA_KEYS as f, DefaultExceptionHandler as g, isErrorResponse as h, createCronExceptionContext as i, Container as j, ERROR_CODES as k, HTTP_METHODS as l, VERSION_NEUTRAL as m, RequestContainerNotInitializedError as n, createQueueExceptionContext as o, SECURITY_SCHEMES as p, createCliExceptionContext as r, RouterContext as s, StratalNotInitializedError as t, METHOD_STATUS_CODES as u, isApplicationError as v, I18N_TOKENS as w, resolveHttpStatus as x, InternalError as y, RequestScopeOperationNotAllowedError as z };
1738
-
1739
- //# sourceMappingURL=errors-COW9-Mar.mjs.map