@rivetjs/router 0.0.0-stage → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +20 -0
- package/adapters/files.js +155 -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 +180 -0
- package/adapters/node.js +986 -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 +95 -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 +35 -0
- package/adapters/vercel.js +45 -0
- package/build/codegen.d.ts +97 -0
- package/build/codegen.js +1037 -0
- package/build/dev-errors.d.ts +23 -0
- package/build/dev-errors.js +247 -0
- package/build/lazy-rows.d.ts +19 -0
- package/build/lazy-rows.js +59 -0
- package/build/migrate.d.ts +31 -0
- package/build/migrate.js +385 -0
- package/build/reach.d.ts +60 -0
- package/build/reach.js +302 -0
- package/build/route-css.d.ts +54 -0
- package/build/route-css.js +216 -0
- package/build/routes.d.ts +55 -0
- package/build/routes.js +219 -0
- package/build/sync.d.ts +20 -0
- package/build/sync.js +16 -0
- package/build/vite.d.ts +208 -0
- package/build/vite.js +861 -0
- package/cli/rivet.d.ts +2 -0
- package/cli/rivet.js +101 -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 +91 -0
- package/client/index.d.ts +156 -0
- package/client/index.js +714 -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 +135 -0
- package/index.js +8 -0
- package/package.json +156 -4
- package/server/app.d.ts +175 -0
- package/server/app.js +335 -0
- package/server/body.d.ts +20 -0
- package/server/body.js +8 -0
- package/server/deferred.d.ts +12 -0
- package/server/deferred.js +60 -0
- package/server/early-hints.d.ts +34 -0
- package/server/early-hints.js +63 -0
- package/server/handler.d.ts +240 -0
- package/server/handler.js +661 -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 +96 -0
- package/server/render.d.ts +96 -0
- package/server/render.js +492 -0
- package/server/route-cache.d.ts +245 -0
- package/server/route-cache.js +813 -0
- package/server/security.d.ts +18 -0
- package/server/security.js +47 -0
- package/server/shell-build.d.ts +3 -0
- package/server/shell-build.js +2 -0
- package/server/shell-cache.d.ts +8 -0
- package/server/shell-cache.js +836 -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/server-exports.d.ts +78 -0
- package/shared/server-exports.js +77 -0
- package/shared/slash.d.ts +8 -0
- package/shared/slash.js +24 -0
|
@@ -0,0 +1,240 @@
|
|
|
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 by tag (`server/module.ts`): each key is the kind of
|
|
67
|
+
* the wrapper that made the export (`export const loader = load(…)` arrives as `load`). `onRequest` and
|
|
68
|
+
* `on<Method>` request 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
|
+
}
|
|
88
|
+
type Load<T> = () => Promise<T>;
|
|
89
|
+
/** One generated route-table entry. */
|
|
90
|
+
export interface AppRoute {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly pattern: string;
|
|
93
|
+
/** Server modules of the enclosing layouts, outermost first (undefined: layout has none). */
|
|
94
|
+
readonly layouts: readonly (Load<ServerModule> | undefined)[];
|
|
95
|
+
readonly server?: Load<ServerModule>;
|
|
96
|
+
/** False for endpoint-only routes (a `.server.ts` without a page). */
|
|
97
|
+
readonly page: boolean;
|
|
98
|
+
/** Layout ids (`/` + folder path: `/`, `/shop`), parallel to `layouts`: data requests may skip the loaders of kept ones. */
|
|
99
|
+
readonly keys?: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
/** Everything a renderer needs for one page. `data` holds layout data then page data. */
|
|
102
|
+
export interface RenderInput {
|
|
103
|
+
readonly request: Request;
|
|
104
|
+
readonly url: URL;
|
|
105
|
+
readonly route: AppRoute;
|
|
106
|
+
readonly params: Readonly<Record<string, string>>;
|
|
107
|
+
readonly data: readonly unknown[];
|
|
108
|
+
readonly status: number;
|
|
109
|
+
readonly headers: Headers;
|
|
110
|
+
readonly nonce: string | undefined;
|
|
111
|
+
readonly action: ActionResult | undefined;
|
|
112
|
+
readonly locals: Record<string, unknown>;
|
|
113
|
+
/** Merged head (layouts → page) from `head` exports. */
|
|
114
|
+
readonly head: Head | undefined;
|
|
115
|
+
/** Set when a `data` slot is a deferred loader's `Deferred` handle (`load(fn, { defer: true })`): the page streams. */
|
|
116
|
+
readonly deferred?: true;
|
|
117
|
+
/**
|
|
118
|
+
* A deferred loader's `redirect()` (same origin, or `{ external: true }`): its first target, read when the document
|
|
119
|
+
* ends — the status is long sent, so the page navigates there in the browser (`location.replace`).
|
|
120
|
+
*/
|
|
121
|
+
readonly moved?: () => string | undefined;
|
|
122
|
+
/** @internal Route rule `shell` (`shell-cache.ts`): this render fills or replays a stored shell (always streams). */
|
|
123
|
+
readonly shell?: ShellPhase;
|
|
124
|
+
/** Layouts (indices into `data`) whose loader read the request URL: their data follows every URL change. */
|
|
125
|
+
readonly byURL?: readonly number[];
|
|
126
|
+
/** Keys the loaders passed to `event.depends()` (index into `data`); absent when none called it. */
|
|
127
|
+
readonly deps?: LoaderDeps;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @internal Route rule `shell` (`server/shell-cache.ts`): the route rules wrapper sets it on a document GET's Request
|
|
131
|
+
* (`SHELL`). After the guards and `headers()` the handler asks it how to load: a hit's stored shell data (the composed
|
|
132
|
+
* response already went out with the stored shell), a fill's read tracking, or nothing (render as usual).
|
|
133
|
+
*/
|
|
134
|
+
export interface ShellRequest {
|
|
135
|
+
begin(route: AppRoute, event: RequestEvent, headers: Headers): ShellPhase | undefined;
|
|
136
|
+
}
|
|
137
|
+
/** @internal One shell render (fill or hit replay). */
|
|
138
|
+
export interface ShellPhase {
|
|
139
|
+
/** Hit: the fill's non-deferred loader results (those loaders are skipped) and URL / depends facts. */
|
|
140
|
+
readonly data?: readonly unknown[];
|
|
141
|
+
readonly byURL?: readonly number[];
|
|
142
|
+
readonly deps?: LoaderDeps;
|
|
143
|
+
/** Fill: a non-deferred loader's event view that records its request reads. */
|
|
144
|
+
event?(view: RequestEvent, index: number): RequestEvent;
|
|
145
|
+
/** Fill: the non-deferred loaders' results (deferred slots undefined), stored with the shell. */
|
|
146
|
+
loaded?(data: readonly unknown[], byURL: readonly number[], deps: LoaderDeps | undefined): void;
|
|
147
|
+
/** Fill: a deferred slot's handle (delivers only after the shell is out: in-order use is detected). */
|
|
148
|
+
handle?(promise: Promise<unknown>, dev: boolean): object;
|
|
149
|
+
/** Fill: the page's URL for the render (named query reads outside the key recorded). */
|
|
150
|
+
readonly url?: URL;
|
|
151
|
+
/** Set by `app.ts`: this render does not stream (dev `devResume` check mode), deferred data waits in place. */
|
|
152
|
+
plain?: boolean;
|
|
153
|
+
}
|
|
154
|
+
/** @internal Request property carrying a `ShellRequest` (`Symbol.for("rivet.shell")`). */
|
|
155
|
+
export declare const SHELL: unique symbol;
|
|
156
|
+
/** What the error renderer receives: request, matched route, status and a user-safe message. */
|
|
157
|
+
export interface ErrorInput {
|
|
158
|
+
readonly request: Request;
|
|
159
|
+
readonly url: URL;
|
|
160
|
+
/** Matched route (undefined for unmatched URLs). */
|
|
161
|
+
readonly route: AppRoute | undefined;
|
|
162
|
+
readonly status: number;
|
|
163
|
+
/** User-safe message: the HttpError's for 4xx, generic for 5xx outside dev. */
|
|
164
|
+
readonly message: string;
|
|
165
|
+
readonly headers: Headers;
|
|
166
|
+
readonly nonce: string | undefined;
|
|
167
|
+
/** The request's `locals` as guards/loaders left them (only the handler's seed, `context.locals`, when no guard ran, e.g. unmatched URLs). */
|
|
168
|
+
readonly locals: Record<string, unknown>;
|
|
169
|
+
/**
|
|
170
|
+
* Data of the outermost layouts the error page renders inside (route data order): those whose guards
|
|
171
|
+
* passed and whose loaders succeeded, up to the first that did not. Unmatched URLs: the root layout's.
|
|
172
|
+
*/
|
|
173
|
+
readonly layouts?: readonly unknown[];
|
|
174
|
+
}
|
|
175
|
+
/** Options of the app handler: routes, renderers, head and dev flags. */
|
|
176
|
+
export interface AppOptions {
|
|
177
|
+
readonly routes: readonly AppRoute[];
|
|
178
|
+
render(input: RenderInput): Response | Promise<Response>;
|
|
179
|
+
renderError?(input: ErrorInput): Response | Promise<Response>;
|
|
180
|
+
/** Merged head for a route from its universal modules' `head` exports. */
|
|
181
|
+
head?(route: AppRoute, data: readonly unknown[], match: {
|
|
182
|
+
params: Readonly<Record<string, string>>;
|
|
183
|
+
url: URL;
|
|
184
|
+
}): Head | undefined | Promise<Head | undefined>;
|
|
185
|
+
/** Show 5xx messages (never in production). */
|
|
186
|
+
readonly dev?: boolean;
|
|
187
|
+
/** Server failures; `digest` is also in the (otherwise generic) 5xx message the client sees. */
|
|
188
|
+
onError?(error: unknown, request: Request, info?: ErrorInfo): void;
|
|
189
|
+
/** Request body limit in bytes for unsafe methods (413 past it). Default 1 MiB, multipart 10 MiB. */
|
|
190
|
+
readonly maxBody?: BodyLimit;
|
|
191
|
+
/**
|
|
192
|
+
* URL of the resume manifest's `builtins` chunk (RegExp / URLSearchParams / binary / error decoders): data and action
|
|
193
|
+
* answers holding such values name it (`x`), the client imports it before decoding. Without it they fail to decode.
|
|
194
|
+
*/
|
|
195
|
+
builtins?(): string | undefined;
|
|
196
|
+
/** Data requests: per layout of `route`, whether its loader may be skipped when the client keeps its data (default all). */
|
|
197
|
+
keepable?(route: AppRoute): readonly boolean[] | undefined | Promise<readonly boolean[] | undefined>;
|
|
198
|
+
/**
|
|
199
|
+
* Called once per HTML page GET / HEAD (no data request, no action) after the request handlers and before the guards
|
|
200
|
+
* and loaders: the moment a server can send `103 Early Hints` while it is still busy (`createApp({ earlyHints })`).
|
|
201
|
+
*/
|
|
202
|
+
earlyHints?(route: AppRoute, request: Request): void;
|
|
203
|
+
}
|
|
204
|
+
/** Where a server failure happened: request handler (`onRequest`/`on<Method>`/endpoint, module load), guard, loader, action or page render. */
|
|
205
|
+
export type ErrorPhase = "handler" | "guard" | "loader" | "action" | "render";
|
|
206
|
+
/** `onError` details of a reported (5xx) failure. */
|
|
207
|
+
export interface ErrorInfo {
|
|
208
|
+
readonly digest: string;
|
|
209
|
+
readonly phase?: ErrorPhase;
|
|
210
|
+
/** Matched route id. */
|
|
211
|
+
readonly route?: string;
|
|
212
|
+
}
|
|
213
|
+
/** @internal Short random id tying a hidden 5xx message to its server log entry. */
|
|
214
|
+
export declare const _digest: () => string;
|
|
215
|
+
/** What the caller of the app handler passes with a request (adapters: `nonce`, `address`, `platform`). */
|
|
216
|
+
export interface AppHandlerContext {
|
|
217
|
+
/** CSP nonce of this response (node adapter: fresh per request). */
|
|
218
|
+
nonce?: string;
|
|
219
|
+
/** Client address (`event.platform.clientAddress`). */
|
|
220
|
+
address?: string;
|
|
221
|
+
/** Adapter-provided request facts (`event.platform`). */
|
|
222
|
+
platform?: Platform;
|
|
223
|
+
/**
|
|
224
|
+
* Seeds `event.locals`: each request starts with a shallow copy, before any request handler, guard, loader or action
|
|
225
|
+
* runs (the caller's object is never changed). Only from the code that calls the handler (no adapter fills it from the
|
|
226
|
+
* request), e.g. a view model another server computed. Never sent to the browser unless a loader returns it. Requests
|
|
227
|
+
* that pass it bypass the route rules' page cache (their page depends on more than the URL). Client-navigation data
|
|
228
|
+
* requests (`?_rivet=data`) need the same seed.
|
|
229
|
+
*/
|
|
230
|
+
locals?: Readonly<Record<string, unknown>>;
|
|
231
|
+
}
|
|
232
|
+
/** The app's web-standard request handler. */
|
|
233
|
+
export type AppHandler = (request: Request, context?: AppHandlerContext) => Promise<Response>;
|
|
234
|
+
/**
|
|
235
|
+
* Encode a value with the resume table (Date/Map/Set/BigInt/undefined/cycles survive). With built-in entries (RegExp /
|
|
236
|
+
* URLSearchParams / binary / errors) and a `builtins` chunk URL, `x` names it: the client imports it before decoding.
|
|
237
|
+
*/
|
|
238
|
+
export declare function encodeData(value: unknown, builtins?: string, origin?: string): string;
|
|
239
|
+
/** Create the app's request handler. */
|
|
240
|
+
export declare function createHandler(options: AppOptions): AppHandler;
|