@warlock.js/core 4.16.0 → 5.0.1

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 (180) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/warlock.js +154 -1
  3. package/esm/application/application.d.mts +65 -1
  4. package/esm/application/application.d.mts.map +1 -1
  5. package/esm/application/application.mjs +62 -0
  6. package/esm/application/application.mjs.map +1 -1
  7. package/esm/application/index.d.mts +1 -1
  8. package/esm/cli/cli-commands.manager.mjs +60 -10
  9. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  10. package/esm/cli/commands/dev-server.command.mjs +1 -0
  11. package/esm/cli/commands/dev-server.command.mjs.map +1 -1
  12. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +40 -0
  13. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -0
  14. package/esm/cli/commands/doctor/checks/index.mjs +4 -2
  15. package/esm/cli/commands/doctor/checks/index.mjs.map +1 -1
  16. package/esm/commands/cli-command.d.mts +1 -1
  17. package/esm/commands/cli-command.d.mts.map +1 -1
  18. package/esm/commands/cli-command.mjs.map +1 -1
  19. package/esm/commands/types.d.mts +10 -2
  20. package/esm/commands/types.d.mts.map +1 -1
  21. package/esm/config/config-handlers.d.mts +1 -2
  22. package/esm/config/config-handlers.d.mts.map +1 -1
  23. package/esm/config/config-handlers.mjs +3 -2
  24. package/esm/config/config-handlers.mjs.map +1 -1
  25. package/esm/config/locale-configuration.mjs +29 -0
  26. package/esm/config/locale-configuration.mjs.map +1 -0
  27. package/esm/connectors/assert-no-reserved-connector-names.d.mts +7 -0
  28. package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -0
  29. package/esm/connectors/assert-no-reserved-connector-names.mjs +44 -0
  30. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -0
  31. package/esm/connectors/assert-unique-connector-names.d.mts +7 -0
  32. package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -0
  33. package/esm/connectors/assert-unique-connector-names.mjs +20 -0
  34. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -0
  35. package/esm/connectors/connectors-manager.d.mts +38 -0
  36. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  37. package/esm/connectors/connectors-manager.mjs +45 -12
  38. package/esm/connectors/connectors-manager.mjs.map +1 -1
  39. package/esm/connectors/describe-server-address.mjs +75 -0
  40. package/esm/connectors/describe-server-address.mjs.map +1 -0
  41. package/esm/connectors/http-connector.d.mts.map +1 -1
  42. package/esm/connectors/http-connector.mjs +6 -3
  43. package/esm/connectors/http-connector.mjs.map +1 -1
  44. package/esm/connectors/index.d.mts +4 -1
  45. package/esm/connectors/index.mjs +4 -1
  46. package/esm/connectors/register-configured-connectors.d.mts +14 -0
  47. package/esm/connectors/register-configured-connectors.d.mts.map +1 -0
  48. package/esm/connectors/register-configured-connectors.mjs +99 -0
  49. package/esm/connectors/register-configured-connectors.mjs.map +1 -0
  50. package/esm/connectors/socket-connector.d.mts.map +1 -1
  51. package/esm/connectors/socket-connector.mjs +4 -1
  52. package/esm/connectors/socket-connector.mjs.map +1 -1
  53. package/esm/connectors/types.d.mts +76 -1
  54. package/esm/connectors/types.d.mts.map +1 -1
  55. package/esm/connectors/types.mjs.map +1 -1
  56. package/esm/database/models/database-log/database-log.d.mts +50 -2
  57. package/esm/database/models/database-log/database-log.d.mts.map +1 -1
  58. package/esm/database/utils.d.mts +2 -2
  59. package/esm/database/utils.d.mts.map +1 -1
  60. package/esm/dev-server/development-server.mjs +1 -0
  61. package/esm/dev-server/development-server.mjs.map +1 -1
  62. package/esm/dev-server/layer-executor.mjs +2 -1
  63. package/esm/dev-server/layer-executor.mjs.map +1 -1
  64. package/esm/dev-server/read-config-ast.mjs +48 -0
  65. package/esm/dev-server/read-config-ast.mjs.map +1 -0
  66. package/esm/dev-server/run-typings-generation.mjs +18 -0
  67. package/esm/dev-server/run-typings-generation.mjs.map +1 -0
  68. package/esm/dev-server/type-generator.mjs +30 -39
  69. package/esm/dev-server/type-generator.mjs.map +1 -1
  70. package/esm/generations/add-command.action.mjs +169 -1
  71. package/esm/generations/add-command.action.mjs.map +1 -1
  72. package/esm/generations/stubs.mjs +93 -1
  73. package/esm/generations/stubs.mjs.map +1 -1
  74. package/esm/http/context/request-context.d.mts +14 -3
  75. package/esm/http/context/request-context.d.mts.map +1 -1
  76. package/esm/http/context/request-context.mjs +11 -1
  77. package/esm/http/context/request-context.mjs.map +1 -1
  78. package/esm/http/context/request-memo.d.mts +21 -0
  79. package/esm/http/context/request-memo.d.mts.map +1 -0
  80. package/esm/http/context/request-memo.mjs +48 -0
  81. package/esm/http/context/request-memo.mjs.map +1 -0
  82. package/esm/http/database/RequestLog.d.mts +164 -2
  83. package/esm/http/database/RequestLog.d.mts.map +1 -1
  84. package/esm/http/index.d.mts +6 -5
  85. package/esm/http/index.mjs +2 -1
  86. package/esm/http/middleware/cache-response-middleware.d.mts +2 -2
  87. package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
  88. package/esm/http/middleware/cache-response-middleware.mjs +1 -1
  89. package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
  90. package/esm/http/middleware/concurrency-limit.middleware.mjs +1 -1
  91. package/esm/http/middleware/concurrency-limit.middleware.mjs.map +1 -1
  92. package/esm/http/middleware/idempotency.middleware.mjs +1 -1
  93. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  94. package/esm/http/middleware/index.d.mts +1 -1
  95. package/esm/http/middleware/index.mjs +1 -1
  96. package/esm/http/middleware/inject-request-context.d.mts +1 -8
  97. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  98. package/esm/http/middleware/inject-request-context.mjs +9 -22
  99. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  100. package/esm/http/middleware/ip-filter.middleware.mjs +1 -1
  101. package/esm/http/middleware/ip-filter.middleware.mjs.map +1 -1
  102. package/esm/http/middleware/maintenance.middleware.mjs +1 -1
  103. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  104. package/esm/http/middleware/max-body-size.middleware.mjs +1 -1
  105. package/esm/http/middleware/max-body-size.middleware.mjs.map +1 -1
  106. package/esm/http/middleware/rate-limit.middleware.mjs +1 -1
  107. package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
  108. package/esm/http/middleware/utils/idempotency-key.d.mts +0 -14
  109. package/esm/http/middleware/utils/idempotency-key.d.mts.map +1 -1
  110. package/esm/http/middleware/utils/idempotency-key.mjs +19 -1
  111. package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
  112. package/esm/http/request.d.mts +119 -30
  113. package/esm/http/request.d.mts.map +1 -1
  114. package/esm/http/request.mjs +98 -25
  115. package/esm/http/request.mjs.map +1 -1
  116. package/esm/http/response.mjs +1 -1
  117. package/esm/http/response.mjs.map +1 -1
  118. package/esm/http/types.d.mts +36 -1
  119. package/esm/http/types.d.mts.map +1 -1
  120. package/esm/http/uploaded-file.d.mts +51 -19
  121. package/esm/http/uploaded-file.d.mts.map +1 -1
  122. package/esm/http/uploaded-file.mjs +36 -8
  123. package/esm/http/uploaded-file.mjs.map +1 -1
  124. package/esm/index.d.mts +17 -9
  125. package/esm/index.mjs +10 -4
  126. package/esm/production/build-contributions.mjs +115 -0
  127. package/esm/production/build-contributions.mjs.map +1 -0
  128. package/esm/production/production-builder.mjs +97 -2
  129. package/esm/production/production-builder.mjs.map +1 -1
  130. package/esm/production/resolve-build-config.d.mts +25 -0
  131. package/esm/production/resolve-build-config.d.mts.map +1 -0
  132. package/esm/production/resolve-build-config.mjs +43 -1
  133. package/esm/production/resolve-build-config.mjs.map +1 -1
  134. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +1 -1
  135. package/esm/repositories/adapters/cascade/filter-applicator.mjs +20 -9
  136. package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
  137. package/esm/restful/restful.d.mts +29 -8
  138. package/esm/restful/restful.d.mts.map +1 -1
  139. package/esm/restful/restful.mjs +31 -13
  140. package/esm/restful/restful.mjs.map +1 -1
  141. package/esm/router/describe-route-for-log.mjs +29 -0
  142. package/esm/router/describe-route-for-log.mjs.map +1 -0
  143. package/esm/router/index.d.mts +3 -1
  144. package/esm/router/index.mjs +2 -0
  145. package/esm/router/log-request-lifecycle.mjs +38 -0
  146. package/esm/router/log-request-lifecycle.mjs.map +1 -0
  147. package/esm/router/positional-handler-diagnostics.d.mts +90 -0
  148. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -0
  149. package/esm/router/positional-handler-diagnostics.mjs +247 -0
  150. package/esm/router/positional-handler-diagnostics.mjs.map +1 -0
  151. package/esm/router/route-registry.d.mts +34 -0
  152. package/esm/router/route-registry.d.mts.map +1 -0
  153. package/esm/router/router.d.mts.map +1 -1
  154. package/esm/router/router.mjs +87 -63
  155. package/esm/router/router.mjs.map +1 -1
  156. package/esm/router/types.d.mts +23 -5
  157. package/esm/router/types.d.mts.map +1 -1
  158. package/esm/storage/storage.d.mts.map +1 -1
  159. package/esm/storage/storage.mjs +1 -1
  160. package/esm/storage/storage.mjs.map +1 -1
  161. package/esm/storage/utils/safe-fetch.d.mts +11 -1
  162. package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
  163. package/esm/storage/utils/safe-fetch.mjs +51 -4
  164. package/esm/storage/utils/safe-fetch.mjs.map +1 -1
  165. package/esm/tests/vitest-setup.mjs +1 -1
  166. package/esm/utils/load-environment.mjs +33 -2
  167. package/esm/utils/load-environment.mjs.map +1 -1
  168. package/esm/utils/types.d.mts +4 -0
  169. package/esm/utils/types.d.mts.map +1 -1
  170. package/esm/validation/validateAll.mjs +4 -1
  171. package/esm/validation/validateAll.mjs.map +1 -1
  172. package/esm/validation/validators/file-validator.d.mts +25 -1
  173. package/esm/validation/validators/file-validator.d.mts.map +1 -1
  174. package/esm/warlock-config/index.mjs +1 -1
  175. package/esm/warlock-config/normalize-build-config.mjs.map +1 -1
  176. package/esm/warlock-config/types.d.mts +36 -2
  177. package/esm/warlock-config/types.d.mts.map +1 -1
  178. package/package.json +15 -12
  179. package/skills/request-memo/SKILL.md +142 -0
  180. package/skills/use-request-locals/SKILL.md +144 -0
@@ -1,6 +1,6 @@
1
1
  import { UploadedFile } from "./uploaded-file.mjs";
2
2
  import { Response } from "./response.mjs";
3
- import { RequestEvent } from "./types.mjs";
3
+ import { RequestEvent, RequestLocals, RequestUser } from "./types.mjs";
4
4
  import { Middleware, RequestHandler, Route } from "../router/types.mjs";
5
5
  import { BaseValidator } from "@warlock.js/seal";
6
6
  import { trans } from "@mongez/localization";
@@ -44,6 +44,86 @@ declare class Request<RequestValidation = any> {
44
44
  * Decoded access token payload (set by auth middleware)
45
45
  */
46
46
  decodedAccessToken?: any;
47
+ /**
48
+ * The authenticated user attached to this request, if any.
49
+ *
50
+ * `RequestUser` is empty by default, so ANY shape is assignable here at the
51
+ * declaration site — the app or auth package declares its real fields via
52
+ * module augmentation:
53
+ *
54
+ * ```typescript
55
+ * declare module "@warlock.js/core" {
56
+ * interface RequestUser {
57
+ * id: string | number;
58
+ * }
59
+ * }
60
+ * ```
61
+ *
62
+ * Replaces the v4 `GuardedRequest` convention
63
+ * (`create-warlock/.../guarded.request.ts` — `Request<T> & { user: User }`,
64
+ * an intersection type hand-declared per app) with a property core itself
65
+ * declares and types. `clearCurrentUser()` below is the one place core
66
+ * writes it directly; auth middleware is expected to do the same after a
67
+ * successful token resolution.
68
+ */
69
+ user?: RequestUser;
70
+ /**
71
+ * Private, server-only, per-request data bag.
72
+ *
73
+ * Distinct from the input payload (`body` / `query` / `params` / `all()`):
74
+ * a write here never surfaces in `request.all()`, `request.validated()`, or
75
+ * `request.input()`. That is the trap `request.set()` sets for private data
76
+ * — it writes into the payload `all` bag, so anything stored there leaks
77
+ * into every input accessor and, from there, into the client-facing
78
+ * payload. `locals` is the correct home for private per-request app data
79
+ * (a resolved session, a fetched-once model) that must never be mistaken
80
+ * for client input.
81
+ *
82
+ * Augmentable via module augmentation, in the module that OWNS the key:
83
+ *
84
+ * ```typescript
85
+ * declare module "@warlock.js/core" {
86
+ * interface RequestLocals {
87
+ * session?: { token: string };
88
+ * }
89
+ * }
90
+ * ```
91
+ *
92
+ * A plain class-field initializer is sufficient for "fresh per request":
93
+ * `router.ts:925` constructs `new Request()` for every incoming request —
94
+ * `Request` instances are not pooled or reused across requests — so this
95
+ * initializer runs exactly once per request and no value can leak in from
96
+ * a prior one.
97
+ */
98
+ locals: RequestLocals;
99
+ /**
100
+ * Backing field for the lazily-generated CSP nonce. Left `undefined` until
101
+ * the first `request.nonce` read; see the `nonce` getter below.
102
+ */
103
+ protected _nonce?: string;
104
+ /**
105
+ * Per-request Content-Security-Policy nonce — a fresh, unguessable value
106
+ * the web layer hands to `<Scripts nonce={...} />` (the inline payload
107
+ * script) and to the `Content-Security-Policy` header, so a strict
108
+ * `script-src 'nonce-...'` allows only the script this request actually
109
+ * rendered.
110
+ *
111
+ * Generated LAZILY on first access, not eagerly in `setRequest()`: most
112
+ * requests (API routes, anything that isn't rendering HTML) never read it,
113
+ * and spending a `randomBytes` call on every single request for a value
114
+ * most of them discard is wasted entropy draw + CPU. Once generated it is
115
+ * cached in `_nonce`, so every subsequent read within the SAME request
116
+ * returns the identical value — required, since the header and the inline
117
+ * `<script>` tag must agree on one nonce. `_nonce` is a plain field on a
118
+ * per-request `Request` instance (see `locals` above — `router.ts:925`,
119
+ * no pooling), so the cache can never leak into the next request; a fresh
120
+ * `Request` means a fresh, unset `_nonce`.
121
+ *
122
+ * 16 random bytes, base64-encoded — the size the CSP Level 3 spec's own
123
+ * examples use, and far more entropy than an attacker could feasibly guess
124
+ * to defeat the policy.
125
+ */
126
+ get nonce(): string;
47
127
  /**
48
128
  * Current request instance
49
129
  */
@@ -57,23 +137,6 @@ declare class Request<RequestValidation = any> {
57
137
  * Alias to trans method
58
138
  */
59
139
  t: ReturnType<typeof trans>;
60
- /**
61
- * Dynamic properties index signature
62
- *
63
- * This allows attaching custom properties to the request instance,
64
- * commonly used during validation middleware to attach fetched models.
65
- *
66
- * @example
67
- * // In validation middleware:
68
- * const post = await Post.find(request.int("id"));
69
- * if (!post) return response.notFound();
70
- * request.post = post; // Attach the model to the request
71
- *
72
- * // In route handler:
73
- * const post = request.post;
74
- * // Work with the pre-fetched model
75
- */
76
- [key: string]: any;
77
140
  /**
78
141
  * Locale code
79
142
  */
@@ -118,6 +181,20 @@ declare class Request<RequestValidation = any> {
118
181
  * Translate from the given locale code
119
182
  */
120
183
  transFrom(localeCode: string, keyword: string, placeholders?: any): any;
184
+ /**
185
+ * Cache one supported locale without coercing request-controlled input.
186
+ *
187
+ * The default is the answer for a client that asked for NOTHING. A client
188
+ * that did ask is only overridden when its value fails a declared
189
+ * `app.localeCodes` allow-list; with no list declared there is nothing to
190
+ * fail, so the requested locale passes through unchanged.
191
+ */
192
+ protected cacheLocale(candidate: unknown): string;
193
+ /**
194
+ * Resolve the first present Mode B source. Unsupported values fail closed to
195
+ * the configured default instead of widening the application's locale set.
196
+ */
197
+ protected resolveLocale(): string;
121
198
  /**
122
199
  * Get current locale code
123
200
  */
@@ -126,18 +203,16 @@ declare class Request<RequestValidation = any> {
126
203
  * Set locale code
127
204
  */
128
205
  set locale(localeCode: string);
129
- /**
130
- * Get locale code that will be used for translation
131
- */
132
- get localized(): any;
133
206
  /**
134
207
  * Set locale code
135
208
  */
136
209
  setLocaleCode(localeCode: string): this;
137
210
  /**
138
- * Get current locale code or return default locale code
211
+ * @deprecated Use `request.locale`. This alias is removed after one version.
212
+ * The legacy default argument is accepted for source compatibility but the
213
+ * resolved default is owned exclusively by app configuration.
139
214
  */
140
- getLocaleCode(defaultLocaleCode?: string): string;
215
+ getLocaleCode(_legacyDefaultLocaleCode?: string): string;
141
216
  /**
142
217
  * Get http protocol
143
218
  */
@@ -145,11 +220,7 @@ declare class Request<RequestValidation = any> {
145
220
  /**
146
221
  * Validate the given validation schema
147
222
  */
148
- validate(validation: BaseValidator, selectedInputs?: string[]): Promise<any>;
149
- /**
150
- * Clear current user
151
- */
152
- clearCurrentUser(): void;
223
+ validate(validation: BaseValidator, selectedInputs?: string[]): Promise<import("@warlock.js/seal").ValidationResult>;
153
224
  /**
154
225
  * Get value of the given header
155
226
  */
@@ -203,6 +274,24 @@ declare class Request<RequestValidation = any> {
203
274
  /**
204
275
  * Parse the payload and merge it from the request body, params and query string
205
276
  */
277
+ /**
278
+ * Turn a bracket-notation key into the dotted path `set()` expects.
279
+ *
280
+ * `a[b][c]` -> `a.b.c`. Used only for NON-numeric nesting; numeric indices
281
+ * keep the array-of-objects path in {@link parseBody}, which builds real
282
+ * arrays rather than objects with numeric keys.
283
+ */
284
+ protected bracketKeyToPath(key: string): string;
285
+ /**
286
+ * Apply the `key[]` array marker to a parsed value.
287
+ *
288
+ * The subtlety this exists to remove: a key declared `[]` should ALWAYS be an
289
+ * array, but the underlying query/body parser only hands us one when the
290
+ * caller sent the key more than once. Deciding the TYPE from the number of
291
+ * occurrences means one selected filter is a string and two are an array —
292
+ * a shape that changes under the user's hands.
293
+ */
294
+ protected arrayValueFor(value: any, isArrayKey: boolean, parse: (value: any) => any): any;
206
295
  protected parsePayload(): void;
207
296
  /**
208
297
  * Parse body payload
@@ -223,7 +312,7 @@ declare class Request<RequestValidation = any> {
223
312
  /**
224
313
  * Listen to the given event
225
314
  */
226
- on(eventName: RequestEvent, callback: any): any;
315
+ on(eventName: RequestEvent, callback: any): import("@mongez/events").EventSubscription;
227
316
  /**
228
317
  * Make a log message
229
318
  */
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.mts","names":[],"sources":["../../../../../../../core/src/http/request.ts"],"mappings":"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"}
1
+ {"version":3,"file":"request.d.mts","names":[],"sources":["../../../../../../../core/src/http/request.ts"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { config } from "../config/config-getter.mjs";
2
+ import { resolveLocaleConfiguration } from "../config/locale-configuration.mjs";
2
3
  import { createRequestStore } from "./middleware/inject-request-context.mjs";
3
4
  import { validateAll } from "../validation/validateAll.mjs";
4
5
  import { Response } from "./response.mjs";
@@ -10,11 +11,13 @@ import { isEmpty } from "@mongez/supportive-is";
10
11
  import { Random, except, get, only, rtrim, set, unset } from "@mongez/reinforcements";
11
12
  import { colors } from "@mongez/copper";
12
13
  import events from "@mongez/events";
14
+ import { randomBytes } from "node:crypto";
13
15
 
14
16
  //#region ../core/src/http/request.ts
15
17
  var Request = class Request {
16
18
  constructor() {
17
19
  this.payload = {};
20
+ this.locals = {};
18
21
  this.trans = trans;
19
22
  this.t = trans;
20
23
  this._locale = "";
@@ -22,14 +25,39 @@ var Request = class Request {
22
25
  this.startTime = Date.now();
23
26
  }
24
27
  /**
28
+ * Per-request Content-Security-Policy nonce — a fresh, unguessable value
29
+ * the web layer hands to `<Scripts nonce={...} />` (the inline payload
30
+ * script) and to the `Content-Security-Policy` header, so a strict
31
+ * `script-src 'nonce-...'` allows only the script this request actually
32
+ * rendered.
33
+ *
34
+ * Generated LAZILY on first access, not eagerly in `setRequest()`: most
35
+ * requests (API routes, anything that isn't rendering HTML) never read it,
36
+ * and spending a `randomBytes` call on every single request for a value
37
+ * most of them discard is wasted entropy draw + CPU. Once generated it is
38
+ * cached in `_nonce`, so every subsequent read within the SAME request
39
+ * returns the identical value — required, since the header and the inline
40
+ * `<script>` tag must agree on one nonce. `_nonce` is a plain field on a
41
+ * per-request `Request` instance (see `locals` above — `router.ts:925`,
42
+ * no pooling), so the cache can never leak into the next request; a fresh
43
+ * `Request` means a fresh, unset `_nonce`.
44
+ *
45
+ * 16 random bytes, base64-encoded — the size the CSP Level 3 spec's own
46
+ * examples use, and far more entropy than an attacker could feasibly guess
47
+ * to defeat the policy.
48
+ */
49
+ get nonce() {
50
+ if (!this._nonce) this._nonce = randomBytes(16).toString("base64");
51
+ return this._nonce;
52
+ }
53
+ /**
25
54
  * Set request handler
26
55
  */
27
56
  setRequest(request) {
28
57
  this.baseRequest = request;
29
58
  this.resolveRequestId();
30
59
  this.parsePayload();
31
- const localeCode = this.getLocaleCode();
32
- this.trans = this.t = transFrom.bind(null, localeCode);
60
+ this.trans = this.t = (keyword, placeholders) => transFrom(this.getLocaleCode(), keyword, placeholders);
33
61
  return this;
34
62
  }
35
63
  /**
@@ -67,37 +95,58 @@ var Request = class Request {
67
95
  return transFrom(localeCode, keyword, placeholders);
68
96
  }
69
97
  /**
98
+ * Cache one supported locale without coercing request-controlled input.
99
+ *
100
+ * The default is the answer for a client that asked for NOTHING. A client
101
+ * that did ask is only overridden when its value fails a declared
102
+ * `app.localeCodes` allow-list; with no list declared there is nothing to
103
+ * fail, so the requested locale passes through unchanged.
104
+ */
105
+ cacheLocale(candidate) {
106
+ const { defaultLocaleCode, localeCodes } = resolveLocaleConfiguration(config.key("app.localeCode"), config.key("app.localeCodes"));
107
+ const requested = typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
108
+ this._locale = requested !== void 0 && (localeCodes === void 0 || localeCodes.includes(requested)) ? requested : defaultLocaleCode;
109
+ return this._locale;
110
+ }
111
+ /**
112
+ * Resolve the first present Mode B source. Unsupported values fail closed to
113
+ * the configured default instead of widening the application's locale set.
114
+ */
115
+ resolveLocale() {
116
+ const candidate = [
117
+ this.query["locale"],
118
+ this.cookies["locale"],
119
+ this.header("locale")
120
+ ].find((value) => typeof value === "string" && value.length > 0);
121
+ return this.cacheLocale(candidate);
122
+ }
123
+ /**
70
124
  * Get current locale code
71
125
  */
72
126
  get locale() {
73
127
  if (this._locale) return this._locale;
74
- return this.header("translation-locale-code") || this.localized;
128
+ return this.resolveLocale();
75
129
  }
76
130
  /**
77
131
  * Set locale code
78
132
  */
79
133
  set locale(localeCode) {
80
- this._locale = localeCode;
81
- }
82
- /**
83
- * Get locale code that will be used for translation
84
- */
85
- get localized() {
86
- if (this._locale) return this._locale;
87
- return this._locale = this.header("locale") || this.query["locale"];
134
+ this.cacheLocale(localeCode);
88
135
  }
89
136
  /**
90
137
  * Set locale code
91
138
  */
92
139
  setLocaleCode(localeCode) {
93
- this._locale = localeCode;
140
+ this.locale = localeCode;
94
141
  return this;
95
142
  }
96
143
  /**
97
- * Get current locale code or return default locale code
144
+ * @deprecated Use `request.locale`. This alias is removed after one version.
145
+ * The legacy default argument is accepted for source compatibility but the
146
+ * resolved default is owned exclusively by app configuration.
98
147
  */
99
- getLocaleCode(defaultLocaleCode = config.key("app.localeCode") || "en") {
100
- return this.locale || defaultLocaleCode;
148
+ getLocaleCode(_legacyDefaultLocaleCode) {
149
+ return this.locale;
101
150
  }
102
151
  /**
103
152
  * Get http protocol
@@ -112,12 +161,6 @@ var Request = class Request {
112
161
  return await v.validate(validation, selectedInputs ? this.only(selectedInputs) : this.all());
113
162
  }
114
163
  /**
115
- * Clear current user
116
- */
117
- clearCurrentUser() {
118
- this.user = void 0;
119
- }
120
- /**
121
164
  * Get value of the given header
122
165
  */
123
166
  header(name, defaultValue = null) {
@@ -209,6 +252,29 @@ var Request = class Request {
209
252
  /**
210
253
  * Parse the payload and merge it from the request body, params and query string
211
254
  */
255
+ /**
256
+ * Turn a bracket-notation key into the dotted path `set()` expects.
257
+ *
258
+ * `a[b][c]` -> `a.b.c`. Used only for NON-numeric nesting; numeric indices
259
+ * keep the array-of-objects path in {@link parseBody}, which builds real
260
+ * arrays rather than objects with numeric keys.
261
+ */
262
+ bracketKeyToPath(key) {
263
+ return key.replace(/\]\[/g, ".").replace(/\[/g, ".").replace(/\]/g, "");
264
+ }
265
+ /**
266
+ * Apply the `key[]` array marker to a parsed value.
267
+ *
268
+ * The subtlety this exists to remove: a key declared `[]` should ALWAYS be an
269
+ * array, but the underlying query/body parser only hands us one when the
270
+ * caller sent the key more than once. Deciding the TYPE from the number of
271
+ * occurrences means one selected filter is a string and two are an array —
272
+ * a shape that changes under the user's hands.
273
+ */
274
+ arrayValueFor(value, isArrayKey, parse) {
275
+ if (Array.isArray(value)) return value.map(parse);
276
+ return isArrayKey ? [parse(value)] : parse(value);
277
+ }
212
278
  parsePayload() {
213
279
  this.payload.body = this.parseBody(this.baseRequest.body);
214
280
  this.payload.query = this.parseBody(this.baseRequest.query);
@@ -236,9 +302,13 @@ var Request = class Request {
236
302
  if (key.includes("][")) {
237
303
  const keyParts = key.split("[");
238
304
  const keyName = keyParts[0];
239
- if (!arrayOfObjectValues[keyName]) arrayOfObjectValues[keyName] = [];
240
305
  const keyNameParts = keyParts[1].split("]");
241
306
  const index = Number(keyNameParts[0]);
307
+ if (Number.isNaN(index)) {
308
+ set(body, this.bracketKeyToPath(key), this.arrayValueFor(value, isArrayKey, this.parseValue.bind(this)));
309
+ continue;
310
+ }
311
+ if (!arrayOfObjectValues[keyName]) arrayOfObjectValues[keyName] = [];
242
312
  if (!arrayOfObjectValues[keyName][index]) arrayOfObjectValues[keyName][index] = {};
243
313
  const keyName2 = keyParts[2].split("]")[0];
244
314
  arrayOfObjectValues[keyName][index][keyName2] = this.parseValue(value);
@@ -247,7 +317,7 @@ var Request = class Request {
247
317
  const keyParts = key.split("[");
248
318
  const keyName = keyParts[0];
249
319
  const keyNameParts = keyParts[1].split("]");
250
- set(body, keyName + "." + keyNameParts[0], Array.isArray(value) ? value.map(this.parseValue.bind(this)) : this.parseValue(value));
320
+ set(body, keyName + "." + keyNameParts[0], this.arrayValueFor(value, isArrayKey, this.parseValue.bind(this)));
251
321
  continue;
252
322
  }
253
323
  if (Array.isArray(value)) set(body, key, value.map(this.parseValue.bind(this)));
@@ -295,7 +365,7 @@ var Request = class Request {
295
365
  * Listen to the given event
296
366
  */
297
367
  on(eventName, callback) {
298
- return this.subscribe(eventName, callback);
368
+ return events.subscribe(`request.${eventName}`, callback);
299
369
  }
300
370
  /**
301
371
  * Make a log message
@@ -403,7 +473,10 @@ var Request = class Request {
403
473
  this.trigger("executingMiddleware", middlewares, this.route);
404
474
  for (const middleware of middlewares) {
405
475
  this.log("Executing middleware " + colors.yellowBright(middleware.name));
406
- const output = await middleware(this, this.response);
476
+ const output = await middleware({
477
+ request: this,
478
+ response: this.response
479
+ });
407
480
  this.log("Executed middleware " + colors.yellowBright(middleware.name), "success");
408
481
  if (output !== void 0) {
409
482
  this.log(colors.yellow("request intercepted by middleware ") + colors.cyanBright(middleware.name), "warn");