@c9up/ream 0.1.25 → 0.1.27

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 (302) hide show
  1. package/README.md +65 -0
  2. package/dist/ConfigLoader.d.ts +46 -5
  3. package/dist/ConfigLoader.d.ts.map +1 -1
  4. package/dist/ConfigLoader.js +60 -9
  5. package/dist/ConfigLoader.js.map +1 -1
  6. package/dist/HttpKernel.d.ts.map +1 -1
  7. package/dist/HttpKernel.js +46 -6
  8. package/dist/HttpKernel.js.map +1 -1
  9. package/dist/Ignitor.d.ts +115 -7
  10. package/dist/Ignitor.d.ts.map +1 -1
  11. package/dist/Ignitor.js +254 -40
  12. package/dist/Ignitor.js.map +1 -1
  13. package/dist/console/BaseCommand.d.ts +217 -0
  14. package/dist/console/BaseCommand.d.ts.map +1 -0
  15. package/dist/console/BaseCommand.js +340 -0
  16. package/dist/console/BaseCommand.js.map +1 -0
  17. package/dist/console/Console.d.ts +86 -0
  18. package/dist/console/Console.d.ts.map +1 -0
  19. package/dist/console/Console.js +134 -0
  20. package/dist/console/Console.js.map +1 -0
  21. package/dist/console/ExceptionHandler.d.ts +28 -0
  22. package/dist/console/ExceptionHandler.d.ts.map +1 -0
  23. package/dist/console/ExceptionHandler.js +76 -0
  24. package/dist/console/ExceptionHandler.js.map +1 -0
  25. package/dist/console/HelpCommand.d.ts +16 -0
  26. package/dist/console/HelpCommand.d.ts.map +1 -0
  27. package/dist/console/HelpCommand.js +40 -0
  28. package/dist/console/HelpCommand.js.map +1 -0
  29. package/dist/console/IndexGenerator.d.ts +24 -0
  30. package/dist/console/IndexGenerator.d.ts.map +1 -0
  31. package/dist/console/IndexGenerator.js +65 -0
  32. package/dist/console/IndexGenerator.js.map +1 -0
  33. package/dist/console/Kernel.d.ts +298 -0
  34. package/dist/console/Kernel.d.ts.map +1 -0
  35. package/dist/console/Kernel.js +1120 -0
  36. package/dist/console/Kernel.js.map +1 -0
  37. package/dist/console/ListCommand.d.ts +18 -0
  38. package/dist/console/ListCommand.d.ts.map +1 -0
  39. package/dist/console/ListCommand.js +60 -0
  40. package/dist/console/ListCommand.js.map +1 -0
  41. package/dist/console/assertions.d.ts +20 -0
  42. package/dist/console/assertions.d.ts.map +1 -0
  43. package/dist/console/assertions.js +84 -0
  44. package/dist/console/assertions.js.map +1 -0
  45. package/dist/console/cliui.d.ts +248 -0
  46. package/dist/console/cliui.d.ts.map +1 -0
  47. package/dist/console/cliui.js +587 -0
  48. package/dist/console/cliui.js.map +1 -0
  49. package/dist/console/decorators.d.ts +90 -0
  50. package/dist/console/decorators.d.ts.map +1 -0
  51. package/dist/console/decorators.js +142 -0
  52. package/dist/console/decorators.js.map +1 -0
  53. package/dist/console/index.d.ts +32 -0
  54. package/dist/console/index.d.ts.map +1 -0
  55. package/dist/console/index.js +24 -0
  56. package/dist/console/index.js.map +1 -0
  57. package/dist/console/loaders.d.ts +52 -0
  58. package/dist/console/loaders.d.ts.map +1 -0
  59. package/dist/console/loaders.js +131 -0
  60. package/dist/console/loaders.js.map +1 -0
  61. package/dist/console/parser.d.ts +86 -0
  62. package/dist/console/parser.d.ts.map +1 -0
  63. package/dist/console/parser.js +440 -0
  64. package/dist/console/parser.js.map +1 -0
  65. package/dist/console/prompts.d.ts +124 -0
  66. package/dist/console/prompts.d.ts.map +1 -0
  67. package/dist/console/prompts.js +356 -0
  68. package/dist/console/prompts.js.map +1 -0
  69. package/dist/console/tracing.d.ts +17 -0
  70. package/dist/console/tracing.d.ts.map +1 -0
  71. package/dist/console/tracing.js +11 -0
  72. package/dist/console/tracing.js.map +1 -0
  73. package/dist/console/types.d.ts +255 -0
  74. package/dist/console/types.d.ts.map +1 -0
  75. package/dist/console/types.js +25 -0
  76. package/dist/console/types.js.map +1 -0
  77. package/dist/console/ui.d.ts +20 -0
  78. package/dist/console/ui.d.ts.map +1 -0
  79. package/dist/console/ui.js +31 -0
  80. package/dist/console/ui.js.map +1 -0
  81. package/dist/console/utils.d.ts +27 -0
  82. package/dist/console/utils.d.ts.map +1 -0
  83. package/dist/console/utils.js +56 -0
  84. package/dist/console/utils.js.map +1 -0
  85. package/dist/container/Container.d.ts +23 -3
  86. package/dist/container/Container.d.ts.map +1 -1
  87. package/dist/container/Container.js +177 -70
  88. package/dist/container/Container.js.map +1 -1
  89. package/dist/container/types.d.ts +14 -2
  90. package/dist/container/types.d.ts.map +1 -1
  91. package/dist/decorators/Service.d.ts +7 -0
  92. package/dist/decorators/Service.d.ts.map +1 -1
  93. package/dist/decorators/Service.js +23 -3
  94. package/dist/decorators/Service.js.map +1 -1
  95. package/dist/env/Env.d.ts +29 -4
  96. package/dist/env/Env.d.ts.map +1 -1
  97. package/dist/env/Env.js +27 -4
  98. package/dist/env/Env.js.map +1 -1
  99. package/dist/env/Secret.d.ts +11 -0
  100. package/dist/env/Secret.d.ts.map +1 -0
  101. package/dist/env/Secret.js +36 -0
  102. package/dist/env/Secret.js.map +1 -0
  103. package/dist/env/interpolate.d.ts +26 -0
  104. package/dist/env/interpolate.d.ts.map +1 -0
  105. package/dist/env/interpolate.js +48 -0
  106. package/dist/env/interpolate.js.map +1 -0
  107. package/dist/env/loadEnvFiles.d.ts.map +1 -1
  108. package/dist/env/loadEnvFiles.js +14 -4
  109. package/dist/env/loadEnvFiles.js.map +1 -1
  110. package/dist/env/schema.d.ts +23 -6
  111. package/dist/env/schema.d.ts.map +1 -1
  112. package/dist/env/schema.js +67 -33
  113. package/dist/env/schema.js.map +1 -1
  114. package/dist/errors/ReamError.d.ts +25 -0
  115. package/dist/errors/ReamError.d.ts.map +1 -1
  116. package/dist/errors/ReamError.js +5 -0
  117. package/dist/errors/ReamError.js.map +1 -1
  118. package/dist/errors/prettyPrintError.d.ts +9 -0
  119. package/dist/errors/prettyPrintError.d.ts.map +1 -0
  120. package/dist/errors/prettyPrintError.js +22 -0
  121. package/dist/errors/prettyPrintError.js.map +1 -0
  122. package/dist/events/Emitter.d.ts +1 -1
  123. package/dist/events/Emitter.d.ts.map +1 -1
  124. package/dist/events/Emitter.js +1 -1
  125. package/dist/events/Emitter.js.map +1 -1
  126. package/dist/events/EventsProvider.d.ts +2 -2
  127. package/dist/events/EventsProvider.d.ts.map +1 -1
  128. package/dist/events/EventsProvider.js +3 -3
  129. package/dist/events/EventsProvider.js.map +1 -1
  130. package/dist/graphql/GraphQLEngine.d.ts +1 -1
  131. package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
  132. package/dist/graphql/GraphQLEngine.js +2 -2
  133. package/dist/graphql/GraphQLEngine.js.map +1 -1
  134. package/dist/graphql/GraphQLProvider.d.ts.map +1 -1
  135. package/dist/graphql/GraphQLProvider.js +7 -3
  136. package/dist/graphql/GraphQLProvider.js.map +1 -1
  137. package/dist/http/Exception.d.ts +63 -1
  138. package/dist/http/Exception.d.ts.map +1 -1
  139. package/dist/http/Exception.js +185 -48
  140. package/dist/http/Exception.js.map +1 -1
  141. package/dist/http/HttpContext.d.ts +53 -7
  142. package/dist/http/HttpContext.d.ts.map +1 -1
  143. package/dist/http/HttpContext.js +56 -15
  144. package/dist/http/HttpContext.js.map +1 -1
  145. package/dist/http/RedirectBuilder.d.ts.map +1 -1
  146. package/dist/http/RedirectBuilder.js +4 -1
  147. package/dist/http/RedirectBuilder.js.map +1 -1
  148. package/dist/http/Request.d.ts +141 -10
  149. package/dist/http/Request.d.ts.map +1 -1
  150. package/dist/http/Request.js +244 -34
  151. package/dist/http/Request.js.map +1 -1
  152. package/dist/http/Response.d.ts +176 -9
  153. package/dist/http/Response.d.ts.map +1 -1
  154. package/dist/http/Response.js +404 -16
  155. package/dist/http/Response.js.map +1 -1
  156. package/dist/index.d.ts +19 -8
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +20 -5
  159. package/dist/index.js.map +1 -1
  160. package/dist/middleware/Pipeline.d.ts +29 -8
  161. package/dist/middleware/Pipeline.d.ts.map +1 -1
  162. package/dist/middleware/Pipeline.js +40 -2
  163. package/dist/middleware/Pipeline.js.map +1 -1
  164. package/dist/openapi/OpenApiProvider.js +4 -4
  165. package/dist/openapi/OpenApiProvider.js.map +1 -1
  166. package/dist/router/Router.d.ts +223 -31
  167. package/dist/router/Router.d.ts.map +1 -1
  168. package/dist/router/Router.js +520 -102
  169. package/dist/router/Router.js.map +1 -1
  170. package/dist/rpc/RpcProvider.d.ts +1 -0
  171. package/dist/rpc/RpcProvider.d.ts.map +1 -1
  172. package/dist/rpc/RpcProvider.js +7 -3
  173. package/dist/rpc/RpcProvider.js.map +1 -1
  174. package/dist/rpc/RpcRouter.d.ts +2 -2
  175. package/dist/rpc/RpcRouter.d.ts.map +1 -1
  176. package/dist/rpc/RpcRouter.js +17 -5
  177. package/dist/rpc/RpcRouter.js.map +1 -1
  178. package/dist/scheduler/ScheduleProvider.d.ts.map +1 -1
  179. package/dist/scheduler/ScheduleProvider.js +7 -15
  180. package/dist/scheduler/ScheduleProvider.js.map +1 -1
  181. package/dist/server/Server.d.ts +17 -4
  182. package/dist/server/Server.d.ts.map +1 -1
  183. package/dist/server/Server.js +41 -7
  184. package/dist/server/Server.js.map +1 -1
  185. package/dist/services/app.d.ts +1 -1
  186. package/dist/services/app.js +1 -1
  187. package/dist/services/console.d.ts +21 -0
  188. package/dist/services/console.d.ts.map +1 -0
  189. package/dist/services/console.js +35 -0
  190. package/dist/services/console.js.map +1 -0
  191. package/dist/session/SessionMiddleware.js +3 -3
  192. package/dist/session/SessionMiddleware.js.map +1 -1
  193. package/dist/storage/StaticProvider.js +1 -1
  194. package/dist/storage/StaticProvider.js.map +1 -1
  195. package/dist/testing/ApiResponse.d.ts +218 -0
  196. package/dist/testing/ApiResponse.d.ts.map +1 -0
  197. package/dist/testing/ApiResponse.js +576 -0
  198. package/dist/testing/ApiResponse.js.map +1 -0
  199. package/dist/testing/RequestBuilder.d.ts +155 -35
  200. package/dist/testing/RequestBuilder.d.ts.map +1 -1
  201. package/dist/testing/RequestBuilder.js +455 -109
  202. package/dist/testing/RequestBuilder.js.map +1 -1
  203. package/dist/testing/TestClient.d.ts +53 -37
  204. package/dist/testing/TestClient.d.ts.map +1 -1
  205. package/dist/testing/TestClient.js +84 -52
  206. package/dist/testing/TestClient.js.map +1 -1
  207. package/dist/utils/Macroable.d.ts +30 -0
  208. package/dist/utils/Macroable.d.ts.map +1 -0
  209. package/dist/utils/Macroable.js +43 -0
  210. package/dist/utils/Macroable.js.map +1 -0
  211. package/dist/utils/inflect.d.ts +17 -0
  212. package/dist/utils/inflect.d.ts.map +1 -0
  213. package/dist/utils/inflect.js +32 -0
  214. package/dist/utils/inflect.js.map +1 -0
  215. package/dist/utils/objectPath.d.ts +57 -0
  216. package/dist/utils/objectPath.d.ts.map +1 -0
  217. package/dist/utils/objectPath.js +141 -0
  218. package/dist/utils/objectPath.js.map +1 -0
  219. package/events.darwin-arm64.node +0 -0
  220. package/events.darwin-x64.node +0 -0
  221. package/events.linux-arm64-gnu.node +0 -0
  222. package/events.linux-x64-gnu.node +0 -0
  223. package/events.win32-x64-msvc.node +0 -0
  224. package/index.darwin-arm64.node +0 -0
  225. package/index.darwin-x64.node +0 -0
  226. package/index.linux-arm64-gnu.node +0 -0
  227. package/index.linux-x64-gnu.node +0 -0
  228. package/index.win32-x64-msvc.node +0 -0
  229. package/package.json +20 -2
  230. package/scheduler.darwin-arm64.node +0 -0
  231. package/scheduler.darwin-x64.node +0 -0
  232. package/scheduler.linux-arm64-gnu.node +0 -0
  233. package/scheduler.linux-x64-gnu.node +0 -0
  234. package/scheduler.win32-x64-msvc.node +0 -0
  235. package/src/ConfigLoader.ts +72 -9
  236. package/src/HttpKernel.ts +53 -15
  237. package/src/Ignitor.ts +364 -45
  238. package/src/console/BaseCommand.ts +467 -0
  239. package/src/console/Console.ts +174 -0
  240. package/src/console/ExceptionHandler.ts +91 -0
  241. package/src/console/HelpCommand.ts +37 -0
  242. package/src/console/IndexGenerator.ts +79 -0
  243. package/src/console/Kernel.ts +1382 -0
  244. package/src/console/ListCommand.ts +55 -0
  245. package/src/console/assertions.ts +114 -0
  246. package/src/console/cliui.ts +756 -0
  247. package/src/console/decorators.ts +199 -0
  248. package/src/console/index.ts +67 -0
  249. package/src/console/loaders.ts +145 -0
  250. package/src/console/parser.ts +598 -0
  251. package/src/console/prompts.ts +548 -0
  252. package/src/console/tracing.ts +22 -0
  253. package/src/console/types.ts +280 -0
  254. package/src/console/ui.ts +37 -0
  255. package/src/console/utils.ts +69 -0
  256. package/src/container/Container.ts +198 -72
  257. package/src/container/types.ts +15 -2
  258. package/src/decorators/Service.ts +28 -3
  259. package/src/env/Env.ts +49 -5
  260. package/src/env/Secret.ts +41 -0
  261. package/src/env/interpolate.ts +54 -0
  262. package/src/env/loadEnvFiles.ts +12 -4
  263. package/src/env/schema.ts +109 -35
  264. package/src/errors/ReamError.ts +31 -0
  265. package/src/errors/prettyPrintError.ts +20 -0
  266. package/src/events/Emitter.ts +2 -2
  267. package/src/events/EventsProvider.ts +5 -5
  268. package/src/graphql/GraphQLEngine.ts +4 -4
  269. package/src/graphql/GraphQLProvider.ts +7 -3
  270. package/src/http/Exception.ts +214 -37
  271. package/src/http/HttpContext.ts +87 -18
  272. package/src/http/RedirectBuilder.ts +4 -1
  273. package/src/http/Request.ts +264 -34
  274. package/src/http/Response.ts +478 -27
  275. package/src/index.ts +41 -6
  276. package/src/middleware/Pipeline.ts +77 -6
  277. package/src/openapi/OpenApiProvider.ts +4 -4
  278. package/src/router/Router.ts +631 -113
  279. package/src/rpc/RpcProvider.ts +6 -2
  280. package/src/rpc/RpcRouter.ts +22 -7
  281. package/src/scheduler/ScheduleProvider.ts +7 -15
  282. package/src/server/Server.ts +49 -10
  283. package/src/services/app.ts +1 -1
  284. package/src/services/console.ts +42 -0
  285. package/src/session/SessionMiddleware.ts +4 -4
  286. package/src/storage/StaticProvider.ts +1 -1
  287. package/src/testing/ApiResponse.ts +691 -0
  288. package/src/testing/RequestBuilder.ts +577 -137
  289. package/src/testing/TestClient.ts +110 -77
  290. package/src/utils/Macroable.ts +54 -0
  291. package/src/utils/inflect.ts +29 -0
  292. package/src/utils/objectPath.ts +142 -0
  293. package/dist/console/CommandRunner.d.ts +0 -18
  294. package/dist/console/CommandRunner.d.ts.map +0 -1
  295. package/dist/console/CommandRunner.js +0 -65
  296. package/dist/console/CommandRunner.js.map +0 -1
  297. package/dist/decorators/Lazy.d.ts +0 -19
  298. package/dist/decorators/Lazy.d.ts.map +0 -1
  299. package/dist/decorators/Lazy.js +0 -53
  300. package/dist/decorators/Lazy.js.map +0 -1
  301. package/src/console/CommandRunner.ts +0 -82
  302. package/src/decorators/Lazy.ts +0 -57
@@ -9,7 +9,10 @@
9
9
  * response.redirect().toRoute('posts.show', { id: '42' })
10
10
  */
11
11
  function isSameOriginOrRelative(referer, requestUrl) {
12
- if (referer.startsWith('/') && !referer.startsWith('//'))
12
+ // A relative path is trusted only when it starts with a single "/" and has no
13
+ // backslash: browsers normalise "\" to "/", so "/\evil.com" would become the
14
+ // protocol-relative "//evil.com" that a lone `!startsWith("//")` check misses.
15
+ if (referer.startsWith('/') && !referer.startsWith('//') && !referer.includes('\\'))
13
16
  return true;
14
17
  if (!requestUrl)
15
18
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"RedirectBuilder.js","sourceRoot":"","sources":["../../src/http/RedirectBuilder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RedirectBuilder.js","sourceRoot":"","sources":["../../src/http/RedirectBuilder.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,10 @@
6
6
  *
7
7
  * @implements FR21
8
8
  */
9
+ import type { CookieSigner } from '../security/CookieSigner.js';
10
+ import type { SignedUrl } from '../security/SignedUrl.js';
9
11
  import type { Dict } from '../types/helpers.js';
12
+ import { Macroable } from '../utils/Macroable.js';
10
13
  export interface RawRequest {
11
14
  method: string;
12
15
  path: string;
@@ -23,6 +26,12 @@ export interface RawRequest {
23
26
  * `ip()` accessor falls back to legacy header parsing.
24
27
  */
25
28
  ip?: string;
29
+ /**
30
+ * Connection scheme as seen by the server (`http`/`https`), when the Rust
31
+ * layer ships it. Defaults to `http` in `protocol()` when absent; the
32
+ * `X-Forwarded-Proto` header only overrides it when trust-proxy is enabled.
33
+ */
34
+ scheme?: 'http' | 'https';
26
35
  /**
27
36
  * Pre-parsed `multipart/form-data` payload — the HyperServer parses bodies
28
37
  * server-side via `multer` and ships fields/files in this typed shape.
@@ -48,7 +57,7 @@ export interface RawRequest {
48
57
  */
49
58
  cookies?: Dict;
50
59
  }
51
- export declare class Request {
60
+ export declare class Request extends Macroable {
52
61
  #private;
53
62
  /**
54
63
  * CSRF token for this request (AdonisJS idiom: `request.csrfToken`). Seeded
@@ -56,9 +65,51 @@ export declare class Request {
56
65
  * otherwise. Also published to `ctx.store` for templating helpers.
57
66
  */
58
67
  csrfToken?: string;
68
+ /**
69
+ * `true` only when CSRF was enabled, the request method guarded, the route not
70
+ * excepted, AND the token validated for this request — set by the
71
+ * `@c9up/blackhole` middleware. Unlike {@link csrfToken} (seeded on every
72
+ * passing request, even when verification was skipped), this is the trustworthy
73
+ * "the request was CSRF-verified" signal a consumer reads to fail-close on
74
+ * state-changing routes. `undefined` when the middleware never ran.
75
+ */
76
+ csrfProtected?: boolean;
59
77
  constructor(raw: RawRequest, params?: Dict);
60
- /** HTTP method (GET, POST, etc.). */
78
+ /**
79
+ * The HTTP method, honouring `_method` form spoofing when enabled (AdonisJS
80
+ * `method`). With spoofing enabled and a real POST, the `_method` field
81
+ * (`PUT`/`PATCH`/`DELETE`) overrides — the classic HTML-form workaround.
82
+ * Spoofing is OFF by default (opt in via {@link setMethodSpoofing}); routing
83
+ * always uses {@link intended}.
84
+ */
61
85
  method(): string;
86
+ /** The real HTTP method, ignoring any `_method` spoofing (AdonisJS `intended`). */
87
+ intended(): string;
88
+ /** @internal Give the request access to its response — wired by HttpContext (for `fresh()`). */
89
+ setResponse(response: {
90
+ fresh(): boolean;
91
+ }): void;
92
+ /** @internal Record the matched route — wired by HttpContext (for `matchesRoute()`). */
93
+ setRouteInfo(info: {
94
+ name?: string;
95
+ pattern: string;
96
+ }): void;
97
+ /**
98
+ * Whether the client's cached copy is still fresh (AdonisJS `fresh`) —
99
+ * delegates to the response's `ETag`/`If-None-Match` revalidation check, so a
100
+ * handler can answer `304 Not Modified`. False before the response is wired.
101
+ */
102
+ fresh(): boolean;
103
+ /** The negation of {@link fresh} (AdonisJS `stale`). */
104
+ stale(): boolean;
105
+ /** True when the matched route's name or pattern equals `identifier` (AdonisJS `matchesRoute`). */
106
+ matchesRoute(identifier: string): boolean;
107
+ /**
108
+ * Enable/disable `_method` form spoofing (AdonisJS gates this behind the
109
+ * `allowMethodSpoofing` config; ream exposes it as an explicit opt-in, off by
110
+ * default, so an attacker can never silently rewrite a POST into a DELETE).
111
+ */
112
+ setMethodSpoofing(enabled: boolean): void;
62
113
  /** Request URL (path + query string). */
63
114
  url(includeQs?: boolean): string;
64
115
  /** Request path (without query string). */
@@ -80,6 +131,41 @@ export declare class Request {
80
131
  * desired resolved value.
81
132
  */
82
133
  ip(): string;
134
+ /**
135
+ * Enable/disable trusting proxy headers (`X-Forwarded-Proto`/`-Host`/`-For`)
136
+ * for `protocol()`/`host()`/`ips()`. OFF by default — turning it on when the
137
+ * app is NOT behind a trusted proxy lets clients spoof their scheme/host/IP,
138
+ * so it's an explicit opt-in (same stance as {@link setMethodSpoofing}).
139
+ */
140
+ setTrustProxy(enabled: boolean): void;
141
+ /**
142
+ * The request host including port (AdonisJS `host`). Honours
143
+ * `X-Forwarded-Host` ONLY when trust-proxy is enabled; otherwise the `Host`
144
+ * header. Returns null when neither is present.
145
+ */
146
+ host(): string | null;
147
+ /**
148
+ * The request protocol — `http` or `https` (AdonisJS `protocol`). Honours
149
+ * `X-Forwarded-Proto` only under trust-proxy; otherwise the connection scheme
150
+ * the Rust layer reported (defaulting to `http`).
151
+ */
152
+ protocol(): string;
153
+ /** True when the request protocol is `https` (AdonisJS `secure`). */
154
+ secure(): boolean;
155
+ /**
156
+ * The client IP chain (AdonisJS `ips`). Under trust-proxy, the parsed
157
+ * `X-Forwarded-For` list (left-most = original client); otherwise just the
158
+ * single resolved {@link ip}.
159
+ */
160
+ ips(): string[];
161
+ /** The request hostname without port (AdonisJS `hostname`), or null. */
162
+ hostname(): string | null;
163
+ /**
164
+ * Subdomains of the hostname (AdonisJS `subdomains`). `offset` drops the
165
+ * registrable domain (default 2 → `example.com`); a leading `www` is removed.
166
+ * Empty for an IP host or a host with no subdomain.
167
+ */
168
+ subdomains(offset?: number): string[];
83
169
  /**
84
170
  * Return all cookies sent on this request as a name → value map. The
85
171
  * HyperServer parses the `Cookie:` header once via the `cookie` crate
@@ -88,14 +174,37 @@ export declare class Request {
88
174
  * header — same tolerant `;`-split with quoted-value passthrough.
89
175
  */
90
176
  cookies(): Dict;
91
- /** Pre-parsed cookie value by name, or `null` when absent. */
92
- cookie(name: string): string | null;
177
+ /** Inject the APP_KEY-backed cookie signer — wired by HttpContext. */
178
+ setCookieSigner(signer: CookieSigner): void;
179
+ /**
180
+ * Signed cookie value, verified with APP_KEY (AdonisJS default). Returns
181
+ * `defaultValue` (or null) when absent OR when the signature is invalid
182
+ * (tampered / not signed).
183
+ */
184
+ cookie(name: string, defaultValue?: string): string | null;
185
+ /** Raw (unsigned) cookie value (AdonisJS `plainCookie`), or `defaultValue`/null when absent. */
186
+ plainCookie(name: string, defaultValue?: string): string | null;
187
+ /**
188
+ * Encrypted cookie value, decrypted with APP_KEY (AdonisJS `encryptedCookie`).
189
+ * Returns `defaultValue` (or null) when absent, undecryptable, or no
190
+ * encryption service.
191
+ */
192
+ encryptedCookie(name: string, defaultValue?: string): string | null;
193
+ /** @internal Inject the APP_KEY-backed signed-URL helper — wired by HttpContext. */
194
+ setSignedUrl(signedUrl: SignedUrl): void;
195
+ /**
196
+ * Verify the request's signed-URL `signature` (AdonisJS `hasValidSignature`).
197
+ * Delegates to the {@link SignedUrl} helper, which recomputes the HMAC over
198
+ * the current path + query, rejects an expired `expires`, and checks the
199
+ * `purpose`. Returns false without an APP_KEY-backed signer.
200
+ */
201
+ hasValidSignature(purpose?: string): boolean;
93
202
  /** Get the raw body as a string (decoded from base64 if binary). */
94
203
  raw(): string;
95
204
  /** Get the raw body as a Buffer (preserves binary integrity for file uploads). */
96
205
  rawBuffer(): Buffer;
97
- /** Get a single request header (case-insensitive). */
98
- header(key: string): string | undefined;
206
+ /** Get a single request header (case-insensitive), or `defaultValue` when absent. */
207
+ header(key: string, defaultValue?: string): string | undefined;
99
208
  /** Get all request headers. */
100
209
  headers(): Readonly<Dict>;
101
210
  /** Get a single route parameter. */
@@ -106,14 +215,36 @@ export declare class Request {
106
215
  qs(): Dict<unknown>;
107
216
  /** Get the parsed request body. */
108
217
  body(): unknown;
109
- /** Get a single input value from body or query string. */
218
+ /**
219
+ * Get a single input value from body or query string, by AdonisJS
220
+ * dot-notation (`input('user.address.city')`). Returns `defaultValue` when
221
+ * the path is absent (parity with `lodash.get`, reimplemented dependency-free).
222
+ */
110
223
  input<T = unknown>(key: string, defaultValue?: T): T;
111
224
  /** Get all input (query string merged with body). */
112
225
  all(): Dict<unknown>;
113
- /** Cherry-pick specific keys from input. */
114
- only<K extends string>(keys: K[]): Partial<Record<K, unknown>>;
115
- /** Get all input except specific keys. */
226
+ /**
227
+ * The original request input, captured once and never mutated (AdonisJS
228
+ * `request.original`) — the basis for flash "old input" on validation errors.
229
+ */
230
+ original(): Dict<unknown>;
231
+ /**
232
+ * Cherry-pick specific keys from input, honouring dot-notation for nested
233
+ * branches (`only(['user.id'])` → `{ user: { id } }`) — AdonisJS `only`
234
+ * (`lodash.pick`). Absent paths are skipped.
235
+ */
236
+ only(keys: string[]): Dict<unknown>;
237
+ /**
238
+ * Get all input except specific keys, honouring dot-notation for nested
239
+ * branches — AdonisJS `except` (`lodash.omit`). Never mutates the input.
240
+ */
116
241
  except(keys: string[]): Dict<unknown>;
242
+ /**
243
+ * True when the request carries a body — a `content-length` above zero or a
244
+ * `transfer-encoding` header (AdonisJS `request.hasBody`). Lets a handler
245
+ * branch on "was anything sent" without parsing.
246
+ */
247
+ hasBody(): boolean;
117
248
  /** Check if the request content-type matches any of the given types. */
118
249
  is(types: string[]): string | null;
119
250
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../../src/http/Request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../../src/http/Request.ts"],"names":[],"mappings":"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"}
@@ -6,12 +6,21 @@
6
6
  *
7
7
  * @implements FR21
8
8
  */
9
- export class Request {
9
+ import { Macroable } from '../utils/Macroable.js';
10
+ import { getPath, omitPaths, pickPaths } from '../utils/objectPath.js';
11
+ export class Request extends Macroable {
10
12
  #raw;
11
13
  #params;
14
+ #cookieSigner;
15
+ #signedUrl;
16
+ #allowMethodSpoofing = false;
17
+ #trustProxy = false;
18
+ #routeInfo;
19
+ #response;
12
20
  #parsedBody;
13
21
  #parsedQs;
14
22
  #merged;
23
+ #original;
15
24
  #files = new Map();
16
25
  #validated;
17
26
  /**
@@ -20,15 +29,74 @@ export class Request {
20
29
  * otherwise. Also published to `ctx.store` for templating helpers.
21
30
  */
22
31
  csrfToken;
32
+ /**
33
+ * `true` only when CSRF was enabled, the request method guarded, the route not
34
+ * excepted, AND the token validated for this request — set by the
35
+ * `@c9up/blackhole` middleware. Unlike {@link csrfToken} (seeded on every
36
+ * passing request, even when verification was skipped), this is the trustworthy
37
+ * "the request was CSRF-verified" signal a consumer reads to fail-close on
38
+ * state-changing routes. `undefined` when the middleware never ran.
39
+ */
40
+ csrfProtected;
23
41
  constructor(raw, params = {}) {
42
+ super();
24
43
  this.#raw = raw;
25
44
  this.#params = params;
26
45
  }
27
46
  // ─── HTTP accessors ───────────────────────────────────────
28
- /** HTTP method (GET, POST, etc.). */
47
+ /**
48
+ * The HTTP method, honouring `_method` form spoofing when enabled (AdonisJS
49
+ * `method`). With spoofing enabled and a real POST, the `_method` field
50
+ * (`PUT`/`PATCH`/`DELETE`) overrides — the classic HTML-form workaround.
51
+ * Spoofing is OFF by default (opt in via {@link setMethodSpoofing}); routing
52
+ * always uses {@link intended}.
53
+ */
29
54
  method() {
55
+ if (this.#allowMethodSpoofing && this.intended().toUpperCase() === 'POST') {
56
+ const spoofed = this.input('_method', this.intended());
57
+ if (typeof spoofed === 'string' && spoofed)
58
+ return spoofed.toUpperCase();
59
+ }
60
+ return this.intended();
61
+ }
62
+ /** The real HTTP method, ignoring any `_method` spoofing (AdonisJS `intended`). */
63
+ intended() {
30
64
  return this.#raw.method;
31
65
  }
66
+ /** @internal Give the request access to its response — wired by HttpContext (for `fresh()`). */
67
+ setResponse(response) {
68
+ this.#response = response;
69
+ }
70
+ /** @internal Record the matched route — wired by HttpContext (for `matchesRoute()`). */
71
+ setRouteInfo(info) {
72
+ this.#routeInfo = info;
73
+ }
74
+ /**
75
+ * Whether the client's cached copy is still fresh (AdonisJS `fresh`) —
76
+ * delegates to the response's `ETag`/`If-None-Match` revalidation check, so a
77
+ * handler can answer `304 Not Modified`. False before the response is wired.
78
+ */
79
+ fresh() {
80
+ return this.#response?.fresh() ?? false;
81
+ }
82
+ /** The negation of {@link fresh} (AdonisJS `stale`). */
83
+ stale() {
84
+ return !this.fresh();
85
+ }
86
+ /** True when the matched route's name or pattern equals `identifier` (AdonisJS `matchesRoute`). */
87
+ matchesRoute(identifier) {
88
+ if (!this.#routeInfo)
89
+ return false;
90
+ return this.#routeInfo.name === identifier || this.#routeInfo.pattern === identifier;
91
+ }
92
+ /**
93
+ * Enable/disable `_method` form spoofing (AdonisJS gates this behind the
94
+ * `allowMethodSpoofing` config; ream exposes it as an explicit opt-in, off by
95
+ * default, so an attacker can never silently rewrite a POST into a DELETE).
96
+ */
97
+ setMethodSpoofing(enabled) {
98
+ this.#allowMethodSpoofing = enabled;
99
+ }
32
100
  /** Request URL (path + query string). */
33
101
  url(includeQs = true) {
34
102
  if (includeQs && this.#raw.query) {
@@ -61,6 +129,87 @@ export class Request {
61
129
  return this.#raw.ip;
62
130
  return this.#raw.remoteAddr ?? '127.0.0.1';
63
131
  }
132
+ /**
133
+ * Enable/disable trusting proxy headers (`X-Forwarded-Proto`/`-Host`/`-For`)
134
+ * for `protocol()`/`host()`/`ips()`. OFF by default — turning it on when the
135
+ * app is NOT behind a trusted proxy lets clients spoof their scheme/host/IP,
136
+ * so it's an explicit opt-in (same stance as {@link setMethodSpoofing}).
137
+ */
138
+ setTrustProxy(enabled) {
139
+ this.#trustProxy = enabled;
140
+ }
141
+ /**
142
+ * The request host including port (AdonisJS `host`). Honours
143
+ * `X-Forwarded-Host` ONLY when trust-proxy is enabled; otherwise the `Host`
144
+ * header. Returns null when neither is present.
145
+ */
146
+ host() {
147
+ if (this.#trustProxy) {
148
+ const forwarded = this.#raw.headers['x-forwarded-host'];
149
+ if (forwarded)
150
+ return forwarded.split(',')[0].trim();
151
+ }
152
+ return this.#raw.headers.host ?? null;
153
+ }
154
+ /**
155
+ * The request protocol — `http` or `https` (AdonisJS `protocol`). Honours
156
+ * `X-Forwarded-Proto` only under trust-proxy; otherwise the connection scheme
157
+ * the Rust layer reported (defaulting to `http`).
158
+ */
159
+ protocol() {
160
+ if (this.#trustProxy) {
161
+ const forwarded = this.#raw.headers['x-forwarded-proto'];
162
+ if (forwarded)
163
+ return forwarded.split(',')[0].trim().toLowerCase();
164
+ }
165
+ return this.#raw.scheme ?? 'http';
166
+ }
167
+ /** True when the request protocol is `https` (AdonisJS `secure`). */
168
+ secure() {
169
+ return this.protocol() === 'https';
170
+ }
171
+ /**
172
+ * The client IP chain (AdonisJS `ips`). Under trust-proxy, the parsed
173
+ * `X-Forwarded-For` list (left-most = original client); otherwise just the
174
+ * single resolved {@link ip}.
175
+ */
176
+ ips() {
177
+ if (this.#trustProxy) {
178
+ const forwarded = this.#raw.headers['x-forwarded-for'];
179
+ if (forwarded) {
180
+ return forwarded
181
+ .split(',')
182
+ .map((value) => value.trim())
183
+ .filter((value) => value.length > 0);
184
+ }
185
+ }
186
+ return [this.ip()];
187
+ }
188
+ /** The request hostname without port (AdonisJS `hostname`), or null. */
189
+ hostname() {
190
+ const host = this.host();
191
+ if (host === null)
192
+ return null;
193
+ // Strip the port. IPv6 literals are bracketed (`[::1]:3000`) — keep the brackets' contents.
194
+ if (host.startsWith('['))
195
+ return host.slice(0, host.indexOf(']') + 1) || host;
196
+ const colon = host.indexOf(':');
197
+ return colon === -1 ? host : host.slice(0, colon);
198
+ }
199
+ /**
200
+ * Subdomains of the hostname (AdonisJS `subdomains`). `offset` drops the
201
+ * registrable domain (default 2 → `example.com`); a leading `www` is removed.
202
+ * Empty for an IP host or a host with no subdomain.
203
+ */
204
+ subdomains(offset = 2) {
205
+ const hostname = this.hostname();
206
+ if (hostname === null || isIpLiteral(hostname))
207
+ return [];
208
+ const parts = hostname.split('.').reverse().slice(offset);
209
+ if (parts.length > 0 && parts[parts.length - 1] === 'www')
210
+ parts.pop();
211
+ return parts;
212
+ }
64
213
  /**
65
214
  * Return all cookies sent on this request as a name → value map. The
66
215
  * HyperServer parses the `Cookie:` header once via the `cookie` crate
@@ -93,10 +242,49 @@ export class Request {
93
242
  }
94
243
  return result;
95
244
  }
96
- /** Pre-parsed cookie value by name, or `null` when absent. */
97
- cookie(name) {
245
+ /** Inject the APP_KEY-backed cookie signer — wired by HttpContext. */
246
+ setCookieSigner(signer) {
247
+ this.#cookieSigner = signer;
248
+ }
249
+ /**
250
+ * Signed cookie value, verified with APP_KEY (AdonisJS default). Returns
251
+ * `defaultValue` (or null) when absent OR when the signature is invalid
252
+ * (tampered / not signed).
253
+ */
254
+ cookie(name, defaultValue) {
255
+ const raw = this.plainCookie(name);
256
+ const value = raw === null ? null : this.#cookieSigner ? this.#cookieSigner.unsign(raw) : raw;
257
+ return value ?? defaultValue ?? null;
258
+ }
259
+ /** Raw (unsigned) cookie value (AdonisJS `plainCookie`), or `defaultValue`/null when absent. */
260
+ plainCookie(name, defaultValue) {
98
261
  const cookies = this.#raw.cookies ?? this.cookies();
99
- return cookies[name] ?? null;
262
+ return cookies[name] ?? defaultValue ?? null;
263
+ }
264
+ /**
265
+ * Encrypted cookie value, decrypted with APP_KEY (AdonisJS `encryptedCookie`).
266
+ * Returns `defaultValue` (or null) when absent, undecryptable, or no
267
+ * encryption service.
268
+ */
269
+ encryptedCookie(name, defaultValue) {
270
+ const raw = this.plainCookie(name);
271
+ const value = raw === null || !this.#cookieSigner ? null : this.#cookieSigner.decrypt(raw);
272
+ return value ?? defaultValue ?? null;
273
+ }
274
+ /** @internal Inject the APP_KEY-backed signed-URL helper — wired by HttpContext. */
275
+ setSignedUrl(signedUrl) {
276
+ this.#signedUrl = signedUrl;
277
+ }
278
+ /**
279
+ * Verify the request's signed-URL `signature` (AdonisJS `hasValidSignature`).
280
+ * Delegates to the {@link SignedUrl} helper, which recomputes the HMAC over
281
+ * the current path + query, rejects an expired `expires`, and checks the
282
+ * `purpose`. Returns false without an APP_KEY-backed signer.
283
+ */
284
+ hasValidSignature(purpose) {
285
+ if (!this.#signedUrl)
286
+ return false;
287
+ return this.#signedUrl.verify(this.url(), purpose);
100
288
  }
101
289
  /** Get the raw body as a string (decoded from base64 if binary). */
102
290
  raw() {
@@ -113,9 +301,9 @@ export class Request {
113
301
  return Buffer.from(this.#raw.body, 'utf8');
114
302
  }
115
303
  // ─── Headers ──────────────────────────────────────────────
116
- /** Get a single request header (case-insensitive). */
117
- header(key) {
118
- return this.#raw.headers[key.toLowerCase()];
304
+ /** Get a single request header (case-insensitive), or `defaultValue` when absent. */
305
+ header(key, defaultValue) {
306
+ return this.#raw.headers[key.toLowerCase()] ?? defaultValue;
119
307
  }
120
308
  /** Get all request headers. */
121
309
  headers() {
@@ -145,45 +333,61 @@ export class Request {
145
333
  return this.#parsedBody;
146
334
  }
147
335
  // ─── Merged input (body + qs) ─────────────────────────────
148
- /** Get a single input value from body or query string. */
336
+ /**
337
+ * Get a single input value from body or query string, by AdonisJS
338
+ * dot-notation (`input('user.address.city')`). Returns `defaultValue` when
339
+ * the path is absent (parity with `lodash.get`, reimplemented dependency-free).
340
+ */
149
341
  input(key, defaultValue) {
150
- const merged = this.all();
151
- if (key in merged) {
152
- // biome-ignore lint/suspicious/noExplicitAny: generic accessor — caller brands the value type via T
153
- return merged[key];
154
- }
155
- // biome-ignore lint/suspicious/noExplicitAny: generic default — caller brands the value type via T
156
- return defaultValue;
342
+ // Untyped request data: the caller declares the shape it expects (same
343
+ // contract as AdonisJS `request.input<T>`, whose return is loose `any`).
344
+ return getPath(this.all(), key, defaultValue);
157
345
  }
158
346
  /** Get all input (query string merged with body). */
159
347
  all() {
160
348
  if (!this.#merged) {
161
349
  this.#ensureParsedBody();
162
350
  this.#merged = { ...this.qs(), ...this.#parsedBody };
351
+ // Snapshot the first-seen input as the immutable "original" (flash old-input).
352
+ if (this.#original === undefined)
353
+ this.#original = { ...this.#merged };
163
354
  }
164
355
  return { ...this.#merged };
165
356
  }
166
- /** Cherry-pick specific keys from input. */
357
+ /**
358
+ * The original request input, captured once and never mutated (AdonisJS
359
+ * `request.original`) — the basis for flash "old input" on validation errors.
360
+ */
361
+ original() {
362
+ this.all(); // ensure the snapshot is captured
363
+ return { ...(this.#original ?? {}) };
364
+ }
365
+ /**
366
+ * Cherry-pick specific keys from input, honouring dot-notation for nested
367
+ * branches (`only(['user.id'])` → `{ user: { id } }`) — AdonisJS `only`
368
+ * (`lodash.pick`). Absent paths are skipped.
369
+ */
167
370
  only(keys) {
168
- const merged = this.all();
169
- const result = {};
170
- for (const key of keys) {
171
- if (key in merged) {
172
- result[key] = merged[key];
173
- }
174
- }
175
- return result;
371
+ return pickPaths(this.all(), keys);
176
372
  }
177
- /** Get all input except specific keys. */
373
+ /**
374
+ * Get all input except specific keys, honouring dot-notation for nested
375
+ * branches — AdonisJS `except` (`lodash.omit`). Never mutates the input.
376
+ */
178
377
  except(keys) {
179
- const merged = this.all();
180
- const keySet = new Set(keys);
181
- const result = {};
182
- for (const [k, v] of Object.entries(merged)) {
183
- if (!keySet.has(k))
184
- result[k] = v;
185
- }
186
- return result;
378
+ return omitPaths(this.all(), keys);
379
+ }
380
+ /**
381
+ * True when the request carries a body — a `content-length` above zero or a
382
+ * `transfer-encoding` header (AdonisJS `request.hasBody`). Lets a handler
383
+ * branch on "was anything sent" without parsing.
384
+ */
385
+ hasBody() {
386
+ const transferEncoding = this.#raw.headers['transfer-encoding'];
387
+ if (transferEncoding && transferEncoding.length > 0)
388
+ return true;
389
+ const contentLength = Number.parseInt(this.#raw.headers['content-length'] ?? '', 10);
390
+ return Number.isFinite(contentLength) && contentLength > 0;
187
391
  }
188
392
  // ─── Content negotiation ──────────────────────────────────
189
393
  /** Check if the request content-type matches any of the given types. */
@@ -357,6 +561,12 @@ export class Request {
357
561
  function isPlainObject(value) {
358
562
  return typeof value === 'object' && value !== null && !Array.isArray(value);
359
563
  }
564
+ /** True for an IPv4 dotted-quad or a (bracketed) IPv6 literal — hosts with no subdomains. */
565
+ function isIpLiteral(host) {
566
+ if (host.startsWith('[') || host.includes('::'))
567
+ return true;
568
+ return /^(\d{1,3}\.){3}\d{1,3}$/.test(host);
569
+ }
360
570
  /**
361
571
  * Decode a percent-encoded segment without throwing on malformed input.
362
572
  * Browsers happily send `q=%E0%A4%A` (truncated UTF-8 sequences) — refusing