@rshono/core 1.0.0-rc.2 → 1.0.0-rc.21
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.
- package/LICENSE +21 -0
- package/README.md +348 -158
- package/bin/rshono.mjs +3 -4
- package/dist/builder/env-shadow-loader.cjs +123 -8
- package/dist/builder/page-entry-loader.cjs +28 -1
- package/dist/builder/page-files.d.ts +0 -1
- package/dist/builder/page-files.js +7 -3
- package/dist/builder/page-files.js.map +1 -1
- package/dist/builder/public-env.d.ts +7 -1
- package/dist/builder/public-env.js +7 -0
- package/dist/builder/public-env.js.map +1 -1
- package/dist/builder/react-versions.d.ts +12 -0
- package/dist/builder/react-versions.js +74 -0
- package/dist/builder/react-versions.js.map +1 -0
- package/dist/builder/rspack-config.d.ts +13 -4
- package/dist/builder/rspack-config.js +136 -53
- package/dist/builder/rspack-config.js.map +1 -1
- package/dist/builder/server-only-imports.d.ts +32 -0
- package/dist/builder/server-only-imports.js +51 -0
- package/dist/builder/server-only-imports.js.map +1 -0
- package/dist/cli/build.d.ts +2 -3
- package/dist/cli/build.js +51 -13
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts +2 -3
- package/dist/cli/dev.js +149 -45
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/exit.d.ts +12 -0
- package/dist/cli/exit.js +16 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +91 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/start.d.ts +0 -1
- package/dist/cli/start.js +15 -18
- package/dist/cli/start.js.map +1 -1
- package/dist/config.d.ts +72 -78
- package/dist/config.js +17 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy/aws-lambda/runtime.d.ts +4 -7
- package/dist/deploy/aws-lambda/runtime.js +5 -8
- package/dist/deploy/aws-lambda/runtime.js.map +1 -1
- package/dist/deploy/build-marker.d.ts +9 -6
- package/dist/deploy/build-marker.js +8 -4
- package/dist/deploy/build-marker.js.map +1 -1
- package/dist/deploy/cloudflare/build.d.ts +0 -1
- package/dist/deploy/cloudflare/build.js +17 -13
- package/dist/deploy/cloudflare/build.js.map +1 -1
- package/dist/deploy/cloudflare/runtime.d.ts +2 -6
- package/dist/deploy/cloudflare/runtime.js +73 -68
- package/dist/deploy/cloudflare/runtime.js.map +1 -1
- package/dist/deploy/contract.d.ts +57 -41
- package/dist/deploy/contract.js.map +1 -1
- package/dist/deploy/filesystem.d.ts +3 -6
- package/dist/deploy/filesystem.js +23 -20
- package/dist/deploy/filesystem.js.map +1 -1
- package/dist/deploy/node/runtime.d.ts +5 -3
- package/dist/deploy/node/runtime.js +23 -9
- package/dist/deploy/node/runtime.js.map +1 -1
- package/dist/deploy/presets.d.ts +34 -30
- package/dist/deploy/presets.js +56 -44
- package/dist/deploy/presets.js.map +1 -1
- package/dist/deploy/public-paths.d.ts +42 -0
- package/dist/deploy/public-paths.js +66 -0
- package/dist/deploy/public-paths.js.map +1 -0
- package/dist/deploy/vercel/build.d.ts +0 -1
- package/dist/deploy/vercel/build.js +25 -16
- package/dist/deploy/vercel/build.js.map +1 -1
- package/dist/deploy/vercel/runtime.d.ts +10 -7
- package/dist/deploy/vercel/runtime.js +48 -11
- package/dist/deploy/vercel/runtime.js.map +1 -1
- package/dist/index.d.ts +19 -17
- package/dist/index.js +20 -10
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +212 -120
- package/dist/router.js +3 -8
- package/dist/router.js.map +1 -1
- package/dist/runtime/boundaries.d.ts +62 -48
- package/dist/runtime/boundaries.js +32 -34
- package/dist/runtime/boundaries.js.map +1 -1
- package/dist/runtime/client.d.ts +20 -11
- package/dist/runtime/client.js +20 -10
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/context.d.ts +304 -123
- package/dist/runtime/context.js +377 -149
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.d.ts +15 -1
- package/dist/runtime/control.js +24 -0
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/dev-protocol.d.ts +4 -9
- package/dist/runtime/dev-protocol.js.map +1 -1
- package/dist/runtime/empty-server-app.d.ts +0 -1
- package/dist/runtime/entry.client.d.ts +4 -1
- package/dist/runtime/entry.client.js +455 -313
- package/dist/runtime/entry.client.js.map +1 -1
- package/dist/runtime/entry.rsc.d.ts +15 -7
- package/dist/runtime/entry.rsc.js +811 -252
- package/dist/runtime/entry.rsc.js.map +1 -1
- package/dist/runtime/entry.ssr.d.ts +27 -10
- package/dist/runtime/entry.ssr.js +30 -48
- package/dist/runtime/entry.ssr.js.map +1 -1
- package/dist/runtime/failure-document.d.ts +11 -0
- package/dist/runtime/failure-document.js +35 -0
- package/dist/runtime/failure-document.js.map +1 -0
- package/dist/runtime/flight-inject.d.ts +23 -0
- package/dist/runtime/flight-inject.js +403 -0
- package/dist/runtime/flight-inject.js.map +1 -0
- package/dist/runtime/hot-update.d.ts +44 -0
- package/dist/runtime/hot-update.js +44 -0
- package/dist/runtime/hot-update.js.map +1 -0
- package/dist/runtime/navigation.d.ts +46 -54
- package/dist/runtime/navigation.js +22 -63
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/request.d.ts +42 -8
- package/dist/runtime/request.js +84 -7
- package/dist/runtime/request.js.map +1 -1
- package/dist/runtime/server.d.ts +20 -18
- package/dist/runtime/server.js +22 -17
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/validate-entries.d.ts +77 -0
- package/dist/runtime/validate-entries.js +405 -0
- package/dist/runtime/validate-entries.js.map +1 -0
- package/dist/server/headers.d.ts +41 -15
- package/dist/server/headers.js +53 -24
- package/dist/server/headers.js.map +1 -1
- package/dist/server/load-config.d.ts +4 -5
- package/dist/server/load-config.js +22 -14
- package/dist/server/load-config.js.map +1 -1
- package/dist/server/load-env.d.ts +0 -1
- package/dist/server/prerendered.d.ts +88 -34
- package/dist/server/prerendered.js +184 -24
- package/dist/server/prerendered.js.map +1 -1
- package/dist/server/server-config.d.ts +35 -50
- package/dist/server/server-config.js +27 -74
- package/dist/server/server-config.js.map +1 -1
- package/dist/server/shutdown.d.ts +5 -4
- package/dist/server/shutdown.js +5 -3
- package/dist/server/shutdown.js.map +1 -1
- package/dist/server/ssg.d.ts +9 -7
- package/dist/server/ssg.js +209 -65
- package/dist/server/ssg.js.map +1 -1
- package/dist/server/static.d.ts +0 -1
- package/dist/server/static.js +7 -1
- package/dist/server/static.js.map +1 -1
- package/package.json +21 -23
- package/dist/builder/page-files.d.ts.map +0 -1
- package/dist/builder/public-env.d.ts.map +0 -1
- package/dist/builder/rspack-config.d.ts.map +0 -1
- package/dist/cli/build.d.ts.map +0 -1
- package/dist/cli/dev.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/start.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/deploy/aws-lambda/runtime.d.ts.map +0 -1
- package/dist/deploy/build-marker.d.ts.map +0 -1
- package/dist/deploy/bun/runtime.d.ts +0 -11
- package/dist/deploy/bun/runtime.d.ts.map +0 -1
- package/dist/deploy/bun/runtime.js +0 -22
- package/dist/deploy/bun/runtime.js.map +0 -1
- package/dist/deploy/cloudflare/build.d.ts.map +0 -1
- package/dist/deploy/cloudflare/runtime.d.ts.map +0 -1
- package/dist/deploy/contract.d.ts.map +0 -1
- package/dist/deploy/deno/runtime.d.ts +0 -11
- package/dist/deploy/deno/runtime.d.ts.map +0 -1
- package/dist/deploy/deno/runtime.js +0 -16
- package/dist/deploy/deno/runtime.js.map +0 -1
- package/dist/deploy/filesystem.d.ts.map +0 -1
- package/dist/deploy/listen.d.ts +0 -20
- package/dist/deploy/listen.d.ts.map +0 -1
- package/dist/deploy/listen.js +0 -24
- package/dist/deploy/listen.js.map +0 -1
- package/dist/deploy/netlify/build.d.ts +0 -8
- package/dist/deploy/netlify/build.d.ts.map +0 -1
- package/dist/deploy/netlify/build.js +0 -52
- package/dist/deploy/netlify/build.js.map +0 -1
- package/dist/deploy/netlify/runtime.d.ts +0 -13
- package/dist/deploy/netlify/runtime.d.ts.map +0 -1
- package/dist/deploy/netlify/runtime.js +0 -24
- package/dist/deploy/netlify/runtime.js.map +0 -1
- package/dist/deploy/node/runtime.d.ts.map +0 -1
- package/dist/deploy/presets.d.ts.map +0 -1
- package/dist/deploy/vercel/build.d.ts.map +0 -1
- package/dist/deploy/vercel/runtime.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/runtime/boundaries.d.ts.map +0 -1
- package/dist/runtime/client.d.ts.map +0 -1
- package/dist/runtime/context.d.ts.map +0 -1
- package/dist/runtime/control.d.ts.map +0 -1
- package/dist/runtime/dev-protocol.d.ts.map +0 -1
- package/dist/runtime/empty-server-app.d.ts.map +0 -1
- package/dist/runtime/entry.client.d.ts.map +0 -1
- package/dist/runtime/entry.rsc.d.ts.map +0 -1
- package/dist/runtime/entry.ssr.d.ts.map +0 -1
- package/dist/runtime/navigation.d.ts.map +0 -1
- package/dist/runtime/request.d.ts.map +0 -1
- package/dist/runtime/server.d.ts.map +0 -1
- package/dist/server/compress.d.ts +0 -15
- package/dist/server/compress.d.ts.map +0 -1
- package/dist/server/compress.js +0 -76
- package/dist/server/compress.js.map +0 -1
- package/dist/server/headers.d.ts.map +0 -1
- package/dist/server/load-config.d.ts.map +0 -1
- package/dist/server/load-env.d.ts.map +0 -1
- package/dist/server/prerendered.d.ts.map +0 -1
- package/dist/server/server-config.d.ts.map +0 -1
- package/dist/server/shutdown.d.ts.map +0 -1
- package/dist/server/ssg.d.ts.map +0 -1
- package/dist/server/static.d.ts.map +0 -1
|
@@ -1,170 +1,308 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The request context: {@link
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* what the `@rshono/core/server` subpath resolves to; import *that* from an app. Nothing
|
|
9
|
-
* here is safe in a `'use client'` module — those run in the browser, with no bound
|
|
10
|
-
* request context.
|
|
2
|
+
* The request context: {@link getRequestContext} and the {@link RequestContext} it returns, the
|
|
3
|
+
* {@link redirect} / {@link notFound} control-flow helpers, and the {@link onServerError} reporting
|
|
4
|
+
* funnel — plus the `@internal` plumbing that binds a request to the async context.
|
|
5
|
+
*
|
|
6
|
+
* The public half is re-exported by `runtime/server.ts`, which is what `@rshono/core/server` resolves
|
|
7
|
+
* to; an app imports that.
|
|
11
8
|
*/
|
|
12
|
-
import type { Context, Env
|
|
9
|
+
import type { Context, Env } from 'hono';
|
|
13
10
|
import type { CookieOptions } from 'hono/utils/cookie';
|
|
14
11
|
/**
|
|
15
12
|
* HTTP status codes accepted by {@link redirect}.
|
|
16
13
|
*
|
|
17
14
|
* - `301` Moved Permanently, `308` Permanent Redirect — cacheable, permanent.
|
|
18
15
|
* - `302` Found, `307` Temporary Redirect — temporary.
|
|
19
|
-
* - `303` See Other — the default; forces a `GET` on the target, which is what
|
|
20
|
-
*
|
|
16
|
+
* - `303` See Other — the default; forces a `GET` on the target, which is what you almost always want
|
|
17
|
+
* after a form action (post/redirect/get).
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status#redirection_messages | MDN — redirection status codes}
|
|
21
20
|
*/
|
|
22
21
|
export type RedirectStatus = 301 | 302 | 303 | 307 | 308;
|
|
23
22
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Marks the request as having entered its page render, which is what makes
|
|
24
|
+
* {@link RequestContext.setHeader} and `ctx.cookies.set()` start throwing.
|
|
26
25
|
*
|
|
27
|
-
*
|
|
28
|
-
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export declare function beginPageRender(c: Context): void;
|
|
29
|
+
/**
|
|
30
|
+
* Runs `fn` with `c` bound as the ambient request context, so {@link getRequestContext} resolves to it
|
|
31
|
+
* anywhere in the call tree.
|
|
29
32
|
*
|
|
30
33
|
* @internal
|
|
31
34
|
*/
|
|
32
35
|
export declare function runWithContext<T>(c: Context, fn: () => T): T;
|
|
33
36
|
/**
|
|
34
|
-
*
|
|
35
|
-
* active route match (rather than throwing). Shared by {@link Ctx.params} and the
|
|
36
|
-
* request renderer so the fallback behaviour stays in one place.
|
|
37
|
-
*
|
|
38
|
-
* Framework internal — read params from {@link Ctx.params} or a page's
|
|
39
|
-
* `PageProps` instead.
|
|
37
|
+
* The matched route params, or an empty object when there is no active match.
|
|
40
38
|
*
|
|
41
39
|
* @internal
|
|
42
40
|
*/
|
|
43
41
|
export declare function readParams(c: Context): Record<string, string>;
|
|
44
42
|
/**
|
|
45
|
-
*
|
|
43
|
+
* The browser-facing {@link URL} for a request, resolved from Hono's {@link Context} — a fresh
|
|
44
|
+
* instance per call.
|
|
46
45
|
*
|
|
47
|
-
* `c.req.url`
|
|
48
|
-
*
|
|
49
|
-
* `
|
|
50
|
-
*
|
|
51
|
-
* dictate the origin of every absolute URL the app builds — canonical tags, emails, redirects — and
|
|
52
|
-
* poison a shared cache with them. So the default is to ignore them entirely.
|
|
46
|
+
* `c.req.url` is the internal address the server was reached on, which is wrong behind a proxy;
|
|
47
|
+
* `X-Forwarded-Host` / `-Proto` correct it, but only when `trustProxy` is enabled in
|
|
48
|
+
* `rshono.config.ts` — they are client-supplied, so trusting them unconditionally would let anyone
|
|
49
|
+
* dictate the origin of every absolute URL the app builds.
|
|
53
50
|
*
|
|
54
|
-
*
|
|
51
|
+
* This is the form for **middleware**, which is handed `c` and runs outside the request context — and
|
|
52
|
+
* so the way to give Hono's own middleware the origin the browser actually used. In a server component
|
|
53
|
+
* or action, prefer {@link RequestContext.url}, the same value cached per request.
|
|
55
54
|
*
|
|
56
|
-
* @
|
|
55
|
+
* @param c - The Hono {@link Context} for the request.
|
|
56
|
+
* @returns The browser-facing URL — proxy-corrected under `trustProxy`, `c.req.url` otherwise.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* // src/server.ts — a CSRF check that still works behind a proxy that rewrites Host
|
|
61
|
+
* import { publicUrl } from '@rshono/core/server';
|
|
62
|
+
* import { csrf } from 'hono/csrf';
|
|
63
|
+
*
|
|
64
|
+
* server.use(csrf({ origin: (origin, c) => origin === publicUrl(c).origin }));
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @see {@link https://www.rshono.com/docs/configuration#proxy-headers | Docs — proxy headers}
|
|
57
68
|
*/
|
|
58
69
|
export declare function publicUrl(c: Context): URL;
|
|
59
70
|
/**
|
|
60
|
-
* The environment available to a request:
|
|
61
|
-
*
|
|
62
|
-
*
|
|
71
|
+
* The environment available to a request: Workers `Bindings` merged with process env vars. Values not
|
|
72
|
+
* declared in `Bindings` are typed as `string | undefined`. See {@link RequestContext.env}.
|
|
73
|
+
*
|
|
74
|
+
* @see {@link https://hono.dev/docs/getting-started/cloudflare-workers#bindings | Hono — bindings}
|
|
63
75
|
*/
|
|
64
76
|
export type EnvVars<E extends Env> = E['Bindings'] & Record<string, string | undefined>;
|
|
65
77
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
78
|
+
* Read-mostly wrapper around Hono's {@link Context}, for server components and server actions.
|
|
79
|
+
*
|
|
80
|
+
* Obtain one with {@link getRequestContext}, or take it off a page's `ctx` prop — the same object.
|
|
81
|
+
* Never construct it yourself. One instance is reused for the whole request, so its lazy getters
|
|
82
|
+
* ({@link RequestContext.url}, {@link RequestContext.env}) are computed at most once.
|
|
68
83
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
84
|
+
* The eight members that only throw — `redirect`, `notFound`, `json`, `text`, `html`, `body`, `status`,
|
|
85
|
+
* `header` — are **permanent, and exist to throw**. Every one of them is a silent no-op when reached through
|
|
86
|
+
* {@link RequestContext.hono} from a page, so a stub that names the thing that does work is the difference
|
|
87
|
+
* between a message and a page that renders while quietly ignoring half of what it was asked for. They carry
|
|
88
|
+
* `@deprecated` for the strike-through an editor draws with it, not because they are on the way out: nothing
|
|
89
|
+
* will un-deprecate or remove them, and dropping them would leave `ctx.redirect('/x')` as
|
|
90
|
+
* "property does not exist", which says what is wrong and not what to do.
|
|
73
91
|
*
|
|
74
|
-
* @typeParam E - The Hono {@link Env} describing this app's `Bindings` and
|
|
75
|
-
*
|
|
92
|
+
* @typeParam E - The Hono {@link Env} describing this app's `Bindings` and `Variables`, so
|
|
93
|
+
* {@link RequestContext.var} and {@link RequestContext.env} stay typed.
|
|
76
94
|
*
|
|
77
95
|
* @example
|
|
78
96
|
* ```tsx
|
|
79
|
-
* import {
|
|
97
|
+
* import { getRequestContext } from '@rshono/core/server';
|
|
80
98
|
*
|
|
81
99
|
* export default async function Whoami() {
|
|
82
|
-
* const ctx =
|
|
100
|
+
* const ctx = getRequestContext();
|
|
83
101
|
* const session = ctx.cookies.get('session');
|
|
84
102
|
* return <p>{ctx.url.pathname} — {session ?? 'anonymous'}</p>;
|
|
85
103
|
* }
|
|
86
104
|
* ```
|
|
105
|
+
*
|
|
106
|
+
* @see {@link https://www.rshono.com/docs/api#rshonocoreserver | Docs — `@rshono/core/server`}
|
|
107
|
+
* @see {@link https://hono.dev/docs/api/context | Hono — Context}, reachable in full via {@link RequestContext.hono}
|
|
87
108
|
*/
|
|
88
|
-
export declare class
|
|
109
|
+
export declare class RequestContext<E extends Env = Env> {
|
|
89
110
|
#private;
|
|
111
|
+
/**
|
|
112
|
+
* One instance is created per request and handed out by {@link getRequestContext} or the `ctx` page
|
|
113
|
+
* prop. Application code never calls this.
|
|
114
|
+
*
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
90
117
|
constructor(c: Context<E>);
|
|
91
118
|
/**
|
|
92
|
-
* The underlying Hono {@link Context}
|
|
119
|
+
* The underlying Hono {@link Context} — the escape hatch for what this wrapper does not expose, such
|
|
120
|
+
* as `executionCtx.waitUntil()` on Workers.
|
|
93
121
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
122
|
+
* Its response builders (`redirect`, `json`, `body`, `status`, …) still do nothing from inside a
|
|
123
|
+
* page: reaching them through here bypasses the errors the stubs on this class throw, it does not
|
|
124
|
+
* make them work.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* getRequestContext().hono.executionCtx.waitUntil(logAsync()); // Workers
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @see {@link https://hono.dev/docs/api/context | Hono — Context}
|
|
101
132
|
*/
|
|
102
|
-
get
|
|
103
|
-
/** The parsed Hono request (`c.req`) — headers, body parsing, param access, etc. */
|
|
104
|
-
get req(): HonoRequest;
|
|
133
|
+
get hono(): Context<E>;
|
|
105
134
|
/**
|
|
106
|
-
* The
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
135
|
+
* The parsed request — method, headers, path params, query and the body readers. Hono's
|
|
136
|
+
* {@link Context.req}, unwrapped, so `ctx.req.header('authorization')` rather than
|
|
137
|
+
* `ctx.hono.req.header(…)`.
|
|
138
|
+
*
|
|
139
|
+
* Reads only; setting a *response* header is {@link RequestContext.setHeader}, deliberately spelled
|
|
140
|
+
* differently.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* const ctx = getRequestContext();
|
|
145
|
+
* ctx.req.method; // 'GET'
|
|
146
|
+
* ctx.req.header('authorization'); // string | undefined
|
|
147
|
+
* ctx.req.query('tab'); // string | undefined
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @see {@link https://hono.dev/docs/api/request | Hono — HonoRequest}
|
|
110
151
|
*/
|
|
111
|
-
get
|
|
112
|
-
/** The HTTP method of the request, e.g. `GET` or `POST`. */
|
|
113
|
-
get method(): string;
|
|
152
|
+
get req(): Context<E>['req'];
|
|
114
153
|
/**
|
|
115
|
-
* Matched route params, e.g. `{ id }` for
|
|
116
|
-
*
|
|
154
|
+
* Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. Empty when no route
|
|
155
|
+
* matched.
|
|
156
|
+
*
|
|
157
|
+
* A page is handed the same record as its `params` prop, typed key-by-key from its route path, and
|
|
158
|
+
* that is the better read where it exists. This is for everywhere else — a nested server component,
|
|
159
|
+
* or a `'use server'` action.
|
|
117
160
|
*/
|
|
118
161
|
get params(): Record<string, string>;
|
|
119
162
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
163
|
+
* The browser-facing request URL. Parsed once and cached, so every read within a request returns the
|
|
164
|
+
* same instance — treat it as read-only.
|
|
165
|
+
*
|
|
166
|
+
* `X-Forwarded-Host` / `-Proto` are honoured only when `trustProxy` is enabled in
|
|
167
|
+
* `rshono.config.ts`, since any client can send them.
|
|
168
|
+
*
|
|
169
|
+
* @example `const tab = getRequestContext().url.searchParams.get('tab');`
|
|
170
|
+
*
|
|
171
|
+
* @see {@link https://www.rshono.com/docs/configuration#proxy-headers | Docs — proxy headers}
|
|
172
|
+
*/
|
|
173
|
+
get url(): URL;
|
|
174
|
+
/**
|
|
175
|
+
* Typed variables set by middleware via `c.set('user', …)`, read here as `ctx.var.user`. Type them by
|
|
176
|
+
* parameterising this class's {@link Env}.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* type AppEnv = { Variables: { user: { id: string } } };
|
|
181
|
+
* const { user } = getRequestContext<AppEnv>().var; // typed, set by your middleware
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @see {@link https://hono.dev/docs/api/context#var | Hono — c.var}
|
|
185
|
+
* @see {@link https://www.rshono.com/docs/hono#typing-the-context | Docs — typing the context}
|
|
122
186
|
*/
|
|
123
187
|
get var(): Readonly<E['Variables']>;
|
|
124
188
|
/**
|
|
125
|
-
* Environment for the request: process env vars merged with
|
|
126
|
-
*
|
|
189
|
+
* Environment for the request: process env vars, merged on a bindings platform with the bindings, which
|
|
190
|
+
* win on conflict.
|
|
191
|
+
*
|
|
192
|
+
* The `process.env` half is snapshotted **once per process**, not per request — enumerating it crosses
|
|
193
|
+
* into the host environment, and doing that on every request is a cost with nothing to show for it. So a
|
|
194
|
+
* `process.env` mutation made after the first `ctx.env` read anywhere in the process is never seen here.
|
|
195
|
+
* Read `process.env` directly if you have one. The bindings half is per request, since it comes off the
|
|
196
|
+
* request's own Hono context.
|
|
197
|
+
*
|
|
198
|
+
* Bindings are merged **only where the platform supplies them** — `deploy: 'cloudflare'`, today. Hono's
|
|
199
|
+
* `c.env` is whatever the host passed as the second argument to `app.fetch`, and off Workers that is the
|
|
200
|
+
* adapter's own private state: `{ incoming, outgoing }` on Node and Vercel, the entire invocation —
|
|
201
|
+
* headers, cookies, `authorization` — on Lambda. Merging it would make `ctx.env` uncloneable on one and
|
|
202
|
+
* a disclosure vector on the other, both behind names this type declares `string | undefined`. Reach for
|
|
203
|
+
* {@link RequestContext.hono}`.env` if you really do want the adapter's argument.
|
|
204
|
+
*
|
|
205
|
+
* @example `const key = getRequestContext().env.STRIPE_SECRET_KEY;`
|
|
127
206
|
*
|
|
128
|
-
* @
|
|
207
|
+
* @see {@link https://hono.dev/docs/api/context#env | Hono — c.env}
|
|
208
|
+
* @see {@link https://www.rshono.com/docs/configuration#environment-and-secrets | Docs — environment and secrets}
|
|
129
209
|
*/
|
|
130
210
|
get env(): EnvVars<E>;
|
|
131
|
-
/** Sets a response header. Thin pass-through to `c.header(name, value)`. */
|
|
132
|
-
header(name: string, value: string): void;
|
|
133
211
|
/**
|
|
134
212
|
* Read and write request/response cookies.
|
|
135
213
|
*
|
|
136
214
|
* @example
|
|
137
215
|
* ```ts
|
|
138
|
-
* const ctx =
|
|
216
|
+
* const ctx = getRequestContext();
|
|
139
217
|
* ctx.cookies.get('session'); // string | undefined
|
|
140
218
|
* ctx.cookies.set('session', id, { httpOnly: true, sameSite: 'Lax', path: '/' });
|
|
141
219
|
* ctx.cookies.delete('session', { path: '/' });
|
|
142
220
|
* ```
|
|
221
|
+
*
|
|
222
|
+
* @see {@link https://hono.dev/docs/helpers/cookie | Hono — cookie helper}, which this wraps
|
|
143
223
|
*/
|
|
144
224
|
cookies: {
|
|
145
|
-
/** Reads a single cookie by name, or `undefined` if absent. */
|
|
225
|
+
/** Reads a single cookie by name, or `undefined` if absent. Safe anywhere, a page included. */
|
|
146
226
|
get: (name: string) => string | undefined;
|
|
147
|
-
/** Reads every cookie as a `{ name: value }` record. */
|
|
227
|
+
/** Reads every cookie as a `{ name: value }` record. Safe anywhere, a page included. */
|
|
148
228
|
all: () => Record<string, string>;
|
|
149
|
-
/**
|
|
229
|
+
/**
|
|
230
|
+
* Sets a cookie on the response. See Hono's {@link CookieOptions} for `path`, `httpOnly`, `maxAge`
|
|
231
|
+
* and the rest.
|
|
232
|
+
*
|
|
233
|
+
* **Throws inside a page render** — a `Set-Cookie` is a special case of
|
|
234
|
+
* {@link RequestContext.setHeader}. Set cookies from a `'use server'` action, or with Hono's
|
|
235
|
+
* `setCookie(c, …)` in middleware and endpoint routes.
|
|
236
|
+
*
|
|
237
|
+
* @throws If called while a page is rendering, where it could not reach the browser reliably.
|
|
238
|
+
*
|
|
239
|
+
* @see {@link https://hono.dev/docs/helpers/cookie#options | Hono — cookie options}
|
|
240
|
+
*/
|
|
150
241
|
set: (name: string, value: string, options?: CookieOptions) => void;
|
|
151
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* Clears a cookie. Pass the same `path`/`domain` it was set with so the browser matches it.
|
|
244
|
+
* Throws inside a page render, exactly as `set` does.
|
|
245
|
+
*
|
|
246
|
+
* @throws If called while a page is rendering.
|
|
247
|
+
*/
|
|
152
248
|
delete: (name: string, options?: CookieOptions) => void;
|
|
153
249
|
};
|
|
250
|
+
/**
|
|
251
|
+
* Sets a header on the response — from a `'use server'` action, which is the one place a request
|
|
252
|
+
* context exists *and* the response is still open.
|
|
253
|
+
*
|
|
254
|
+
* From inside a page it throws: a page streams, so its response head is already committed by then,
|
|
255
|
+
* and the write would land on a full page load but vanish on a soft navigation.
|
|
256
|
+
*
|
|
257
|
+
* Middleware and `{ type: 'endpoint' }` routes are handed Hono's `c` directly and use `c.header(…)`.
|
|
258
|
+
* That is also where a header belonging to the *page* goes — `Cache-Control`, `X-Robots-Tag` — since
|
|
259
|
+
* middleware runs before the render.
|
|
260
|
+
*
|
|
261
|
+
* @param name - Header name, case-insensitive.
|
|
262
|
+
* @param value - Header value.
|
|
263
|
+
* @param options - `{ append: true }` to add another value rather than replace.
|
|
264
|
+
* @throws If called while a page is rendering, where it could not reach the browser reliably.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* 'use server';
|
|
269
|
+
* export async function logout() {
|
|
270
|
+
* const ctx = getRequestContext();
|
|
271
|
+
* ctx.cookies.delete('session', { path: '/' });
|
|
272
|
+
* ctx.setHeader('clear-site-data', '"cache", "storage"');
|
|
273
|
+
* redirect('/');
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
setHeader(name: string, value: string, options?: {
|
|
278
|
+
append?: boolean;
|
|
279
|
+
}): void;
|
|
280
|
+
/** @deprecated Not available on a page's context — use `redirect()` from `@rshono/core/server`. */
|
|
281
|
+
redirect(..._args: unknown[]): never;
|
|
282
|
+
/** @deprecated Not available on a page's context — use `notFound()` from `@rshono/core/server`. */
|
|
283
|
+
notFound(..._args: unknown[]): never;
|
|
284
|
+
/** @deprecated A page renders JSX. For a JSON response, use an `{ type: 'endpoint' }` route. */
|
|
285
|
+
json(..._args: unknown[]): never;
|
|
286
|
+
/** @deprecated A page renders JSX. For a text response, use an `{ type: 'endpoint' }` route. */
|
|
287
|
+
text(..._args: unknown[]): never;
|
|
288
|
+
/** @deprecated A page renders JSX, which the framework turns into HTML for you. */
|
|
289
|
+
html(..._args: unknown[]): never;
|
|
290
|
+
/** @deprecated Not available on a page's context. To read the request body, use `ctx.req`. */
|
|
291
|
+
body(..._args: unknown[]): never;
|
|
292
|
+
/** @deprecated A page's status is set by the framework — use `notFound()`, or an endpoint route. */
|
|
293
|
+
status(..._args: unknown[]): never;
|
|
294
|
+
/** @deprecated Renamed — use `ctx.setHeader(name, value)`, which is valid from a `'use server'` action. */
|
|
295
|
+
header(..._args: unknown[]): never;
|
|
154
296
|
}
|
|
155
297
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* component or server action — the URL, cookies, params, env, and middleware
|
|
160
|
-
* variables. The returned wrapper is memoised per request, so repeated calls in
|
|
161
|
-
* the same request are cheap and return the same instance.
|
|
298
|
+
* The {@link RequestContext} for the current request — URL, cookies, params, env and middleware
|
|
299
|
+
* variables — read from a server component or a server action. Memoised per request, so repeated calls
|
|
300
|
+
* return the same instance.
|
|
162
301
|
*
|
|
163
|
-
* A
|
|
164
|
-
*
|
|
165
|
-
* action module — neither of which receives props from the framework.
|
|
302
|
+
* A page is handed that same object as its `ctx` prop, so this import is for everywhere else: a nested
|
|
303
|
+
* server component, or a `'use server'` action module.
|
|
166
304
|
*
|
|
167
|
-
* @typeParam E - The app's Hono {@link Env}, to type {@link
|
|
305
|
+
* @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and {@link RequestContext.env}.
|
|
168
306
|
* @throws If called at module load, where there is no ambient context to resolve.
|
|
169
307
|
* @throws If called while prerendering a `render: 'static'` route, which has no
|
|
170
308
|
* per-request context at build time — mark the route `render: 'dynamic'` instead.
|
|
@@ -172,78 +310,114 @@ export declare class Ctx<E extends Env = Env> {
|
|
|
172
310
|
* @example
|
|
173
311
|
* ```ts
|
|
174
312
|
* 'use server';
|
|
175
|
-
* import {
|
|
313
|
+
* import { getRequestContext, redirect } from '@rshono/core/server';
|
|
176
314
|
*
|
|
177
315
|
* export async function login(form: FormData) {
|
|
178
|
-
*
|
|
316
|
+
* getRequestContext().cookies.set('session', String(form.get('email')), { httpOnly: true });
|
|
179
317
|
* redirect('/dashboard');
|
|
180
318
|
* }
|
|
181
319
|
* ```
|
|
320
|
+
*
|
|
321
|
+
* @see {@link https://www.rshono.com/docs/api#rshonocoreserver | Docs — `@rshono/core/server`}
|
|
182
322
|
*/
|
|
183
|
-
export declare function
|
|
323
|
+
export declare function getRequestContext<E extends Env = Env>(): RequestContext<E>;
|
|
184
324
|
/**
|
|
185
|
-
* Redirects the request to `location
|
|
186
|
-
*
|
|
325
|
+
* Redirects the request to `location`, by throwing a control signal the framework turns into an HTTP
|
|
326
|
+
* redirect.
|
|
187
327
|
*
|
|
188
|
-
* Because it throws
|
|
189
|
-
*
|
|
190
|
-
* that swallows the signal.
|
|
328
|
+
* Because it throws it never returns, so TypeScript narrows away everything after the call and there
|
|
329
|
+
* is nothing to `return`. Don't wrap it in a `try/catch` that swallows the signal.
|
|
191
330
|
*
|
|
192
331
|
* @param location - Absolute path or URL to redirect to, e.g. `/dashboard`.
|
|
193
|
-
* @param status - Redirect {@link RedirectStatus}; defaults to `303` (See Other),
|
|
194
|
-
* the
|
|
332
|
+
* @param status - Redirect {@link RedirectStatus}; defaults to `303` (See Other), which is what makes
|
|
333
|
+
* the browser follow up with a `GET` after a form action.
|
|
195
334
|
*
|
|
196
335
|
* @example
|
|
197
336
|
* ```ts
|
|
198
|
-
* const session =
|
|
337
|
+
* const session = getRequestContext().cookies.get('session');
|
|
199
338
|
* if (!session) redirect('/login');
|
|
200
339
|
* // session is defined below this line
|
|
201
340
|
* ```
|
|
202
341
|
*/
|
|
203
342
|
export declare function redirect(location: string, status?: RedirectStatus): never;
|
|
204
343
|
/**
|
|
205
|
-
* Aborts the current render with a 404, rendering the app's
|
|
344
|
+
* Aborts the current render with a 404, rendering the app's `notFound` page.
|
|
206
345
|
*
|
|
207
|
-
* Like {@link redirect}
|
|
208
|
-
*
|
|
346
|
+
* Like {@link redirect} it throws a control signal and never returns, so TypeScript narrows away
|
|
347
|
+
* everything after the call. Don't catch-and-swallow it.
|
|
348
|
+
*
|
|
349
|
+
* **A real 404 status is only possible on a document load.** A soft navigation asks for a flight payload,
|
|
350
|
+
* and that response is committed as `200 text/x-component` the moment the render hands its stream back —
|
|
351
|
+
* before anything is awaited — so there is no shell to beat and calling this from the first line of a page
|
|
352
|
+
* is already too late. The signal still reaches the browser as a digest, and the client recovers by
|
|
353
|
+
* reloading the page for real: correct, but an extra round trip and a full document parse every time. Unlike
|
|
354
|
+
* {@link redirect}, which the same client turns into a soft navigation and which costs nothing. Where the
|
|
355
|
+
* status matters — a crawler, a monitor — decide in Hono middleware, ahead of the render.
|
|
209
356
|
*
|
|
210
357
|
* @example
|
|
211
358
|
* ```tsx
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
359
|
+
* export default async function Page({ params }: PageProps<'/users/:id'>) {
|
|
360
|
+
* const user = await db.user.find(params.id);
|
|
361
|
+
* if (!user) notFound();
|
|
362
|
+
* return <Profile user={user} />; // user is non-null here
|
|
363
|
+
* }
|
|
215
364
|
* ```
|
|
216
365
|
*/
|
|
217
366
|
export declare function notFound(): never;
|
|
218
367
|
/**
|
|
219
|
-
* Which stage of a request produced an error handed to
|
|
368
|
+
* Which stage of a request produced an error handed to a {@link ServerErrorHandler}.
|
|
220
369
|
*
|
|
221
370
|
* - `action` — a `'use server'` function threw. React sends the client an opaque marker with no
|
|
222
371
|
* message in production, so this is the only place the real error is visible.
|
|
223
372
|
* - `render` — a server component threw while the flight payload was being produced.
|
|
224
373
|
* - `ssr` — SSR failed before the HTML shell could be sent, so the `error` page was unreachable too.
|
|
225
|
-
* - `request` — anything else that reached the top-level handler,
|
|
374
|
+
* - `request` — anything else that reached the top-level handler, a thrown endpoint route included.
|
|
226
375
|
*/
|
|
227
376
|
export type ServerErrorSource = 'action' | 'render' | 'ssr' | 'request';
|
|
228
|
-
/**
|
|
229
|
-
|
|
377
|
+
/**
|
|
378
|
+
* What an {@link ServerErrorHandler} is told about an error, beyond the error itself.
|
|
379
|
+
*
|
|
380
|
+
* @typeParam E - The app's Hono {@link Env}, to type {@link ServerErrorContext.hono}'s `var` and `env`.
|
|
381
|
+
*/
|
|
382
|
+
export interface ServerErrorContext<E extends Env = Env> {
|
|
230
383
|
/** The stage that produced it — see {@link ServerErrorSource}. */
|
|
231
384
|
source: ServerErrorSource;
|
|
232
385
|
/** The request being served, for the URL, method and headers. */
|
|
233
386
|
request: Request;
|
|
387
|
+
/**
|
|
388
|
+
* The Hono {@link Context} for this request — `hono.var` for whatever middleware put there, such as a
|
|
389
|
+
* request id to correlate the report on, and `hono.env` for a platform that passes bindings.
|
|
390
|
+
*
|
|
391
|
+
* Handed over rather than left to {@link getRequestContext}, which a handler cannot reach: an error with
|
|
392
|
+
* `source: 'request'` is reported from the top-level handler, which runs outside the ambient context.
|
|
393
|
+
*/
|
|
394
|
+
hono: Context<E>;
|
|
395
|
+
/**
|
|
396
|
+
* Holds the invocation open until `promise` settles, where the platform has something to ask.
|
|
397
|
+
*
|
|
398
|
+
* Reporting is what this hook exists for, and on a serverless platform a report started here is cut off
|
|
399
|
+
* the moment the response ends unless something keeps the invocation alive. On Cloudflare Workers that is
|
|
400
|
+
* `executionCtx.waitUntil`, which this calls. On the `node` and `vercel` targets there is nothing to hold
|
|
401
|
+
* open — the process outlives the response — so it is a no-op and the report finishes on its own. On
|
|
402
|
+
* `aws-lambda` it is a no-op as well, because `hono/aws-lambda`'s streaming handler exposes no execution
|
|
403
|
+
* context to ask; a slow report there is best-effort, so prefer a tracker that batches over one that
|
|
404
|
+
* round-trips per error.
|
|
405
|
+
*
|
|
406
|
+
* A rejection is logged rather than propagated: reporting can never fail a request.
|
|
407
|
+
*/
|
|
408
|
+
waitUntil: (promise: Promise<unknown>) => void;
|
|
234
409
|
}
|
|
235
410
|
/** Handler registered with {@link onServerError}. Called for the side effect; its return value is ignored. */
|
|
236
|
-
export type ServerErrorHandler = (error: unknown, context: ServerErrorContext) => void;
|
|
411
|
+
export type ServerErrorHandler<E extends Env = Env> = (error: unknown, context: ServerErrorContext<E>) => void;
|
|
237
412
|
/**
|
|
238
413
|
* Registers a handler for every error the framework catches, so they can reach an error tracker
|
|
239
414
|
* (Sentry, Datadog, a log pipeline) instead of only `stderr`.
|
|
240
415
|
*
|
|
241
|
-
* Call it
|
|
242
|
-
*
|
|
416
|
+
* Call it once, at the top level of `src/server.ts`, which is imported as the server starts.
|
|
417
|
+
* Registering again replaces the previous handler. Errors still go to `stderr` either way, and a
|
|
418
|
+
* handler that throws is caught and logged — reporting can never fail a request.
|
|
243
419
|
*
|
|
244
|
-
*
|
|
245
|
-
* replacing one. A handler that throws is caught and logged: reporting must never be able to fail
|
|
246
|
-
* a request.
|
|
420
|
+
* @typeParam E - The app's Hono {@link Env}, to type the `hono` context the handler is given.
|
|
247
421
|
*
|
|
248
422
|
* @example
|
|
249
423
|
* ```ts
|
|
@@ -251,21 +425,28 @@ export type ServerErrorHandler = (error: unknown, context: ServerErrorContext) =
|
|
|
251
425
|
* import * as Sentry from '@sentry/node';
|
|
252
426
|
* import { onServerError } from '@rshono/core/server';
|
|
253
427
|
*
|
|
254
|
-
* onServerError((error, { source, request }) => {
|
|
255
|
-
*
|
|
428
|
+
* onServerError((error, { source, request, hono, waitUntil }) => {
|
|
429
|
+
* // `waitUntil` so a serverless invocation is not frozen before the report is sent.
|
|
430
|
+
* waitUntil(
|
|
431
|
+
* Sentry.captureException(error, {
|
|
432
|
+
* tags: { source, requestId: hono.var.requestId },
|
|
433
|
+
* extra: { url: request.url },
|
|
434
|
+
* }),
|
|
435
|
+
* );
|
|
256
436
|
* });
|
|
257
437
|
* ```
|
|
438
|
+
*
|
|
439
|
+
* @see {@link https://www.rshono.com/docs/hono#error-reporting | Docs — error reporting}
|
|
258
440
|
*/
|
|
259
|
-
export declare function onServerError(handler: ServerErrorHandler): void;
|
|
441
|
+
export declare function onServerError<E extends Env = Env>(handler: ServerErrorHandler<E>): void;
|
|
260
442
|
/**
|
|
261
|
-
* Logs an error and forwards it to the registered {@link ServerErrorHandler}
|
|
262
|
-
*
|
|
263
|
-
* Framework internal — the single funnel every caught server-side error goes through, so that
|
|
264
|
-
* adding a reporting destination is one registration rather than a hook per call site.
|
|
443
|
+
* Logs an error and forwards it to the registered {@link ServerErrorHandler} — the single funnel every
|
|
444
|
+
* caught server-side error goes through.
|
|
265
445
|
*
|
|
266
446
|
* @internal
|
|
267
447
|
*/
|
|
268
|
-
export declare function reportServerError(error: unknown, info:
|
|
448
|
+
export declare function reportServerError(error: unknown, info: {
|
|
449
|
+
source: ServerErrorSource;
|
|
450
|
+
hono: Context;
|
|
269
451
|
message: string;
|
|
270
452
|
}): void;
|
|
271
|
-
//# sourceMappingURL=context.d.ts.map
|