@rshono/core 1.0.0-rc.12 → 1.0.0-rc.13

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 (143) hide show
  1. package/bin/rshono.mjs +3 -4
  2. package/dist/builder/env-shadow-loader.cjs +5 -5
  3. package/dist/builder/page-files.js +5 -5
  4. package/dist/builder/page-files.js.map +1 -1
  5. package/dist/builder/public-env.d.ts +5 -4
  6. package/dist/builder/public-env.d.ts.map +1 -1
  7. package/dist/builder/public-env.js +5 -4
  8. package/dist/builder/public-env.js.map +1 -1
  9. package/dist/builder/rspack-config.d.ts +5 -11
  10. package/dist/builder/rspack-config.d.ts.map +1 -1
  11. package/dist/builder/rspack-config.js +28 -50
  12. package/dist/builder/rspack-config.js.map +1 -1
  13. package/dist/cli/build.js +2 -2
  14. package/dist/cli/build.js.map +1 -1
  15. package/dist/cli/dev.d.ts.map +1 -1
  16. package/dist/cli/dev.js +30 -40
  17. package/dist/cli/dev.js.map +1 -1
  18. package/dist/cli/index.js +4 -4
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/start.d.ts.map +1 -1
  21. package/dist/cli/start.js +2 -3
  22. package/dist/cli/start.js.map +1 -1
  23. package/dist/config.d.ts +28 -31
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +2 -2
  26. package/dist/config.js.map +1 -1
  27. package/dist/deploy/aws-lambda/runtime.d.ts +4 -6
  28. package/dist/deploy/aws-lambda/runtime.d.ts.map +1 -1
  29. package/dist/deploy/aws-lambda/runtime.js +5 -8
  30. package/dist/deploy/aws-lambda/runtime.js.map +1 -1
  31. package/dist/deploy/build-marker.d.ts +3 -5
  32. package/dist/deploy/build-marker.d.ts.map +1 -1
  33. package/dist/deploy/build-marker.js +3 -5
  34. package/dist/deploy/build-marker.js.map +1 -1
  35. package/dist/deploy/cloudflare/build.d.ts.map +1 -1
  36. package/dist/deploy/cloudflare/build.js +6 -10
  37. package/dist/deploy/cloudflare/build.js.map +1 -1
  38. package/dist/deploy/cloudflare/runtime.d.ts +2 -5
  39. package/dist/deploy/cloudflare/runtime.d.ts.map +1 -1
  40. package/dist/deploy/cloudflare/runtime.js +19 -32
  41. package/dist/deploy/cloudflare/runtime.js.map +1 -1
  42. package/dist/deploy/contract.d.ts +25 -42
  43. package/dist/deploy/contract.d.ts.map +1 -1
  44. package/dist/deploy/contract.js.map +1 -1
  45. package/dist/deploy/filesystem.d.ts +3 -5
  46. package/dist/deploy/filesystem.d.ts.map +1 -1
  47. package/dist/deploy/filesystem.js +7 -11
  48. package/dist/deploy/filesystem.js.map +1 -1
  49. package/dist/deploy/node/runtime.d.ts +4 -5
  50. package/dist/deploy/node/runtime.d.ts.map +1 -1
  51. package/dist/deploy/node/runtime.js +9 -15
  52. package/dist/deploy/node/runtime.js.map +1 -1
  53. package/dist/deploy/presets.d.ts +19 -29
  54. package/dist/deploy/presets.d.ts.map +1 -1
  55. package/dist/deploy/presets.js +18 -25
  56. package/dist/deploy/presets.js.map +1 -1
  57. package/dist/deploy/vercel/build.d.ts.map +1 -1
  58. package/dist/deploy/vercel/build.js +9 -12
  59. package/dist/deploy/vercel/build.js.map +1 -1
  60. package/dist/deploy/vercel/runtime.d.ts +4 -7
  61. package/dist/deploy/vercel/runtime.d.ts.map +1 -1
  62. package/dist/deploy/vercel/runtime.js +4 -7
  63. package/dist/deploy/vercel/runtime.js.map +1 -1
  64. package/dist/index.d.ts +13 -9
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +15 -12
  67. package/dist/index.js.map +1 -1
  68. package/dist/router.d.ts +65 -93
  69. package/dist/router.d.ts.map +1 -1
  70. package/dist/router.js +2 -5
  71. package/dist/router.js.map +1 -1
  72. package/dist/runtime/boundaries.d.ts +24 -30
  73. package/dist/runtime/boundaries.d.ts.map +1 -1
  74. package/dist/runtime/boundaries.js +15 -22
  75. package/dist/runtime/boundaries.js.map +1 -1
  76. package/dist/runtime/client.d.ts +16 -7
  77. package/dist/runtime/client.d.ts.map +1 -1
  78. package/dist/runtime/client.js +16 -7
  79. package/dist/runtime/client.js.map +1 -1
  80. package/dist/runtime/context.d.ts +89 -118
  81. package/dist/runtime/context.d.ts.map +1 -1
  82. package/dist/runtime/context.js +107 -167
  83. package/dist/runtime/context.js.map +1 -1
  84. package/dist/runtime/control.js +3 -3
  85. package/dist/runtime/control.js.map +1 -1
  86. package/dist/runtime/dev-protocol.d.ts +4 -8
  87. package/dist/runtime/dev-protocol.d.ts.map +1 -1
  88. package/dist/runtime/dev-protocol.js.map +1 -1
  89. package/dist/runtime/entry.client.js +69 -105
  90. package/dist/runtime/entry.client.js.map +1 -1
  91. package/dist/runtime/entry.rsc.d.ts +5 -6
  92. package/dist/runtime/entry.rsc.d.ts.map +1 -1
  93. package/dist/runtime/entry.rsc.js +67 -122
  94. package/dist/runtime/entry.rsc.js.map +1 -1
  95. package/dist/runtime/entry.ssr.d.ts +7 -12
  96. package/dist/runtime/entry.ssr.d.ts.map +1 -1
  97. package/dist/runtime/entry.ssr.js +13 -24
  98. package/dist/runtime/entry.ssr.js.map +1 -1
  99. package/dist/runtime/flight-inject.d.ts +10 -17
  100. package/dist/runtime/flight-inject.d.ts.map +1 -1
  101. package/dist/runtime/flight-inject.js +35 -53
  102. package/dist/runtime/flight-inject.js.map +1 -1
  103. package/dist/runtime/hot-update.d.ts +20 -27
  104. package/dist/runtime/hot-update.d.ts.map +1 -1
  105. package/dist/runtime/hot-update.js +17 -23
  106. package/dist/runtime/hot-update.js.map +1 -1
  107. package/dist/runtime/navigation.d.ts +14 -19
  108. package/dist/runtime/navigation.d.ts.map +1 -1
  109. package/dist/runtime/navigation.js +9 -13
  110. package/dist/runtime/navigation.js.map +1 -1
  111. package/dist/runtime/request.d.ts +4 -6
  112. package/dist/runtime/request.d.ts.map +1 -1
  113. package/dist/runtime/request.js +2 -3
  114. package/dist/runtime/request.js.map +1 -1
  115. package/dist/runtime/server.d.ts +18 -10
  116. package/dist/runtime/server.d.ts.map +1 -1
  117. package/dist/runtime/server.js +21 -19
  118. package/dist/runtime/server.js.map +1 -1
  119. package/dist/server/headers.d.ts +8 -15
  120. package/dist/server/headers.d.ts.map +1 -1
  121. package/dist/server/headers.js +8 -15
  122. package/dist/server/headers.js.map +1 -1
  123. package/dist/server/load-config.d.ts +2 -2
  124. package/dist/server/load-config.d.ts.map +1 -1
  125. package/dist/server/load-config.js +6 -9
  126. package/dist/server/load-config.js.map +1 -1
  127. package/dist/server/prerendered.d.ts +30 -43
  128. package/dist/server/prerendered.d.ts.map +1 -1
  129. package/dist/server/prerendered.js +20 -29
  130. package/dist/server/prerendered.js.map +1 -1
  131. package/dist/server/server-config.d.ts +13 -28
  132. package/dist/server/server-config.d.ts.map +1 -1
  133. package/dist/server/server-config.js +5 -10
  134. package/dist/server/server-config.js.map +1 -1
  135. package/dist/server/shutdown.d.ts +2 -3
  136. package/dist/server/shutdown.d.ts.map +1 -1
  137. package/dist/server/shutdown.js +2 -3
  138. package/dist/server/shutdown.js.map +1 -1
  139. package/dist/server/ssg.d.ts +3 -6
  140. package/dist/server/ssg.d.ts.map +1 -1
  141. package/dist/server/ssg.js +11 -20
  142. package/dist/server/ssg.js.map +1 -1
  143. package/package.json +1 -1
@@ -1,51 +1,34 @@
1
+ // `__RSHONO_CONFIG__` is a global const, and an `import` cannot bring one into scope — a path reference is
2
+ // the only way to reach it, which is the whole reason that file is separate. See its header.
3
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
1
4
  /// <reference path="../types/rshono-config.d.ts" />
2
5
  /**
3
- * The request context: {@link getRequestContext} and the {@link RequestContext} wrapper it returns,
4
- * the {@link redirect} / {@link notFound} control-flow helpers, and the
5
- * {@link onServerError} reporting funnel — plus the `@internal` plumbing that binds
6
- * a request to the async context in the first place.
6
+ * The request context: {@link getRequestContext} and the {@link RequestContext} it returns, the
7
+ * {@link redirect} / {@link notFound} control-flow helpers, and the {@link onServerError} reporting
8
+ * funnel — plus the `@internal` plumbing that binds a request to the async context.
7
9
  *
8
- * The public half of this module is re-exported by `runtime/server.ts`, which is
9
- * what the `@rshono/core/server` subpath resolves to; import *that* from an app. Nothing
10
- * here is safe in a `'use client'` module — those run in the browser, with no bound
11
- * request context.
10
+ * The public half is re-exported by `runtime/server.ts`, which is what `@rshono/core/server` resolves
11
+ * to; an app imports that.
12
12
  */
13
13
  import { deleteCookie, getCookie, setCookie } from 'hono/cookie';
14
14
  import { AsyncLocalStorage } from 'node:async_hooks';
15
15
  import { NotFoundSignal, RedirectSignal } from './control.js';
16
16
  const contextStorage = new AsyncLocalStorage();
17
- /** One {@link RequestContext} per Hono {@link Context}, so repeated `getRequestContext()` calls in a request share its lazy getters. */
17
+ /** One {@link RequestContext} per Hono {@link Context}, so repeated `getRequestContext()` calls share its lazy getters. */
18
18
  const wrappers = new WeakMap();
19
- /**
20
- * Requests whose page render has begun — the point past which nothing can change the response head.
21
- *
22
- * A `WeakSet` keyed on the Hono {@link Context} rather than a field on {@link RequestContext},
23
- * so marking a request costs nothing for the pages that never read their context: the wrapper is
24
- * built lazily by {@link getRequestContext} and this must not be what forces it into existence.
25
- */
19
+ // Keyed on the Hono context rather than held as a field, so marking a request never forces the lazily
20
+ // built `RequestContext` wrapper into existence.
26
21
  const rendering = new WeakSet();
27
22
  /**
28
23
  * Marks the request as having entered its page render, which is what makes
29
24
  * {@link RequestContext.setHeader} and `ctx.cookies.set()` start throwing.
30
25
  *
31
- * Framework internal — `renderComponent` calls this immediately before handing the page to React.
32
- * Everything that legitimately writes to the response (middleware, a `'use server'` action, an
33
- * endpoint route) has already run by then, so none of them are affected.
34
- *
35
26
  * @internal
36
27
  */
37
28
  export function beginPageRender(c) {
38
29
  rendering.add(c);
39
30
  }
40
- /**
41
- * The shared explanation for a response mutation that arrived too late, thrown by
42
- * {@link RequestContext.setHeader} and the `cookies` writers.
43
- *
44
- * Refusing beats the alternative, which was silent *and* inconsistent: a page setting a cookie got it
45
- * on a full page load and lost it on a soft navigation, because the flight stream's response head is
46
- * committed before the page component's first line runs. Nothing inside the render can fix that, so
47
- * the message says where the write does belong instead.
48
- */
31
+ /** The shared refusal for a response write that arrived too late — the message names where it belongs instead. */
49
32
  function tooLateToWrite(call) {
50
33
  throw new Error(`[rshono] ${call} was called while rendering a page, which is too late to affect the response. ` +
51
34
  'A page streams, so its response head is already committed by the time the component runs — the ' +
@@ -53,38 +36,24 @@ function tooLateToWrite(call) {
53
36
  "'use server' action instead; or, in middleware and { type: 'endpoint' } routes — which are handed " +
54
37
  "Hono's `c` directly and run outside the request context — with `c.header(…)` / `setCookie(c, …)`.");
55
38
  }
56
- /** The shared explanation for a Hono `Context` member that a page has no way to use. See the stubs on {@link RequestContext}. */
39
+ /** The shared refusal for a Hono `Context` member a page has no way to use. See the stubs on {@link RequestContext}. */
57
40
  function notOnContext(call, instead) {
58
41
  throw new Error(`[rshono] ctx.${call} does not exist. A page returns JSX and the framework builds the response from it, ` +
59
42
  `so Hono's response builders have nothing to return to. ${instead}`);
60
43
  }
61
- /**
62
- * `process.env`, snapshotted on first read.
63
- *
64
- * Enumerating it crosses into the host environment, which made the spread (~20µs) by far the most
65
- * expensive thing {@link RequestContext.env} did, once per request that touched it. Lazily rather
66
- * than at module load, because `loadEnvFiles()` runs *after* this module is imported and an eager
67
- * copy would miss everything from `.env`. The trade-off: a `process.env` mutation after the first
68
- * `ctx.env` read is not picked up.
69
- */
44
+ // Snapshotted rather than spread per request: enumerating `process.env` crosses into the host
45
+ // environment (~20µs). Lazily, because `loadEnvFiles()` runs after this module is imported — so a
46
+ // mutation after the first `ctx.env` read is not picked up.
70
47
  let envSnapshot;
71
48
  function processEnv() {
72
49
  return (envSnapshot ??= typeof process !== 'undefined' && process.env ? { ...process.env } : {});
73
50
  }
74
- /**
75
- * True when this process is the SSG build prerendering `render: 'static'` routes rather than a server
76
- * handling real requests. `build.ts` sets `RSHONO_PRERENDER` before importing the app bundle, which
77
- * inlines its own copy of this module — so `process.env` is what crosses that boundary, not a
78
- * module-level flag. {@link getRequestContext} reads it to fail loudly instead of baking synthetic
79
- * build-time values (a `localhost` URL, no cookies, build env) into the prerendered page.
80
- */
51
+ // Set by `build.ts` before it imports the app bundle, which inlines its own copy of this module — so
52
+ // `process.env` is what crosses that boundary rather than a module-level flag.
81
53
  const prerendering = typeof process !== 'undefined' && !!process.env?.RSHONO_PRERENDER;
82
54
  /**
83
- * Runs `fn` with the given Hono {@link Context} bound as the ambient request
84
- * context, so that {@link getRequestContext} resolves to it anywhere in the call tree.
85
- *
86
- * Framework internal — the request handler wraps every render and action in
87
- * this. Application code should reach for {@link getRequestContext} instead.
55
+ * Runs `fn` with `c` bound as the ambient request context, so {@link getRequestContext} resolves to it
56
+ * anywhere in the call tree.
88
57
  *
89
58
  * @internal
90
59
  */
@@ -94,9 +63,6 @@ export function runWithContext(c, fn) {
94
63
  /**
95
64
  * The matched route params, or an empty object when there is no active match.
96
65
  *
97
- * Framework internal — the request renderer calls this to build a page's `params` prop, and
98
- * {@link RequestContext.params} caches it. Read them from that prop, or from `ctx.params`.
99
- *
100
66
  * @internal
101
67
  */
102
68
  export function readParams(c) {
@@ -112,25 +78,24 @@ function firstForwardedValue(header) {
112
78
  const first = header?.split(',')[0]?.trim();
113
79
  return first || undefined;
114
80
  }
115
- // DefinePlugin inlines the config into the server bundle, but this module is the public
116
- // `@rshono/core/server` entry and could be loaded by tooling that doesn't (a unit test, a one-off script).
117
- // Read through `typeof` so that degrades to the safe answer — don't trust — instead of a ReferenceError.
81
+ // Read through `typeof`: DefinePlugin inlines this into the server bundle, but the module is also the
82
+ // public `@rshono/core/server` entry, which tooling can load without one. Absent means don't trust.
118
83
  const trustProxy = typeof __RSHONO_CONFIG__ !== 'undefined' && __RSHONO_CONFIG__.trustProxy;
119
84
  /**
120
- * Resolves the browser-facing {@link URL} for a request, from a Hono {@link Context}.
85
+ * The browser-facing {@link URL} for a request, resolved from Hono's {@link Context} — a fresh
86
+ * instance per call.
121
87
  *
122
- * `c.req.url` reflects the internal address the server was reached on, which is wrong behind a proxy.
123
- * `X-Forwarded-Host` / `X-Forwarded-Proto` fix that up — **but only when `trustProxy` is enabled in
124
- * `rshono.config.ts`** (always so under `rshono dev`). They are client-supplied, so honouring them
125
- * unconditionally would let anyone who can reach the server dictate the origin of every absolute URL
126
- * the app builds, and poison a shared cache with it.
88
+ * `c.req.url` is the internal address the server was reached on, which is wrong behind a proxy;
89
+ * `X-Forwarded-Host` / `-Proto` correct it, but only when `trustProxy` is enabled in
90
+ * `rshono.config.ts` — they are client-supplied, so trusting them unconditionally would let anyone
91
+ * dictate the origin of every absolute URL the app builds.
127
92
  *
128
- * This is the form for **middleware**, which is handed `c` and runs outside the request context. In
129
- * a server component or a `'use server'` action prefer {@link RequestContext.url}, which is this same
130
- * value cached per request.
93
+ * This is the form for **middleware**, which is handed `c` and runs outside the request context — and
94
+ * so the way to give Hono's own middleware the origin the browser actually used. In a server component
95
+ * or action, prefer {@link RequestContext.url}, the same value cached per request.
131
96
  *
132
- * Its main use is giving Hono's own middleware the origin the browser actually used, since they all
133
- * read `c.req.url` on their own and so see the internal one:
97
+ * @param c - The Hono {@link Context} for the request.
98
+ * @returns The browser-facing URL — proxy-corrected under `trustProxy`, `c.req.url` otherwise.
134
99
  *
135
100
  * @example
136
101
  * ```ts
@@ -141,11 +106,6 @@ const trustProxy = typeof __RSHONO_CONFIG__ !== 'undefined' && __RSHONO_CONFIG__
141
106
  * server.use(csrf({ origin: (origin, c) => origin === publicUrl(c).origin }));
142
107
  * ```
143
108
  *
144
- * A fresh instance per call, so mutating it disturbs nothing else.
145
- *
146
- * @param c - The Hono {@link Context} for the request.
147
- * @returns The browser-facing URL — proxy-corrected under `trustProxy`, `c.req.url` otherwise.
148
- *
149
109
  * @see {@link https://www.rshono.com/docs/configuration#proxy-headers | Docs — proxy headers}
150
110
  */
151
111
  export function publicUrl(c) {
@@ -153,31 +113,27 @@ export function publicUrl(c) {
153
113
  if (!trustProxy)
154
114
  return url;
155
115
  const forwardedHost = firstForwardedValue(c.req.header('x-forwarded-host'));
156
- // Parsed rather than assigned to `url.host`, because that setter *keeps the existing port* when
157
- // the new value has none — leaving the internal port on the public URL (`example.com:3000`).
116
+ // Parsed, not assigned to `url.host`: that setter keeps the existing port when the new value has none.
158
117
  const forwarded = forwardedHost ? URL.parse(`http://${forwardedHost}`) : null;
159
118
  if (forwarded) {
160
119
  url.hostname = forwarded.hostname;
161
- url.port = forwarded.port; // '' when the forwarded host carries no port, which clears it
120
+ url.port = forwarded.port;
162
121
  }
163
- // Restricted to the two schemes a browser can actually have requested; anything else (a proxy
164
- // sending junk, or a client trying its luck) leaves the scheme alone.
122
+ // Only the two schemes a browser could have requested; anything else leaves the scheme alone.
165
123
  const forwardedProto = firstForwardedValue(c.req.header('x-forwarded-proto'));
166
124
  if (forwardedProto === 'http' || forwardedProto === 'https')
167
125
  url.protocol = forwardedProto;
168
126
  return url;
169
127
  }
170
128
  /**
171
- * Ergonomic, read-mostly wrapper around Hono's {@link Context} for use inside
172
- * server components and server actions.
129
+ * Read-mostly wrapper around Hono's {@link Context}, for server components and server actions.
173
130
  *
174
- * Obtain one with {@link getRequestContext}, or — in a page component — take it straight
175
- * off the `ctx` prop, which is this same object. Never construct it yourself. One
176
- * instance is reused for the lifetime of a request, so its lazy getters
131
+ * Obtain one with {@link getRequestContext}, or take it off a page's `ctx` prop — the same object.
132
+ * Never construct it yourself. One instance is reused for the whole request, so its lazy getters
177
133
  * ({@link RequestContext.url}, {@link RequestContext.env}) are computed at most once.
178
134
  *
179
- * @typeParam E - The Hono {@link Env} describing this app's `Bindings` and
180
- * `Variables`, so {@link RequestContext.var} and {@link RequestContext.env} stay typed.
135
+ * @typeParam E - The Hono {@link Env} describing this app's `Bindings` and `Variables`, so
136
+ * {@link RequestContext.var} and {@link RequestContext.env} stay typed.
181
137
  *
182
138
  * @example
183
139
  * ```tsx
@@ -199,8 +155,8 @@ export class RequestContext {
199
155
  #env;
200
156
  #params;
201
157
  /**
202
- * Framework internal — one instance is created per request and handed to you by
203
- * {@link getRequestContext} or the `ctx` page prop. Application code never calls this.
158
+ * One instance is created per request and handed out by {@link getRequestContext} or the `ctx` page
159
+ * prop. Application code never calls this.
204
160
  *
205
161
  * @internal
206
162
  */
@@ -208,12 +164,12 @@ export class RequestContext {
208
164
  this.#raw = c;
209
165
  }
210
166
  /**
211
- * The underlying Hono {@link Context} — the escape hatch for what this wrapper does not expose,
212
- * such as `executionCtx.waitUntil()` on Workers.
167
+ * The underlying Hono {@link Context} — the escape hatch for what this wrapper does not expose, such
168
+ * as `executionCtx.waitUntil()` on Workers.
213
169
  *
214
- * Its response builders (`redirect`, `notFound`, `json`, `body`, `status`, …) still do nothing from
215
- * inside a page, for the reason the stubs on this class explain: reaching them through here
216
- * bypasses the error, it does not make them work.
170
+ * Its response builders (`redirect`, `json`, `body`, `status`, …) still do nothing from inside a
171
+ * page: reaching them through here bypasses the errors the stubs on this class throw, it does not
172
+ * make them work.
217
173
  *
218
174
  * @example
219
175
  * ```ts
@@ -222,13 +178,10 @@ export class RequestContext {
222
178
  *
223
179
  * @see {@link https://hono.dev/docs/api/context | Hono — Context}
224
180
  */
225
- // A prototype getter rather than a plain property, so it is not *own enumerable*. React's
226
- // diagnostic for a value that cannot be sent to a client component walks `Object.keys` recursively
227
- // with no depth limit and no cycle guard, and the Hono context graph reaches the socket and the
228
- // whole server through `req.raw` and `env` — as a plain property this blew the stack inside the
229
- // message builder, so React's accurate "you cannot pass this" error never got printed. Every member
230
- // here is a getter or method for the same reason; `cookies` is the one own enumerable property, and
231
- // it is a shallow object of four functions.
181
+ // Every member here is a getter or method so that none is *own enumerable*: React's "you cannot pass
182
+ // this to a client component" diagnostic walks `Object.keys` recursively with no cycle guard, and the
183
+ // Hono context graph reaches the socket through `req.raw`. `cookies` is the one own property, and it
184
+ // is a shallow object of four functions.
232
185
  get hono() {
233
186
  return this.#raw;
234
187
  }
@@ -237,9 +190,8 @@ export class RequestContext {
237
190
  * {@link Context.req}, unwrapped, so `ctx.req.header('authorization')` rather than
238
191
  * `ctx.hono.req.header(…)`.
239
192
  *
240
- * Reads only. Setting a *response* header is {@link RequestContext.setHeader}, deliberately in a
241
- * different place — Hono's `c.header()` writing the response while `c.req.header()` reads the
242
- * request is a well-worn source of confusion.
193
+ * Reads only; setting a *response* header is {@link RequestContext.setHeader}, deliberately spelled
194
+ * differently.
243
195
  *
244
196
  * @example
245
197
  * ```ts
@@ -255,32 +207,33 @@ export class RequestContext {
255
207
  return this.#raw.req;
256
208
  }
257
209
  /**
258
- * Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. Empty when there
259
- * is no active route match.
210
+ * Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. Empty when no route
211
+ * matched.
260
212
  *
261
- * A **page** is handed the same record as its `params` prop, typed key-by-key from its route path,
262
- * and that is the better read where it is available. This is for everywhere else — a nested server
263
- * component, or a `'use server'` action — which get no props from the framework.
213
+ * A page is handed the same record as its `params` prop, typed key-by-key from its route path, and
214
+ * that is the better read where it exists. This is for everywhere else — a nested server component,
215
+ * or a `'use server'` action.
264
216
  */
265
217
  get params() {
266
218
  return (this.#params ??= readParams(this.#raw));
267
219
  }
268
220
  /**
269
- * The browser-facing request URL — read `url.pathname`, `url.searchParams` and the
270
- * rest off it. Parsed once and cached, so the same instance comes back on every
271
- * read within a request; treat it as read-only for that reason.
221
+ * The browser-facing request URL. Parsed once and cached, so every read within a request returns the
222
+ * same instance — treat it as read-only.
272
223
  *
273
224
  * `X-Forwarded-Host` / `-Proto` are honoured only when `trustProxy` is enabled in
274
225
  * `rshono.config.ts`, since any client can send them.
275
226
  *
227
+ * @example `const tab = getRequestContext().url.searchParams.get('tab');`
228
+ *
276
229
  * @see {@link https://www.rshono.com/docs/configuration#proxy-headers | Docs — proxy headers}
277
230
  */
278
231
  get url() {
279
232
  return (this.#url ??= publicUrl(this.#raw));
280
233
  }
281
234
  /**
282
- * Typed variables set by middleware via `c.set('user', …)`, read here as
283
- * `ctx.var.user`. Type them by parameterising this class's {@link Env}.
235
+ * Typed variables set by middleware via `c.set('user', …)`, read here as `ctx.var.user`. Type them by
236
+ * parameterising this class's {@link Env}.
284
237
  *
285
238
  * @example
286
239
  * ```ts
@@ -295,8 +248,8 @@ export class RequestContext {
295
248
  return this.#raw.var;
296
249
  }
297
250
  /**
298
- * Environment for the request: process env vars merged with runtime bindings
299
- * (bindings win on conflict). Computed once and cached.
251
+ * Environment for the request: process env vars merged with runtime bindings, which win on conflict.
252
+ * Computed once and cached.
300
253
  *
301
254
  * @example `const key = getRequestContext().env.STRIPE_SECRET_KEY;`
302
255
  *
@@ -307,7 +260,6 @@ export class RequestContext {
307
260
  if (this.#env)
308
261
  return this.#env;
309
262
  const bindings = this.#raw.env;
310
- // The snapshot is shared, so hand it back as-is when there are no bindings to merge over it.
311
263
  return (this.#env = (bindings ? { ...processEnv(), ...bindings } : processEnv()));
312
264
  }
313
265
  /**
@@ -329,12 +281,12 @@ export class RequestContext {
329
281
  /** Reads every cookie as a `{ name: value }` record. Safe anywhere, a page included. */
330
282
  all: () => getCookie(this.#raw),
331
283
  /**
332
- * Sets a cookie on the response. See Hono's {@link CookieOptions} for `path`, `httpOnly`,
333
- * `maxAge`, etc.
284
+ * Sets a cookie on the response. See Hono's {@link CookieOptions} for `path`, `httpOnly`, `maxAge`
285
+ * and the rest.
334
286
  *
335
- * **Throws inside a page render** — see {@link RequestContext.setHeader}, of which a `Set-Cookie`
336
- * is a special case. Set cookies from a `'use server'` action, or with Hono's `setCookie(c, …)`
337
- * in middleware and endpoint routes.
287
+ * **Throws inside a page render** — a `Set-Cookie` is a special case of
288
+ * {@link RequestContext.setHeader}. Set cookies from a `'use server'` action, or with Hono's
289
+ * `setCookie(c, …)` in middleware and endpoint routes.
338
290
  *
339
291
  * @throws If called while a page is rendering, where it could not reach the browser reliably.
340
292
  *
@@ -355,7 +307,6 @@ export class RequestContext {
355
307
  deleteCookie(this.#raw, name, options);
356
308
  },
357
309
  };
358
- /** Guards every write that has to reach the response head. See {@link tooLateToWrite}. */
359
310
  #assertWritable(call) {
360
311
  if (rendering.has(this.#raw))
361
312
  tooLateToWrite(call);
@@ -364,14 +315,12 @@ export class RequestContext {
364
315
  * Sets a header on the response — from a `'use server'` action, which is the one place a request
365
316
  * context exists *and* the response is still open.
366
317
  *
367
- * From inside a page it throws: a page streams, so by then the response head is committed. Hono's
368
- * `c.header()` fails there silently and inconsistently — landing on a full page load, vanishing on
369
- * a soft navigation — so this refuses rather than doing it half the time.
318
+ * From inside a page it throws: a page streams, so its response head is already committed by then,
319
+ * and the write would land on a full page load but vanish on a soft navigation.
370
320
  *
371
- * Middleware and `{ type: 'endpoint' }` routes run outside the request context but are handed
372
- * Hono's `c` directly, so they use `c.header(…)`. That is also where a header belonging to the
373
- * *page* rather than to one action goes — `Cache-Control`, `X-Robots-Tag` — since middleware runs
374
- * before the render.
321
+ * Middleware and `{ type: 'endpoint' }` routes are handed Hono's `c` directly and use `c.header(…)`.
322
+ * That is also where a header belonging to the *page* goes — `Cache-Control`, `X-Robots-Tag` — since
323
+ * middleware runs before the render.
375
324
  *
376
325
  * @param name - Header name, case-insensitive.
377
326
  * @param value - Header value.
@@ -393,52 +342,49 @@ export class RequestContext {
393
342
  this.#assertWritable('ctx.setHeader()');
394
343
  this.#raw.header(name, value, options);
395
344
  }
396
- // Hono's response builders, restated as errors naming what to use instead. A page returns JSX and
397
- // `renderComponent` builds the response from it, so every one of these is a silent no-op through
398
- // `ctx.hono`. `@deprecated` is the compile-time signal — an editor strikes them through in
399
- // autocomplete — and the thrown message is the one that explains. Each takes `...args: unknown[]`
400
- // it never reads so that `ctx.redirect('/dashboard')` reaches that message rather than stopping at
401
- // "Expected 0 arguments, but got 1".
345
+ // Hono's response builders, restated as errors naming what to use instead — through `ctx.hono` every
346
+ // one of them is a silent no-op from a page. `@deprecated` strikes them through in autocomplete; the
347
+ // unread `..._args` is so `ctx.redirect('/x')` reaches the thrown message rather than an arity error.
402
348
  /** @deprecated Not available on a page's context — use `redirect()` from `@rshono/core/server`. */
403
- redirect(...args) {
349
+ redirect(..._args) {
404
350
  return notOnContext('redirect(location, status?)', "Use `redirect()` from '@rshono/core/server', which throws a signal the framework turns into a real redirect.");
405
351
  }
406
352
  /** @deprecated Not available on a page's context — use `notFound()` from `@rshono/core/server`. */
407
- notFound(...args) {
353
+ notFound(..._args) {
408
354
  return notOnContext('notFound()', "Use `notFound()` from '@rshono/core/server', which aborts the render and shows the app's not-found page.");
409
355
  }
410
356
  /** @deprecated A page renders JSX. For a JSON response, use an `{ type: 'endpoint' }` route. */
411
- json(...args) {
357
+ json(..._args) {
412
358
  return notOnContext('json(object)', "For a JSON response use an { type: 'endpoint' } route; to read the request body use `ctx.req.json()`.");
413
359
  }
414
360
  /** @deprecated A page renders JSX. For a text response, use an `{ type: 'endpoint' }` route. */
415
- text(...args) {
361
+ text(..._args) {
416
362
  return notOnContext('text(string)', "For a text response use an { type: 'endpoint' } route; to read the request body use `ctx.req.text()`.");
417
363
  }
418
364
  /** @deprecated A page renders JSX, which the framework turns into HTML for you. */
419
- html(...args) {
365
+ html(..._args) {
420
366
  return notOnContext('html(string)', "A page's JSX is already its HTML; for a hand-built HTML response use an { type: 'endpoint' } route.");
421
367
  }
422
368
  /** @deprecated Not available on a page's context. To read the request body, use `ctx.req`. */
423
- body(...args) {
369
+ body(..._args) {
424
370
  return notOnContext('body(data, …)', "To read the *request* body use `ctx.req.json()` / `ctx.req.text()` / `ctx.req.formData()`; to build a response, use an { type: 'endpoint' } route.");
425
371
  }
426
372
  /** @deprecated A page's status is set by the framework — use `notFound()`, or an endpoint route. */
427
- status(...args) {
373
+ status(..._args) {
428
374
  return notOnContext('status(code)', "A page's status is the framework's: 200, 404 via `notFound()`, 500 when it throws. For any other code use an { type: 'endpoint' } route.");
429
375
  }
430
376
  /** @deprecated Renamed — use `ctx.setHeader(name, value)`, which is valid from a `'use server'` action. */
431
- header(...args) {
377
+ header(..._args) {
432
378
  return notOnContext('header(name, value)', "Use `ctx.setHeader(name, value)` from a 'use server' action, or `c.header(…)` in middleware — a page renders too late to set one.");
433
379
  }
434
380
  }
435
381
  /**
436
- * Returns the {@link RequestContext} for the current request — the URL, cookies, params, env and
437
- * middleware variables, read from a server component or a server action. Memoised per request, so
438
- * repeated calls return the same instance.
382
+ * The {@link RequestContext} for the current request — URL, cookies, params, env and middleware
383
+ * variables — read from a server component or a server action. Memoised per request, so repeated calls
384
+ * return the same instance.
439
385
  *
440
- * A **page** component is handed that same object as its `ctx` prop, so this import is for everywhere
441
- * else: a nested server component, or a `'use server'` action module.
386
+ * A page is handed that same object as its `ctx` prop, so this import is for everywhere else: a nested
387
+ * server component, or a `'use server'` action module.
442
388
  *
443
389
  * @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and {@link RequestContext.env}.
444
390
  * @throws If called at module load, where there is no ambient context to resolve.
@@ -477,16 +423,15 @@ export function getRequestContext() {
477
423
  return ctx;
478
424
  }
479
425
  /**
480
- * Redirects the request to `location` by throwing a control signal that the
481
- * framework catches and turns into an HTTP redirect response.
426
+ * Redirects the request to `location`, by throwing a control signal the framework turns into an HTTP
427
+ * redirect.
482
428
  *
483
- * Because it throws, it never returns — TypeScript narrows away any code after
484
- * the call, and you do not need to `return` it. Do not wrap it in a `try/catch`
485
- * that swallows the signal.
429
+ * Because it throws it never returns, so TypeScript narrows away everything after the call and there
430
+ * is nothing to `return`. Don't wrap it in a `try/catch` that swallows the signal.
486
431
  *
487
432
  * @param location - Absolute path or URL to redirect to, e.g. `/dashboard`.
488
- * @param status - Redirect {@link RedirectStatus}; defaults to `303` (See Other),
489
- * the correct choice after a form action so the browser follows up with a `GET`.
433
+ * @param status - Redirect {@link RedirectStatus}; defaults to `303` (See Other), which is what makes
434
+ * the browser follow up with a `GET` after a form action.
490
435
  *
491
436
  * @example
492
437
  * ```ts
@@ -499,10 +444,10 @@ export function redirect(location, status = 303) {
499
444
  throw new RedirectSignal(location, status);
500
445
  }
501
446
  /**
502
- * Aborts the current render with a 404, rendering the app's not-found page.
447
+ * Aborts the current render with a 404, rendering the app's `notFound` page.
503
448
  *
504
- * Like {@link redirect}, this throws a control signal and never returns, so
505
- * TypeScript narrows away everything after the call. Do not catch-and-swallow it.
449
+ * Like {@link redirect} it throws a control signal and never returns, so TypeScript narrows away
450
+ * everything after the call. Don't catch-and-swallow it.
506
451
  *
507
452
  * @example
508
453
  * ```tsx
@@ -521,12 +466,9 @@ let errorHandler;
521
466
  * Registers a handler for every error the framework catches, so they can reach an error tracker
522
467
  * (Sentry, Datadog, a log pipeline) instead of only `stderr`.
523
468
  *
524
- * Call it **once, at the top level of `src/server.ts`** — that module is imported as the server
525
- * starts, before any request is served. Registering again replaces the previous handler.
526
- *
527
- * Errors are still written to `stderr` either way, so a handler adds a destination rather than
528
- * replacing one. A handler that throws is caught and logged: reporting must never be able to fail
529
- * a request.
469
+ * Call it once, at the top level of `src/server.ts`, which is imported as the server starts.
470
+ * Registering again replaces the previous handler. Errors still go to `stderr` either way, and a
471
+ * handler that throws is caught and logged — reporting can never fail a request.
530
472
  *
531
473
  * @example
532
474
  * ```ts
@@ -545,10 +487,8 @@ export function onServerError(handler) {
545
487
  errorHandler = handler;
546
488
  }
547
489
  /**
548
- * Logs an error and forwards it to the registered {@link ServerErrorHandler}.
549
- *
550
- * Framework internal — the single funnel every caught server-side error goes through, so that
551
- * adding a reporting destination is one registration rather than a hook per call site.
490
+ * Logs an error and forwards it to the registered {@link ServerErrorHandler} — the single funnel every
491
+ * caught server-side error goes through.
552
492
  *
553
493
  * @internal
554
494
  */