@rivetjs/router 0.0.0-stage → 0.1.0-alpha.0
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 +10 -2
- package/adapters/assemble.d.ts +32 -0
- package/adapters/assemble.js +32 -0
- package/adapters/build.d.ts +24 -0
- package/adapters/build.js +43 -0
- package/adapters/bun.d.ts +18 -0
- package/adapters/bun.js +44 -0
- package/adapters/cloudflare.d.ts +5 -0
- package/adapters/cloudflare.js +8 -0
- package/adapters/cluster.d.ts +7 -0
- package/adapters/cluster.js +130 -0
- package/adapters/csr.d.ts +12 -0
- package/adapters/csr.js +11 -0
- package/adapters/deno.d.ts +13 -0
- package/adapters/deno.js +35 -0
- package/adapters/fetch.d.ts +55 -0
- package/adapters/fetch.js +72 -0
- package/adapters/files.d.ts +7 -0
- package/adapters/files.js +103 -0
- package/adapters/idle-memory.d.ts +23 -0
- package/adapters/idle-memory.js +91 -0
- package/adapters/netlify.d.ts +13 -0
- package/adapters/netlify.js +15 -0
- package/adapters/node.d.ts +163 -0
- package/adapters/node.js +940 -0
- package/adapters/pack.d.ts +39 -0
- package/adapters/pack.js +360 -0
- package/adapters/server-target.d.ts +17 -0
- package/adapters/server-target.js +8 -0
- package/adapters/static.d.ts +84 -0
- package/adapters/static.js +231 -0
- package/adapters/target-build.d.ts +92 -0
- package/adapters/target-build.js +118 -0
- package/adapters/vercel-edge.d.ts +7 -0
- package/adapters/vercel-edge.js +9 -0
- package/adapters/vercel.d.ts +33 -0
- package/adapters/vercel.js +45 -0
- package/build/codegen.d.ts +84 -0
- package/build/codegen.js +920 -0
- package/build/dev-errors.d.ts +19 -0
- package/build/dev-errors.js +236 -0
- package/build/migrate.d.ts +15 -0
- package/build/migrate.js +146 -0
- package/build/route-css.d.ts +54 -0
- package/build/route-css.js +216 -0
- package/build/routes.d.ts +50 -0
- package/build/routes.js +202 -0
- package/build/sync.d.ts +20 -0
- package/build/sync.js +16 -0
- package/build/vite.d.ts +195 -0
- package/build/vite.js +703 -0
- package/cli/rivet.d.ts +2 -0
- package/cli/rivet.js +100 -0
- package/client/active.d.ts +6 -0
- package/client/active.js +22 -0
- package/client/announce.d.ts +2 -0
- package/client/announce.js +21 -0
- package/client/dev.d.ts +41 -0
- package/client/dev.js +74 -0
- package/client/index.d.ts +152 -0
- package/client/index.js +680 -0
- package/client/layouts.d.ts +110 -0
- package/client/layouts.js +310 -0
- package/client/leave.d.ts +40 -0
- package/client/leave.js +75 -0
- package/client/link.d.ts +48 -0
- package/client/link.jsx +65 -0
- package/client/live.d.ts +57 -0
- package/client/live.js +170 -0
- package/client/navigate.d.ts +71 -0
- package/client/navigate.js +120 -0
- package/client/navigation.d.ts +28 -0
- package/client/navigation.js +14 -0
- package/client/params.d.ts +16 -0
- package/client/params.js +28 -0
- package/client/route-context.d.ts +32 -0
- package/client/route-context.js +21 -0
- package/client/scroll.d.ts +16 -0
- package/client/scroll.js +80 -0
- package/client/search.d.ts +8 -0
- package/client/search.js +17 -0
- package/client/tailwind.css +8 -0
- package/client/transition-helpers.d.ts +28 -0
- package/client/transition-helpers.js +63 -0
- package/client/transitions.css +90 -0
- package/client/transitions.d.ts +21 -0
- package/client/transitions.js +156 -0
- package/index.d.ts +138 -0
- package/index.js +7 -0
- package/package.json +156 -4
- package/server/app.d.ts +169 -0
- package/server/app.js +302 -0
- package/server/body.d.ts +20 -0
- package/server/body.js +8 -0
- package/server/early-hints.d.ts +34 -0
- package/server/early-hints.js +63 -0
- package/server/handler.d.ts +196 -0
- package/server/handler.js +623 -0
- package/server/index.d.ts +9 -0
- package/server/index.js +6 -0
- package/server/inline-styles.d.ts +21 -0
- package/server/inline-styles.js +28 -0
- package/server/module.d.ts +14 -0
- package/server/module.js +78 -0
- package/server/render.d.ts +94 -0
- package/server/render.js +489 -0
- package/server/route-cache.d.ts +175 -0
- package/server/route-cache.js +742 -0
- package/server/security.d.ts +18 -0
- package/server/security.js +47 -0
- package/server/strict-csp.d.ts +7 -0
- package/server/strict-csp.js +18 -0
- package/server-only.d.ts +1 -0
- package/server-only.js +3 -0
- package/shared/actions.d.ts +10 -0
- package/shared/actions.js +18 -0
- package/shared/base.d.ts +8 -0
- package/shared/base.js +20 -0
- package/shared/cookie.d.ts +7 -0
- package/shared/cookie.js +32 -0
- package/shared/csp-directives.d.ts +9 -0
- package/shared/csp-directives.js +85 -0
- package/shared/csp-hash.d.ts +39 -0
- package/shared/csp-hash.js +121 -0
- package/shared/csp.d.ts +26 -0
- package/shared/csp.js +13 -0
- package/shared/data.d.ts +175 -0
- package/shared/data.js +22 -0
- package/shared/errors.d.ts +31 -0
- package/shared/errors.js +51 -0
- package/shared/head.d.ts +57 -0
- package/shared/head.js +242 -0
- package/shared/nonce.d.ts +2 -0
- package/shared/nonce.js +23 -0
- package/shared/prefetch-fallback.min.d.ts +1 -0
- package/shared/prefetch-fallback.min.js +2 -0
- package/shared/prefetch.d.ts +54 -0
- package/shared/prefetch.js +74 -0
- package/shared/redirect.d.ts +6 -0
- package/shared/redirect.js +25 -0
- package/shared/slash.d.ts +8 -0
- package/shared/slash.js +24 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Head } from "../shared/data.js";
|
|
2
|
+
/** `createApp({ earlyHints })`. */
|
|
3
|
+
export interface EarlyHintsOptions {
|
|
4
|
+
/** Also hint the resume runtime entry (`rel=modulepreload`): pages that start it early (visible preloads). Default false. */
|
|
5
|
+
readonly runtime?: boolean;
|
|
6
|
+
/** Extra `Link` values sent as given, e.g. `"<https://cdn.example>; rel=preconnect"`. */
|
|
7
|
+
readonly links?: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
/** Registered symbol: a per-request `(links) => void` the node adapter puts on the Request it builds (one writer of 103s). */
|
|
10
|
+
export declare const EARLY_HINTS: unique symbol;
|
|
11
|
+
export type HintWriter = (links: readonly string[]) => void;
|
|
12
|
+
/** Whether `url` is a build asset below `base` (hashed file name, served immutable). */
|
|
13
|
+
export declare const isAsset: (url: string, base: string) => boolean;
|
|
14
|
+
/** `<url>; rel=preload; as=style` per linked (not inlined) build-asset stylesheet. */
|
|
15
|
+
export declare function styleLinks(urls: readonly string[], inline: Readonly<Record<string, string>> | undefined, base?: string): string[];
|
|
16
|
+
/**
|
|
17
|
+
* Build-asset font preloads of a merged head: build files are the same for every visitor; anything else in a head may
|
|
18
|
+
* come from loader data (preconnects, images) and is left out.
|
|
19
|
+
*/
|
|
20
|
+
export declare function headLinks(head: Head | undefined, base?: string): string[];
|
|
21
|
+
/** Per route id: its `Link` values, re-derived when the learned head links change. */
|
|
22
|
+
export interface Hinter {
|
|
23
|
+
links(routeId: string): readonly string[];
|
|
24
|
+
/** A render's merged head: its build-asset font preloads become the route's from now on. */
|
|
25
|
+
learn(routeId: string, head: Head | undefined): void;
|
|
26
|
+
}
|
|
27
|
+
/** `createApp`'s hinter: `styles` + the route's `routeStyles` (not inlined), learned head links, `links`, the runtime. */
|
|
28
|
+
export declare function createHinter(option: true | EarlyHintsOptions, app: {
|
|
29
|
+
readonly styles: readonly string[];
|
|
30
|
+
readonly routeStyles?: Readonly<Record<string, readonly string[]>> | ((routeId: string) => unknown);
|
|
31
|
+
readonly inlineFor?: (list: readonly string[]) => Readonly<Record<string, string>> | undefined;
|
|
32
|
+
readonly base: string;
|
|
33
|
+
readonly runtime?: string | undefined;
|
|
34
|
+
}): Hinter;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Registered symbol: a per-request `(links) => void` the node adapter puts on the Request it builds (one writer of 103s). */
|
|
2
|
+
export const EARLY_HINTS = Symbol.for("rivet.earlyHints");
|
|
3
|
+
// A URL written into a header value: no whitespace / controls, nothing that ends the `<…>` or splits the list.
|
|
4
|
+
const SAFE = /^[^\s\0-\x1f\x7f<>"',;\\]+$/;
|
|
5
|
+
const TOKEN = /^[\w./+-]+$/;
|
|
6
|
+
/** Whether `url` is a build asset below `base` (hashed file name, served immutable). */
|
|
7
|
+
export const isAsset = (url, base) => url.startsWith(base + "/assets/");
|
|
8
|
+
/** `<url>; rel=preload; as=style` per linked (not inlined) build-asset stylesheet. */
|
|
9
|
+
export function styleLinks(urls, inline, base = "") {
|
|
10
|
+
const out = [];
|
|
11
|
+
for (const url of urls)
|
|
12
|
+
if (!(inline && Object.hasOwn(inline, url)) && SAFE.test(url) && isAsset(url, base))
|
|
13
|
+
out.push(`<${url}>; rel=preload; as=style`);
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build-asset font preloads of a merged head: build files are the same for every visitor; anything else in a head may
|
|
18
|
+
* come from loader data (preconnects, images) and is left out.
|
|
19
|
+
*/
|
|
20
|
+
export function headLinks(head, base = "") {
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const link of head?.links ?? []) {
|
|
23
|
+
const value = linkValue(link, base);
|
|
24
|
+
if (value)
|
|
25
|
+
out.push(value);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function linkValue(link, base) {
|
|
30
|
+
if (!SAFE.test(link.href))
|
|
31
|
+
return undefined;
|
|
32
|
+
const rel = link.rel.toLowerCase();
|
|
33
|
+
const cors = link.crossorigin === "use-credentials" ? "; crossorigin=use-credentials" : link.crossorigin ? "; crossorigin" : "";
|
|
34
|
+
if (rel === "preload" && link.as === "font" && isAsset(link.href, base))
|
|
35
|
+
return `<${link.href}>; rel=preload; as=font${link.type && TOKEN.test(link.type) ? "; type=" + link.type : ""}${cors}`;
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
/** `createApp`'s hinter: `styles` + the route's `routeStyles` (not inlined), learned head links, `links`, the runtime. */
|
|
39
|
+
export function createHinter(option, app) {
|
|
40
|
+
const extra = option === true
|
|
41
|
+
? []
|
|
42
|
+
: [...(option.links ?? []), ...(option.runtime && app.runtime && SAFE.test(app.runtime) ? [`<${app.runtime}>; rel=modulepreload`] : [])];
|
|
43
|
+
const learned = new Map();
|
|
44
|
+
const memo = new Map();
|
|
45
|
+
return {
|
|
46
|
+
links(routeId) {
|
|
47
|
+
let links = memo.get(routeId);
|
|
48
|
+
if (links)
|
|
49
|
+
return links;
|
|
50
|
+
const own = app.routeStyles && typeof app.routeStyles !== "function" ? app.routeStyles[routeId] : undefined;
|
|
51
|
+
const list = own?.length ? [...app.styles, ...own] : app.styles;
|
|
52
|
+
const head = learned.get(routeId);
|
|
53
|
+
links = [...styleLinks(list, app.inlineFor?.(list), app.base), ...(head ? head.split("\n") : []), ...extra];
|
|
54
|
+
memo.set(routeId, links);
|
|
55
|
+
return links;
|
|
56
|
+
},
|
|
57
|
+
learn(routeId, head) {
|
|
58
|
+
const value = headLinks(head, app.base).join("\n");
|
|
59
|
+
if (value !== (learned.get(routeId) ?? ""))
|
|
60
|
+
(value ? learned.set(routeId, value) : learned.delete(routeId), memo.delete(routeId));
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { type ActionResult, type Head, type LoaderDeps } from "../shared/data.js";
|
|
2
|
+
export { DATA_PARAM, type ActionResult } from "../shared/data.js";
|
|
3
|
+
import { type BodyLimit } from "./security.js";
|
|
4
|
+
export type { BodyLimit } from "./security.js";
|
|
5
|
+
import type { RouteId, RouteParams } from "../index.js";
|
|
6
|
+
/** Cookie access for one request; `set`/`delete` append `Set-Cookie` to the response. */
|
|
7
|
+
export interface Cookies {
|
|
8
|
+
get(name: string): string | undefined;
|
|
9
|
+
/** Every request cookie (with this request's `set`/`delete` applied), in header order. */
|
|
10
|
+
getAll(): {
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
}[];
|
|
14
|
+
set(name: string, value: string, options?: CookieOptions): void;
|
|
15
|
+
delete(name: string, options?: Pick<CookieOptions, "path" | "domain">): void;
|
|
16
|
+
}
|
|
17
|
+
/** Cookie attributes of `cookies.set()`. */
|
|
18
|
+
export interface CookieOptions {
|
|
19
|
+
path?: string;
|
|
20
|
+
domain?: string;
|
|
21
|
+
maxAge?: number;
|
|
22
|
+
expires?: Date;
|
|
23
|
+
httpOnly?: boolean;
|
|
24
|
+
secure?: boolean;
|
|
25
|
+
sameSite?: "lax" | "strict" | "none";
|
|
26
|
+
}
|
|
27
|
+
/** What guards, loaders, actions and endpoints receive. `locals` is shared along one request's chain. */
|
|
28
|
+
/** `RequestEvent<"items/[id]">`: params of a file route id (`RouteParams`, generated). */
|
|
29
|
+
export interface RequestEvent<P extends Record<string, string> | RouteId = Record<string, string>> {
|
|
30
|
+
readonly request: Request;
|
|
31
|
+
readonly url: URL;
|
|
32
|
+
readonly params: Readonly<P extends RouteId ? RouteParams[P] : P>;
|
|
33
|
+
readonly locals: Record<string, unknown>;
|
|
34
|
+
readonly signal: AbortSignal;
|
|
35
|
+
readonly cookies: Cookies;
|
|
36
|
+
/** The handler runs in development (`dev` option); undefined when unknown (treat as production). */
|
|
37
|
+
readonly dev?: boolean;
|
|
38
|
+
/** Set a response header (HTML, data and action responses alike). */
|
|
39
|
+
setHeader(name: string, value: string): void;
|
|
40
|
+
/** Set several response headers; `set-cookie` is rejected (use `cookies.set`). */
|
|
41
|
+
setHeaders(headers: Readonly<Record<string, string>>): void;
|
|
42
|
+
/** The matched route (`id`: file route id, e.g. `blog/[slug]`); `null` for unmatched URLs. */
|
|
43
|
+
readonly route: {
|
|
44
|
+
readonly id: string | null;
|
|
45
|
+
};
|
|
46
|
+
/** A client-navigation data request (`?_rivet=data`, answered with JSON), not a document request. */
|
|
47
|
+
readonly isDataRequest: boolean;
|
|
48
|
+
/** What the adapter knows about the connection (node: `clientAddress`). */
|
|
49
|
+
readonly platform: Platform;
|
|
50
|
+
/**
|
|
51
|
+
* Loaders: name what this loader's data depends on (strings; a `URL` counts as its `href`), so
|
|
52
|
+
* `invalidate(key)` in the browser reruns only the loaders that depend on `key`. Any time during
|
|
53
|
+
* the loader; repeats are ignored. Elsewhere (guards, actions, handlers) it does nothing.
|
|
54
|
+
*/
|
|
55
|
+
depends(...keys: readonly (string | URL)[]): void;
|
|
56
|
+
}
|
|
57
|
+
/** Adapter-provided request facts (`event.platform`). */
|
|
58
|
+
export interface Platform {
|
|
59
|
+
/** Client IP address (node adapter: the socket's, or `X-Forwarded-For`'s first with `trustProxy`). */
|
|
60
|
+
readonly clientAddress?: string;
|
|
61
|
+
readonly [key: string]: unknown;
|
|
62
|
+
}
|
|
63
|
+
type Result = unknown;
|
|
64
|
+
type Handler = (event: RequestEvent) => Response | undefined | void | Promise<Response | undefined | void>;
|
|
65
|
+
/**
|
|
66
|
+
* A route's or layout's server exports, normalized: in-file `serverLoad`… arrive here as `load`…
|
|
67
|
+
* (sibling `*.server.ts` modules may still use the old names). `onRequest` and `on<Method>` request
|
|
68
|
+
* handlers run outermost first before guards; a returned `Response` ends the request.
|
|
69
|
+
*/
|
|
70
|
+
export interface ServerModule {
|
|
71
|
+
onRequest?: Handler;
|
|
72
|
+
onGet?: Handler;
|
|
73
|
+
onPost?: Handler;
|
|
74
|
+
onPut?: Handler;
|
|
75
|
+
onPatch?: Handler;
|
|
76
|
+
onDelete?: Handler;
|
|
77
|
+
/** OPTIONS (CORS preflight): after `onRequest`, outer → inner, the route's own module included; void → 204 + `Allow`. */
|
|
78
|
+
onOptions?: Handler;
|
|
79
|
+
guard?(event: RequestEvent): Result | Promise<Result>;
|
|
80
|
+
load?(event: RequestEvent): Result | Promise<Result>;
|
|
81
|
+
entries?(): Iterable<Record<string, string>> | Promise<Iterable<Record<string, string>>>;
|
|
82
|
+
prerender?: boolean;
|
|
83
|
+
/** `false` (route module only): skip the cross-site check for this route's unsafe methods (webhooks). */
|
|
84
|
+
csrf?: boolean;
|
|
85
|
+
actions?: Record<string, (event: RequestEvent) => Result | Promise<Result>>;
|
|
86
|
+
headers?(event: RequestEvent): HeadersInit | undefined;
|
|
87
|
+
GET?(event: RequestEvent): Response | Promise<Response>;
|
|
88
|
+
POST?(event: RequestEvent): Response | Promise<Response>;
|
|
89
|
+
PUT?(event: RequestEvent): Response | Promise<Response>;
|
|
90
|
+
PATCH?(event: RequestEvent): Response | Promise<Response>;
|
|
91
|
+
DELETE?(event: RequestEvent): Response | Promise<Response>;
|
|
92
|
+
}
|
|
93
|
+
type Load<T> = () => Promise<T>;
|
|
94
|
+
/** One generated route-table entry. */
|
|
95
|
+
export interface AppRoute {
|
|
96
|
+
readonly id: string;
|
|
97
|
+
readonly pattern: string;
|
|
98
|
+
/** Server modules of the enclosing layouts, outermost first (undefined: layout has none). */
|
|
99
|
+
readonly layouts: readonly (Load<ServerModule> | undefined)[];
|
|
100
|
+
readonly server?: Load<ServerModule>;
|
|
101
|
+
/** False for endpoint-only routes (a `.server.ts` without a page). */
|
|
102
|
+
readonly page: boolean;
|
|
103
|
+
/** Layout ids (`/` + folder path: `/`, `/shop`), parallel to `layouts`: data requests may skip the loaders of kept ones. */
|
|
104
|
+
readonly keys?: readonly string[];
|
|
105
|
+
}
|
|
106
|
+
/** Everything a renderer needs for one page. `data` holds layout data then page data. */
|
|
107
|
+
export interface RenderInput {
|
|
108
|
+
readonly request: Request;
|
|
109
|
+
readonly url: URL;
|
|
110
|
+
readonly route: AppRoute;
|
|
111
|
+
readonly params: Readonly<Record<string, string>>;
|
|
112
|
+
readonly data: readonly unknown[];
|
|
113
|
+
readonly status: number;
|
|
114
|
+
readonly headers: Headers;
|
|
115
|
+
readonly nonce: string | undefined;
|
|
116
|
+
readonly action: ActionResult | undefined;
|
|
117
|
+
readonly locals: Record<string, unknown>;
|
|
118
|
+
/** Merged head (layouts → page) from `head` exports. */
|
|
119
|
+
readonly head: Head | undefined;
|
|
120
|
+
/** Layouts (indices into `data`) whose loader read the request URL: their data follows every URL change. */
|
|
121
|
+
readonly byURL?: readonly number[];
|
|
122
|
+
/** Keys the loaders passed to `event.depends()` (index into `data`); absent when none called it. */
|
|
123
|
+
readonly deps?: LoaderDeps;
|
|
124
|
+
}
|
|
125
|
+
/** What the error renderer receives: request, matched route, status and a user-safe message. */
|
|
126
|
+
export interface ErrorInput {
|
|
127
|
+
readonly request: Request;
|
|
128
|
+
readonly url: URL;
|
|
129
|
+
/** Matched route (undefined for unmatched URLs). */
|
|
130
|
+
readonly route: AppRoute | undefined;
|
|
131
|
+
readonly status: number;
|
|
132
|
+
/** User-safe message: the HttpError's for 4xx, generic for 5xx outside dev. */
|
|
133
|
+
readonly message: string;
|
|
134
|
+
readonly headers: Headers;
|
|
135
|
+
readonly nonce: string | undefined;
|
|
136
|
+
/** The request's `locals` as guards/loaders left them (empty when no guard ran, e.g. unmatched URLs). */
|
|
137
|
+
readonly locals: Record<string, unknown>;
|
|
138
|
+
/**
|
|
139
|
+
* Data of the outermost layouts the error page renders inside (route data order): those whose guards
|
|
140
|
+
* passed and whose loaders succeeded, up to the first that did not. Unmatched URLs: the root layout's.
|
|
141
|
+
*/
|
|
142
|
+
readonly layouts?: readonly unknown[];
|
|
143
|
+
}
|
|
144
|
+
/** Options of the app handler: routes, renderers, head and dev flags. */
|
|
145
|
+
export interface AppOptions {
|
|
146
|
+
readonly routes: readonly AppRoute[];
|
|
147
|
+
render(input: RenderInput): Response | Promise<Response>;
|
|
148
|
+
renderError?(input: ErrorInput): Response | Promise<Response>;
|
|
149
|
+
/** Merged head for a route from its universal modules' `head` exports. */
|
|
150
|
+
head?(route: AppRoute, data: readonly unknown[], match: {
|
|
151
|
+
params: Readonly<Record<string, string>>;
|
|
152
|
+
url: URL;
|
|
153
|
+
}): Head | undefined | Promise<Head | undefined>;
|
|
154
|
+
/** Show 5xx messages (never in production). */
|
|
155
|
+
readonly dev?: boolean;
|
|
156
|
+
/** Server failures; `digest` is also in the (otherwise generic) 5xx message the client sees. */
|
|
157
|
+
onError?(error: unknown, request: Request, info?: ErrorInfo): void;
|
|
158
|
+
/** Request body limit in bytes for unsafe methods (413 past it). Default 1 MiB, multipart 10 MiB. */
|
|
159
|
+
readonly maxBody?: BodyLimit;
|
|
160
|
+
/**
|
|
161
|
+
* URL of the resume manifest's `builtins` chunk (RegExp / URLSearchParams / binary / error decoders): data and action
|
|
162
|
+
* answers holding such values name it (`x`), the client imports it before decoding. Without it they fail to decode.
|
|
163
|
+
*/
|
|
164
|
+
builtins?(): string | undefined;
|
|
165
|
+
/** Data requests: per layout of `route`, whether its loader may be skipped when the client keeps its data (default all). */
|
|
166
|
+
keepable?(route: AppRoute): readonly boolean[] | undefined | Promise<readonly boolean[] | undefined>;
|
|
167
|
+
/**
|
|
168
|
+
* Called once per HTML page GET / HEAD (no data request, no action) after the request handlers and before the guards
|
|
169
|
+
* and loaders: the moment a server can send `103 Early Hints` while it is still busy (`createApp({ earlyHints })`).
|
|
170
|
+
*/
|
|
171
|
+
earlyHints?(route: AppRoute, request: Request): void;
|
|
172
|
+
}
|
|
173
|
+
/** Where a server failure happened: request handler (`onRequest`/`on<Method>`/endpoint, module load), guard, loader, action or page render. */
|
|
174
|
+
export type ErrorPhase = "handler" | "guard" | "loader" | "action" | "render";
|
|
175
|
+
/** `onError` details of a reported (5xx) failure. */
|
|
176
|
+
export interface ErrorInfo {
|
|
177
|
+
readonly digest: string;
|
|
178
|
+
readonly phase?: ErrorPhase;
|
|
179
|
+
/** Matched route id. */
|
|
180
|
+
readonly route?: string;
|
|
181
|
+
}
|
|
182
|
+
/** @internal Short random id tying a hidden 5xx message to its server log entry. */
|
|
183
|
+
export declare const _digest: () => string;
|
|
184
|
+
/** The app's web-standard request handler. */
|
|
185
|
+
export type AppHandler = (request: Request, context?: {
|
|
186
|
+
nonce?: string;
|
|
187
|
+
address?: string;
|
|
188
|
+
platform?: Platform;
|
|
189
|
+
}) => Promise<Response>;
|
|
190
|
+
/**
|
|
191
|
+
* Encode a value with the resume table (Date/Map/Set/BigInt/undefined/cycles survive). With built-in entries (RegExp /
|
|
192
|
+
* URLSearchParams / binary / errors) and a `builtins` chunk URL, `x` names it: the client imports it before decoding.
|
|
193
|
+
*/
|
|
194
|
+
export declare function encodeData(value: unknown, builtins?: string, origin?: string): string;
|
|
195
|
+
/** Create the app's request handler. */
|
|
196
|
+
export declare function createHandler(options: AppOptions): AppHandler;
|