stratal 0.0.16 → 0.0.18

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