@nifrajs/web 3.1.0 → 3.2.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/dist/build-plan.d.ts +228 -0
- package/dist/build-plan.d.ts.map +1 -0
- package/dist/build-plan.js +514 -0
- package/dist/build-plan.js.map +1 -0
- package/dist/build-vite.d.ts +2 -1
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +2 -197
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +61 -502
- package/dist/build.js.map +1 -1
- package/dist/chunk-names.d.ts.map +1 -1
- package/dist/chunk-names.js +3 -2
- package/dist/chunk-names.js.map +1 -1
- package/dist/dev-ssr-graph.d.ts.map +1 -1
- package/dist/dev-ssr-graph.js +63 -28
- package/dist/dev-ssr-graph.js.map +1 -1
- package/dist/diagnostic.d.ts.map +1 -1
- package/dist/diagnostic.js +9 -2
- package/dist/diagnostic.js.map +1 -1
- package/dist/fonts-google.d.ts.map +1 -1
- package/dist/fonts-google.js +3 -1
- package/dist/fonts-google.js.map +1 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +2 -1
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +15 -609
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -1935
- package/dist/index.js.map +1 -1
- package/dist/internal/codegen.d.ts +68 -0
- package/dist/internal/codegen.d.ts.map +1 -0
- package/dist/internal/codegen.js +317 -0
- package/dist/internal/codegen.js.map +1 -0
- package/dist/internal/head-merge.d.ts +2 -0
- package/dist/internal/head-merge.d.ts.map +1 -1
- package/dist/internal/head-merge.js +17 -1
- package/dist/internal/head-merge.js.map +1 -1
- package/dist/internal/parity.d.ts +7 -0
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +212 -30
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/render-document.d.ts +372 -0
- package/dist/internal/render-document.d.ts.map +1 -0
- package/dist/internal/render-document.js +744 -0
- package/dist/internal/render-document.js.map +1 -0
- package/dist/internal/runtime-contract.d.ts +48 -0
- package/dist/internal/runtime-contract.d.ts.map +1 -0
- package/dist/internal/runtime-contract.js +27 -0
- package/dist/internal/runtime-contract.js.map +1 -0
- package/dist/internal/web-app.d.ts +171 -0
- package/dist/internal/web-app.d.ts.map +1 -0
- package/dist/internal/web-app.js +844 -0
- package/dist/internal/web-app.js.map +1 -0
- package/dist/islands.d.ts +48 -0
- package/dist/islands.d.ts.map +1 -1
- package/dist/islands.js +79 -0
- package/dist/islands.js.map +1 -1
- package/dist/module-graph.d.ts.map +1 -1
- package/dist/module-graph.js +22 -9
- package/dist/module-graph.js.map +1 -1
- package/dist/nano.d.ts +125 -0
- package/dist/nano.d.ts.map +1 -0
- package/dist/nano.js +190 -0
- package/dist/nano.js.map +1 -0
- package/dist/plugins/css-modules.js +2 -2
- package/dist/plugins/css-modules.js.map +1 -1
- package/dist/plugins/kit.d.ts +12 -0
- package/dist/plugins/kit.d.ts.map +1 -1
- package/dist/plugins/kit.js +62 -12
- package/dist/plugins/kit.js.map +1 -1
- package/dist/plugins/postcss.js +2 -2
- package/dist/plugins/postcss.js.map +1 -1
- package/dist/plugins/scss.js +2 -2
- package/dist/plugins/scss.js.map +1 -1
- package/dist/plugins/stylex.d.ts +70 -0
- package/dist/plugins/stylex.d.ts.map +1 -0
- package/dist/plugins/stylex.js +166 -0
- package/dist/plugins/stylex.js.map +1 -0
- package/dist/plugins/svg.js +2 -2
- package/dist/plugins/svg.js.map +1 -1
- package/dist/router.d.ts +1 -1
- package/dist/router.js +23 -23
- package/dist/router.js.map +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +26 -10
- package/dist/vite.js.map +1 -1
- package/package.json +39 -3
- package/src/build-plan.ts +741 -0
- package/src/build-vite.ts +1 -4
- package/src/build.ts +84 -716
- package/src/chunk-names.ts +3 -2
- package/src/dev-ssr-graph.ts +63 -28
- package/src/diagnostic.ts +14 -2
- package/src/fonts-google.ts +3 -1
- package/src/fs.ts +2 -1
- package/src/index.ts +73 -2705
- package/src/internal/codegen.ts +400 -0
- package/src/internal/head-merge.ts +19 -1
- package/src/internal/parity.ts +215 -35
- package/src/internal/render-document.ts +1116 -0
- package/src/internal/runtime-contract.ts +54 -0
- package/src/internal/web-app.ts +1114 -0
- package/src/islands.ts +85 -0
- package/src/module-graph.ts +23 -9
- package/src/nano.ts +246 -0
- package/src/plugins/css-modules.ts +2 -2
- package/src/plugins/kit.ts +65 -12
- package/src/plugins/postcss.ts +2 -2
- package/src/plugins/scss.ts +2 -2
- package/src/plugins/stylex.ts +298 -0
- package/src/plugins/svg.ts +2 -2
- package/src/router.ts +24 -24
- package/src/vite.ts +33 -9
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { type ResponseResult } from "@nifrajs/core/server";
|
|
2
|
+
import type { BoundaryRegistration, BoundaryStates } from "../boundary.js";
|
|
3
|
+
import type { Loader as LayoutLoader, LinkDescriptor, Meta, MetaDescriptor, MetaInput, RouteModule, ScriptDescriptor, UnsafeScriptDescriptor } from "../manifest.js";
|
|
4
|
+
import type { RenderAdapter } from "../render-seam.js";
|
|
5
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
6
|
+
declare const RESPONSE_RESULT: unique symbol;
|
|
7
|
+
/** A returned/thrown value that ends the request as-is: either shape of control-flow signal. */
|
|
8
|
+
export declare const isControlFlow: (value: unknown) => value is Response | ResponseResult;
|
|
9
|
+
export interface RenderedPage {
|
|
10
|
+
readonly [RESPONSE_RESULT]: true;
|
|
11
|
+
toResponse(): Response;
|
|
12
|
+
toNodeBody?(): {
|
|
13
|
+
readonly status: number;
|
|
14
|
+
readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;
|
|
15
|
+
readonly body: string | Uint8Array;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface RenderPageOptions {
|
|
19
|
+
readonly adapter: RenderAdapter;
|
|
20
|
+
/** The layout chain to render - outermost layout → page (opaque; the adapter renders it). */
|
|
21
|
+
readonly chain: readonly unknown[];
|
|
22
|
+
/** The loader output for this request. */
|
|
23
|
+
readonly data: unknown;
|
|
24
|
+
/** An action's data return (POST only) - surfaced to the page as `actionData` + serialized
|
|
25
|
+
* for the client so post-POST hydration matches. Omit on GETs. */
|
|
26
|
+
readonly actionData?: unknown;
|
|
27
|
+
/**
|
|
28
|
+
* URL of the built client entry (loaded as a module script).
|
|
29
|
+
*
|
|
30
|
+
* Optional ONLY on a `hydrate: false` page, where there is no client takeover to feed and this value
|
|
31
|
+
* reaches no output at all. The union below is what enforces that: omitting it on a hydrating page
|
|
32
|
+
* stays a compile error rather than rendering `src=""`.
|
|
33
|
+
*/
|
|
34
|
+
readonly clientEntry?: string;
|
|
35
|
+
/** Chunk URLs for the **matched** route (its layout chain + own chunk) to `modulepreload` in the
|
|
36
|
+
* shell - so the route code downloads in parallel with the entry instead of after it
|
|
37
|
+
* (`buildClient`'s per-route map). Empty/omitted ⇒ only the entry is preloaded (unchanged). */
|
|
38
|
+
readonly preload?: readonly string[];
|
|
39
|
+
/** Stylesheet URLs for the **matched** route (its layout chain + own CSS, from `buildClient`'s
|
|
40
|
+
* `BuildManifest.css`) - injected as `<link rel="stylesheet">` in `<head>` so styles arrive with the
|
|
41
|
+
* first paint (no FOUC). Rendered even on non-hydrated pages. Empty/omitted ⇒ none (unchanged). */
|
|
42
|
+
readonly styles?: readonly string[];
|
|
43
|
+
/** SSG: the prerendered-path set, serialized to `window.__NIFRA_PRERENDERED__` so the client fetches
|
|
44
|
+
* a static `_data.json` on soft-nav into a prerendered route. Empty/omitted ⇒ not injected. */
|
|
45
|
+
readonly prerenderedPaths?: readonly string[];
|
|
46
|
+
/** ISR: route freshness in seconds, emitted as the `x-nifra-isr-revalidate` header for a `withISR`
|
|
47
|
+
* wrapper to read. Omit ⇒ no header (the wrapper's default TTL applies). */
|
|
48
|
+
readonly revalidate?: number;
|
|
49
|
+
/** ISR invalidation tags emitted as a bounded `x-nifra-isr-tags` header. */
|
|
50
|
+
readonly revalidateTags?: readonly string[];
|
|
51
|
+
/** Matched route id; written to `window.__NIFRA_ROUTE__` so the client hydrates this chain. */
|
|
52
|
+
readonly routeId?: string;
|
|
53
|
+
/** The matched route's decoded path params - surfaced to the page as `params` (via {@link RenderProps})
|
|
54
|
+
* so an adapter's `useParams` is SSR-correct. Omit ⇒ `{}` (a route with no dynamic segments, or an
|
|
55
|
+
* error/404 render). */
|
|
56
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
57
|
+
/** The request's `pathname + search` - surfaced as `path` (via {@link RenderProps}) so an adapter's
|
|
58
|
+
* `useLocation`/`useSearchParams` render the right URL server-side and hydrate without drift. Omit ⇒
|
|
59
|
+
* `""`. */
|
|
60
|
+
readonly path?: string;
|
|
61
|
+
/** The route's validated search (`searchOf(mod.searchSchema, url.search)`, the same value handed to
|
|
62
|
+
* the loader as `ctx.search`), surfaced as `search` (via {@link RenderProps}) so an adapter's
|
|
63
|
+
* `useSearch` is SSR-correct. Omit ⇒ `{}` (a render with no search context). */
|
|
64
|
+
readonly search?: Record<string, unknown>;
|
|
65
|
+
/** Per-layout loader data, forwarded to the adapter as `RenderProps.layoutData`. Aligned with the
|
|
66
|
+
* chain's layout prefix; omitted when no layout in the chain has a loader. */
|
|
67
|
+
readonly layoutData?: readonly unknown[];
|
|
68
|
+
/** Dynamic-boundary states, forwarded to the adapter and serialized for hydration when present. */
|
|
69
|
+
readonly boundaries?: BoundaryStates;
|
|
70
|
+
/** HTTP status for the response (default 200; e.g. 404 for a not-found page). */
|
|
71
|
+
readonly status?: number;
|
|
72
|
+
/** Extra response headers - e.g. the `cache-control` a terminal status page wants. `content-type`
|
|
73
|
+
* is ignored (the document is always HTML) and the ISR freshness header is applied after these,
|
|
74
|
+
* so neither can be overridden from here. */
|
|
75
|
+
readonly headers?: HeadersLike;
|
|
76
|
+
/** Document title (fallback when `head.title` is unset). */
|
|
77
|
+
readonly title?: string;
|
|
78
|
+
/** Resolved route head - `title` overrides `title` above; `meta`/`link` render as managed
|
|
79
|
+
* (`data-nifra`) tags the client updates on navigation.
|
|
80
|
+
*
|
|
81
|
+
* **Head contract (the layout chain contributes).** `createWebApp` resolves this via
|
|
82
|
+
* {@link mergeHeads}: a route's head is its **layout chain's** `meta`/`head` exports merged with the
|
|
83
|
+
* page's. A `_layout.tsx` may `export const meta` (or `export function meta(args)`) - its tags land
|
|
84
|
+
* on every page below it (the home for `hreflang`, `preconnect`, a section-default `<title>`). The
|
|
85
|
+
* merge is **nearest-wins for scalars** (the page's `title` overrides an inner layout's, which
|
|
86
|
+
* overrides an outer one; an undefined page title keeps the layout's) and **concatenated for the
|
|
87
|
+
* `meta`/`link` arrays** (outermost layout first, page last). `<meta>`/`<link>` attributes pass a
|
|
88
|
+
* shared tag-specific allowlist (including inert `data-*` metadata) and values are escaped. */
|
|
89
|
+
readonly head?: Meta;
|
|
90
|
+
/** Id of the container wrapping the app markup (default `"root"`). A non-default id also gets
|
|
91
|
+
* {@link ROOT_ATTRIBUTE}, which is how the generated client entry finds the container to hydrate -
|
|
92
|
+
* the entry is built once and cannot know what a given render chose. */
|
|
93
|
+
readonly rootId?: string;
|
|
94
|
+
/** When `false`, emit a complete but **non-hydrated** document - no client entry script, data
|
|
95
|
+
* globals, or modulepreloads. Used for server-rendered `_error` pages: a terminal state that needs no
|
|
96
|
+
* client takeover, and it sidesteps an SSR/hydrate mismatch (the server rendered the boundary, not
|
|
97
|
+
* the page the client manifest maps this route id to). Default `true`. */
|
|
98
|
+
readonly hydrate?: boolean;
|
|
99
|
+
/** Island client bundles (`@nifrajs/web/islands`) to load as `<script type="module">` in the document
|
|
100
|
+
* tail - emitted **regardless of `hydrate`**, so a static (`hydrate: false`) page can still mount
|
|
101
|
+
* no-framework islands. URLs are attribute-escaped. Empty/omitted ⇒ none (unchanged output). */
|
|
102
|
+
readonly islandScripts?: readonly string[];
|
|
103
|
+
/** CSP nonce applied to every framework-owned executable script in this document. */
|
|
104
|
+
readonly nonce?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Advanced: a per-route slot the renderer fills with the request-invariant document pieces (shell
|
|
107
|
+
* prefix/suffix, tail statics) on the first render and reuses afterwards, skipping their re-assembly.
|
|
108
|
+
*
|
|
109
|
+
* Only pass a cache when every shell-shaping input is IDENTICAL across the requests sharing it:
|
|
110
|
+
* same `head` content (a static meta chain - never a `meta(data)` function), `title`, `styles`,
|
|
111
|
+
* `preload`, `islandScripts`, `clientEntry`, `rootId`, `hydrate`, and `prerenderedPaths`. Per-request
|
|
112
|
+
* values (`data`, `params`, `search`, `actionData`, `layoutData`, deferred state) are always assembled
|
|
113
|
+
* fresh and safe. A per-request `nonce` disables the cache automatically. `createWebApp` wires this
|
|
114
|
+
* per route, gated on the route + layout metas being static.
|
|
115
|
+
*/
|
|
116
|
+
readonly assemblyCache?: RenderAssemblyCache;
|
|
117
|
+
}
|
|
118
|
+
/** The mutable per-route slot {@link RenderPageOptions.assemblyCache} fills. Opaque - create as `{}`. */
|
|
119
|
+
export interface RenderAssemblyCache {
|
|
120
|
+
/** Shell up to (not including) the deferred-runtime insertion point. */
|
|
121
|
+
shellPre?: string;
|
|
122
|
+
/** Shell from after the deferred-runtime insertion point through the open `#root` container. */
|
|
123
|
+
shellPost?: string;
|
|
124
|
+
/** Tail opener: the inline script open tag + the route-id global (before the action global). */
|
|
125
|
+
tailPre?: string;
|
|
126
|
+
/** Tail mid: the prerendered-paths global (between the action and layout-data globals). */
|
|
127
|
+
tailMid?: string;
|
|
128
|
+
/** Tail data prefix: the `window.<data global>=` assignment head. */
|
|
129
|
+
tailData?: string;
|
|
130
|
+
/** Tail from after the serialized data through `</html>`. */
|
|
131
|
+
tailPost?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* `renderPage` input. A hydrating page (the default) must supply `clientEntry`, because the document
|
|
135
|
+
* loads it as a module script; a `hydrate: false` page may omit it, because nothing in the emitted
|
|
136
|
+
* document references it. Expressed as a union so the compiler enforces the pairing rather than the
|
|
137
|
+
* renderer discovering an empty `src` at runtime.
|
|
138
|
+
*/
|
|
139
|
+
export type RenderPageInput = RenderPageOptions & ({
|
|
140
|
+
readonly hydrate?: true;
|
|
141
|
+
readonly clientEntry: string;
|
|
142
|
+
} | {
|
|
143
|
+
readonly hydrate: false;
|
|
144
|
+
});
|
|
145
|
+
/**
|
|
146
|
+
* Server: render a full HTML document for a page - the adapter's hydration head + the SSR
|
|
147
|
+
* markup (**streamed**) + the serialized loader data + the client module - as a `Response`.
|
|
148
|
+
* The shell (`<head>` + the open container) flushes first, the adapter's app stream follows,
|
|
149
|
+
* then the tail (data globals + client entry). Pure Web Standards, so it returns straight from
|
|
150
|
+
* a nifra route handler and streams on any fetch runtime (Bun/Node/Deno/Workers).
|
|
151
|
+
*/
|
|
152
|
+
export declare function renderPage(options: RenderPageInput): MaybePromise<Response>;
|
|
153
|
+
export declare function renderPageResult(options: RenderPageInput): MaybePromise<RenderedPage>;
|
|
154
|
+
/** Options for {@link redirect}. */
|
|
155
|
+
export interface RedirectOptions {
|
|
156
|
+
/** HTTP status (default 303 See Other; pass 307/308 to preserve the method). */
|
|
157
|
+
readonly status?: number;
|
|
158
|
+
/** Allow an off-origin / absolute destination. Off by default: only a same-origin path (a single
|
|
159
|
+
* leading `/`) is permitted, so an action can't be turned into an open redirect by passing
|
|
160
|
+
* attacker-controlled input straight through. Set `true` for a deliberate external redirect. */
|
|
161
|
+
readonly external?: boolean;
|
|
162
|
+
/** Extra response headers. A redirect is no longer a `Response`, so there is no `.headers` to
|
|
163
|
+
* mutate after the fact - name them here. Cookies still ride `c.set`, as on any other response. */
|
|
164
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
165
|
+
}
|
|
166
|
+
/** A same-origin destination is an absolute path: one leading `/`, but NOT `//` (protocol-relative →
|
|
167
|
+
* another origin), and nothing a URL parser resolves off-origin. Everything else (absolute URL with
|
|
168
|
+
* a scheme, `//host`, `javascript:`, a bare relative `foo`) requires `external: true`. The predicate
|
|
169
|
+
* lives in the kernel - see `isSameOriginPath` - so this gate and the auth guards' `redirectTo`
|
|
170
|
+
* cannot drift apart. */
|
|
171
|
+
/**
|
|
172
|
+
* Build a redirect - return it from a route `action` for the Post/Redirect/Get pattern (POST
|
|
173
|
+
* mutates, 303 sends the browser to a fresh GET, so a reload doesn't re-submit). Defaults to 303
|
|
174
|
+
* (See Other); pass `{ status: 307 }` or `{ status: 308 }` to preserve the method.
|
|
175
|
+
*
|
|
176
|
+
* **Secure by default:** `location` must be a same-origin path (begins with `/`, not `//`). An
|
|
177
|
+
* off-origin/absolute destination throws unless you pass `{ external: true }` - this closes the
|
|
178
|
+
* open-redirect footgun of `return redirect(formData.get("next"))` on the no-JS (native-form) path,
|
|
179
|
+
* which serves the action's control-flow value verbatim.
|
|
180
|
+
*
|
|
181
|
+
* Returns a plain render, not a `Response`. A redirect is a status line and one header - the most
|
|
182
|
+
* body-less response there is - and building a `Response` for it costs the whole Web object plus, on
|
|
183
|
+
* Node, a stream drained back out. As data it renders on the same lane a handler's return takes.
|
|
184
|
+
* `redirect(...)` is still returned or thrown from exactly the same places; only `.status` /
|
|
185
|
+
* `.headers` are gone from the value, replaced by `options.headers` and the request's `c.set`.
|
|
186
|
+
*
|
|
187
|
+
* @param options redirect status, extra headers, and whether an off-origin destination is intentional.
|
|
188
|
+
*/
|
|
189
|
+
export declare function redirect(location: string, options?: RedirectOptions): ResponseResult;
|
|
190
|
+
/**
|
|
191
|
+
* Brand marking a `Response` as a **terminal-status signal** rather than a response to serve verbatim.
|
|
192
|
+
*
|
|
193
|
+
* A loader that throws a bare `Response` has always been passed straight through - that is how
|
|
194
|
+
* `throw redirect(...)` works, and apps rely on it. So "render the `_404` boundary at 404" cannot be
|
|
195
|
+
* expressed by throwing a plain `Response`: the framework would have no way to tell it apart from a
|
|
196
|
+
* hand-rolled body the app wants served exactly as written. The brand is that distinction, and
|
|
197
|
+
* checking it *before* the pass-through is what keeps every existing throw working unchanged.
|
|
198
|
+
*
|
|
199
|
+
* `Symbol.for` matches `RESPONSE_RESULT` above: a registry symbol survives two copies of this module,
|
|
200
|
+
* which a `unique symbol` would not - and a duplicate-install turning a 404 into a raw 404 body would
|
|
201
|
+
* be a maddening bug to trace.
|
|
202
|
+
*/
|
|
203
|
+
/** Derived from the `Headers` constructor rather than the DOM lib's `HeadersInit`: `@nifrajs/web`
|
|
204
|
+
* is consumed from DOM-free programs (the root tsconfig runs `types: ["bun"]`), and naming the DOM
|
|
205
|
+
* type here would break their build. Same workaround as `SSEInit.headers` in core. */
|
|
206
|
+
export type HeadersLike = ConstructorParameters<typeof Headers>[0];
|
|
207
|
+
/**
|
|
208
|
+
* Append the likely cause to an SSR error that carries a duplicate-instance signature.
|
|
209
|
+
*
|
|
210
|
+
* Deliberately does NOT claim the resolved paths: `@nifrajs/web` is framework-agnostic and does not
|
|
211
|
+
* depend on React, so it cannot resolve the copies without guessing. It names the condition and the
|
|
212
|
+
* command that reports the paths, which is the actionable part. Returns the error untouched when the
|
|
213
|
+
* signature does not match, so an ordinary render error reads exactly as before.
|
|
214
|
+
*/
|
|
215
|
+
export declare function withDuplicateInstanceHint(err: unknown): unknown;
|
|
216
|
+
/**
|
|
217
|
+
* An action's control-flow value passes straight through - except a redirect on a client-submit data
|
|
218
|
+
* request: fetch would follow the 3xx into HTML the client can't use, so the redirect rides the
|
|
219
|
+
* X-Nifra-Redirect header on a 204 and the client navigates. One conversion shared by the returned-
|
|
220
|
+
* and thrown- paths, so `return redirect()` and `throw redirect()` agree.
|
|
221
|
+
*
|
|
222
|
+
* Takes either shape: `redirect()` is a plain render, while a hand-rolled `new Response(...)` from an
|
|
223
|
+
* action still arrives as a `Response`. The rewrite stays on the lane its input was on - a plain
|
|
224
|
+
* redirect converts to a plain 204, and never materializes the `Response` it is replacing.
|
|
225
|
+
*/
|
|
226
|
+
export declare function actionResponse(result: Response | ResponseResult, isDataRequest: boolean): Response | ResponseResult;
|
|
227
|
+
/** A loaded layout module. `loader`/`gate` are the layout-loader surface; `meta` predates it. */
|
|
228
|
+
export type LoadedLayoutModules = ReadonlyArray<{
|
|
229
|
+
default: unknown;
|
|
230
|
+
meta?: MetaInput;
|
|
231
|
+
loader?: LayoutLoader;
|
|
232
|
+
action?: unknown;
|
|
233
|
+
gate?: boolean;
|
|
234
|
+
searchSchema?: RouteModule["searchSchema"];
|
|
235
|
+
boundaries?: readonly BoundaryRegistration[];
|
|
236
|
+
}>;
|
|
237
|
+
/**
|
|
238
|
+
* Narrow the route's params to the ones a layout owns.
|
|
239
|
+
*
|
|
240
|
+
* A layout wraps a URL prefix, so anything deeper belongs to a route beneath it. Handing it the full
|
|
241
|
+
* set would let a layout read a param it does not own - which reads fine until the layout is reused
|
|
242
|
+
* under a route that has no such param and the value silently becomes `undefined`.
|
|
243
|
+
*/
|
|
244
|
+
export declare function scopeParams(params: Record<string, string>, owned: readonly string[] | undefined): Record<string, string>;
|
|
245
|
+
export declare const EMPTY_RETAIN: ReadonlySet<number>;
|
|
246
|
+
export declare const tagLayoutError: (err: unknown, layoutId: string) => unknown;
|
|
247
|
+
export declare const layoutErrorId: (err: unknown) => string | undefined;
|
|
248
|
+
export declare const STATUS_SIGNAL: unique symbol;
|
|
249
|
+
/** Reason phrases for the plain-text fallback, used only when the app authored no `_<status>` and no
|
|
250
|
+
* `_404` page. Deliberately not exhaustive - anything unlisted falls back to "Error", which is more
|
|
251
|
+
* useful than shipping a table of every RFC status for a body almost nobody will see. */
|
|
252
|
+
export declare const STATUS_TEXT: Readonly<Record<number, string>>;
|
|
253
|
+
export interface StatusSignal extends Response {
|
|
254
|
+
readonly [STATUS_SIGNAL]: {
|
|
255
|
+
readonly status: number;
|
|
256
|
+
readonly headers?: HeadersLike;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
export declare function isStatusSignal(value: unknown): value is StatusSignal;
|
|
260
|
+
/** Options shared by {@link notFound}, {@link gone}, and {@link statusPage}. */
|
|
261
|
+
export interface StatusPageOptions {
|
|
262
|
+
/**
|
|
263
|
+
* Extra headers for the rendered response - `cache-control` above all.
|
|
264
|
+
*
|
|
265
|
+
* The defaults differ by status for a reason: a 404 may be a race with publication, so it wants a
|
|
266
|
+
* short TTL, while a 410 is a promise that the URL is permanently gone and can be cached hard.
|
|
267
|
+
* Getting this wrong is the difference between a crawler dropping a dead URL and re-fetching it
|
|
268
|
+
* for weeks.
|
|
269
|
+
*/
|
|
270
|
+
readonly headers?: HeadersLike;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Render the nearest `_404` page at status **404**. `throw` it from a loader when the record does not
|
|
274
|
+
* exist.
|
|
275
|
+
*
|
|
276
|
+
* This is the fix for the soft 404: a matched route whose loader finds nothing has otherwise no way to
|
|
277
|
+
* answer 404, so the path of least resistance is to return empty data and render "not found" inside a
|
|
278
|
+
* **200**. That looks correct in a browser and is invisible in review, which is why it ships and stays
|
|
279
|
+
* shipped - while search engines penalise it and keep the dead URL indexed.
|
|
280
|
+
*
|
|
281
|
+
* Returns `never`: these throw, so a loader narrows without a redundant `return`, and the type states
|
|
282
|
+
* the thing the "loaders `throw` redirect, actions `return` it" rule already trips people on.
|
|
283
|
+
*/
|
|
284
|
+
export declare function notFound(options?: StatusPageOptions): never;
|
|
285
|
+
/**
|
|
286
|
+
* Render a terminal page at status **410 Gone**. `throw` it from a loader for a record that existed and
|
|
287
|
+
* was deliberately removed - a withdrawn listing, a deleted post.
|
|
288
|
+
*
|
|
289
|
+
* 410 is not a pedantic 404: it tells a crawler to **drop** the URL rather than re-fetch it for weeks
|
|
290
|
+
* on the assumption the 404 was transient. Uses `_410.tsx` if the app has one, otherwise `_404`.
|
|
291
|
+
*/
|
|
292
|
+
export declare function gone(options?: StatusPageOptions): never;
|
|
293
|
+
/**
|
|
294
|
+
* Render a terminal page at any 4xx/5xx status - the escape hatch behind {@link notFound} and
|
|
295
|
+
* {@link gone} (402, 451, …). Uses `_<status>.tsx` if present, otherwise `_404`.
|
|
296
|
+
*/
|
|
297
|
+
export declare function statusPage(status: number, options?: StatusPageOptions): never;
|
|
298
|
+
/** The wrapper `revalidate()` returns: the action's `data` plus the paths it changed. A plain tagged
|
|
299
|
+
* shape (not a class) so `@nifrajs/client`'s `ActionData` can unwrap it structurally without importing
|
|
300
|
+
* from `@nifrajs/web`. `createWebApp` strips the wrapper - the client receives `data` as the body and
|
|
301
|
+
* the paths via the `X-Nifra-Revalidate` header. */
|
|
302
|
+
export interface RevalidateResult<T> {
|
|
303
|
+
readonly __nifraRevalidate: readonly string[];
|
|
304
|
+
readonly data: T;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Return this from an action to declare which routes the mutation changed (alongside the action's
|
|
308
|
+
* `data`). `createWebApp` sets the `X-Nifra-Revalidate` response header; after the submit the client
|
|
309
|
+
* marks those cached routes stale - refetching the active one and any mounted fetcher showing them -
|
|
310
|
+
* so a mutation can refresh views beyond the one that was submitted. `data` is still surfaced to the
|
|
311
|
+
* component as `actionData` (the wrapper is transparent to `ActionData<typeof action>`).
|
|
312
|
+
*/
|
|
313
|
+
export declare function revalidate<T>(paths: readonly string[], data: T): RevalidateResult<T>;
|
|
314
|
+
/**
|
|
315
|
+
* Serialize loader data for embedding inside an inline `<script>`. `JSON.stringify` alone
|
|
316
|
+
* is NOT safe there: a string containing `</script>` or `<!--` would break out of the
|
|
317
|
+
* script element (an XSS vector). Escape `<`/`>` to `\uXXXX`, plus the U+2028/U+2029
|
|
318
|
+
* separators.
|
|
319
|
+
*/
|
|
320
|
+
export declare function serializeData(data: unknown): string;
|
|
321
|
+
/**
|
|
322
|
+
* A `<link rel="canonical">` descriptor for a route's `meta.link`. The canonical URL tells search
|
|
323
|
+
* engines which URL is authoritative for a page (deduping query-string / tracking variants).
|
|
324
|
+
*
|
|
325
|
+
* ```ts
|
|
326
|
+
* export const meta = (a) => ({ link: [canonical(`https://site.com/posts/${a.params.slug}`)] })
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
export declare function canonical(href: string): LinkDescriptor;
|
|
330
|
+
/** Inputs for {@link openGraph} - the common Open Graph properties. All optional; only the provided
|
|
331
|
+
* ones become tags. `type` defaults to `"website"`. */
|
|
332
|
+
export interface OpenGraphInput {
|
|
333
|
+
readonly title?: string;
|
|
334
|
+
readonly description?: string;
|
|
335
|
+
/** Absolute URL of the share image (`og:image`). */
|
|
336
|
+
readonly image?: string;
|
|
337
|
+
/** Canonical URL of the page (`og:url`). */
|
|
338
|
+
readonly url?: string;
|
|
339
|
+
/** Object type (`og:type`) - `"website"`, `"article"`, … Default `"website"`. */
|
|
340
|
+
readonly type?: string;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Build the Open Graph `<meta property="og:*">` entries for a route's `meta.meta`. Returns only the
|
|
344
|
+
* properties you supplied (plus `og:type`, defaulting to `"website"`), so it composes with other meta.
|
|
345
|
+
*
|
|
346
|
+
* ```ts
|
|
347
|
+
* export const meta = { meta: [...openGraph({ title: "Nifra", image: "https://site.com/og.png" })] }
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
export declare function openGraph(input: OpenGraphInput): MetaDescriptor[];
|
|
351
|
+
/**
|
|
352
|
+
* Build a JSON-LD `<script type="application/ld+json">` entry for a route's `meta.script` from a plain
|
|
353
|
+
* object. `JSON.stringify` produces the body; the head renderer breakout-escapes it (see
|
|
354
|
+
* `escapeScriptContent`), so a string field containing `</script>` is embedded safely.
|
|
355
|
+
*
|
|
356
|
+
* ```ts
|
|
357
|
+
* export const meta = {
|
|
358
|
+
* script: [jsonLd({ "@context": "https://schema.org", "@type": "Article", headline: "Hi" })],
|
|
359
|
+
* }
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
export declare function jsonLd(data: Record<string, unknown>): ScriptDescriptor;
|
|
363
|
+
/**
|
|
364
|
+
* Deliberately unsafe escape hatch for executable inline code. The required nonce keeps the result
|
|
365
|
+
* compatible with a strict CSP and makes the security-sensitive choice visible at the call site.
|
|
366
|
+
*/
|
|
367
|
+
export declare function unsafeInlineScript(content: string, options: {
|
|
368
|
+
readonly nonce: string;
|
|
369
|
+
readonly type?: "module" | "text/javascript";
|
|
370
|
+
}): UnsafeScriptDescriptor;
|
|
371
|
+
export {};
|
|
372
|
+
//# sourceMappingURL=render-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-document.d.ts","sourceRoot":"","sources":["../../src/internal/render-document.ts"],"names":[],"mappings":"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"}
|