@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
package/dist/index.d.ts
CHANGED
|
@@ -7,618 +7,15 @@
|
|
|
7
7
|
* the adapter interprets them. That keeps this package both framework-agnostic and free
|
|
8
8
|
* of DOM types: it is pure server orchestration + string building.
|
|
9
9
|
*/
|
|
10
|
-
import { type ResponseResult, type ServerOptions, server } from "@nifrajs/core/server";
|
|
11
|
-
import { type BoundaryStates } from "./boundary.js";
|
|
12
|
-
import { type Deferred, defer } from "./deferred.js";
|
|
13
|
-
import { mergeHeads, resolveMeta } from "./internal/head-merge.js";
|
|
14
|
-
import type { LinkDescriptor, Manifest, Meta, MetaDescriptor, ScriptDescriptor, UnsafeScriptDescriptor } from "./manifest.js";
|
|
15
|
-
import type { RenderAdapter } from "./render-seam.js";
|
|
16
10
|
export { assertStaticBoundaryImports, type Boundary, type BoundaryDescriptor, type BoundaryError, type BoundaryMode, type BoundaryRegistration, type BoundaryRequestCtx, type BoundaryState, type BoundaryStates, type BoundaryStatus, boundaryDescriptors, boundaryModeKey, type DynamicBoundary, type DynamicBoundaryBatch, type InterceptBoundary, MemoryStaticBoundaryCache, type PendingBoundary, resolveDynamicBoundaries, resolveStaticBoundaries, type StaticBoundary, type StaticBoundaryCache, type StaticBoundaryImportEdge, type StaticBoundaryRoot, type StaticCtx, startDynamicBoundaries, } from "./boundary.js";
|
|
11
|
+
export { assertRenderAdapterConformance, RenderAdapterConformanceError, type RenderAdapterConformanceFixture, } from "./conformance.js";
|
|
12
|
+
export { type Deferred, defer } from "./deferred.js";
|
|
17
13
|
export { DRAFT_COOKIE, type DraftCookieControls, disableDraft, type EnableDraftOptions, enableDraft, isDraftEnabled, type PreviewEndpointOptions, previewEndpoint, } from "./draft.js";
|
|
18
14
|
export { type FontDisplay, type FontFace, type FontPreloadInput, type FontSource, fontFace, fontPreload, } from "./fonts.js";
|
|
19
|
-
export { type
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export { createMutation, createQueryClient, type DehydratedState, hashQueryKey, type InfiniteData, type InfiniteQueryHandle, type InfiniteQueryOptions, type MutationCallbacks, type MutationHandle, type MutationState, type MutationStatus, type QueryClient, type QueryClientOptions, type QueryHandle, type QueryOptions, type QueryState, type QueryStatus, } from "./query.js";
|
|
24
|
-
export { type ClientRouter, type ClientRouterOptions, createClientRouter, createMatcher, DATA_HEADER, type Fetcher, type FetcherState, type FetchRouteData, type MountRouterOptions, NAV_FROM_HEADER, REDIRECT_HEADER, RETAIN_HEADER, REVALIDATE_HEADER, type RouteMatch, type RoutePattern, type RouterState, STATUS_HEADER, type Submission, type SubmitOptions, } from "./router.js";
|
|
25
|
-
export { type Deferred, defer, mergeHeads, resolveMeta };
|
|
26
|
-
/** Phantom brand key for {@link ServerOnly}. A unique symbol so the brand can't be forged by a plain
|
|
27
|
-
* object literal; `unique symbol` keys never appear in the emitted JS, so the brand is purely
|
|
28
|
-
* type-level (zero runtime cost). The property is optional + `never`-typed, so a `ServerOnly<T>`
|
|
29
|
-
* stays assignment-compatible with `T` - it documents intent without obstructing real use. */
|
|
30
|
-
declare const SERVER_ONLY_BRAND: unique symbol;
|
|
31
|
-
/**
|
|
32
|
-
* Type-level intent marker for a value that must only exist on the server - a secret, a DB handle, a
|
|
33
|
-
* server-only client. `ServerOnly<T>` is structurally `T` (the brand is an optional phantom field, so
|
|
34
|
-
* existing code keeps type-checking), but it advertises to readers + the compiler that the value is
|
|
35
|
-
* not meant to cross to the browser. It is **purely type-level** and erases at build - it does NOT,
|
|
36
|
-
* by itself, keep the value out of the client bundle.
|
|
37
|
-
*
|
|
38
|
-
* The enforcement is two runtime conventions:
|
|
39
|
-
* - add the side-effect import `import "@nifrajs/web/server-only"` at the top of the module - the
|
|
40
|
-
* client build ({@link buildClient}) fails loud, with the import chain, if it reaches a browser
|
|
41
|
-
* chunk (the poison-import marker);
|
|
42
|
-
* - or name the file `*.server.ts` - the `.server` convention empties it in the client build.
|
|
43
|
-
*
|
|
44
|
-
* Use this brand to express the intent in the types; pair it with one of those runtime markers so a
|
|
45
|
-
* leak is caught at build time rather than shipping a secret to the client.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* import "@nifrajs/web/server-only"
|
|
49
|
-
* import type { ServerOnly } from "@nifrajs/web"
|
|
50
|
-
* export const apiKey: ServerOnly<string> = process.env.SECRET_API_KEY!
|
|
51
|
-
*/
|
|
52
|
-
export type ServerOnly<T> = T & {
|
|
53
|
-
readonly [SERVER_ONLY_BRAND]?: never;
|
|
54
|
-
};
|
|
55
|
-
export { assertRenderAdapterConformance, RenderAdapterConformanceError, type RenderAdapterConformanceFixture, } from "./conformance.js";
|
|
56
|
-
export { ACTION_GLOBAL, BOUNDARY_GLOBAL, DATA_GLOBAL, LAYOUT_DATA_GLOBAL, type RenderAdapter, type RenderProps, ROOT_ATTRIBUTE, ROUTE_GLOBAL, type SsrModuleLoader, setSsrModuleLoader, ssrModuleLoader, } from "./render-seam.js";
|
|
57
|
-
export { type SearchOf, searchOf, searchOfChain, serializeSearch } from "./search.js";
|
|
58
|
-
/**
|
|
59
|
-
* Pre-hydration form guard - a tiny inline script flushed in `<head>` (it runs in the window between
|
|
60
|
-
* first paint and the island bundle taking over). It neutralizes the one real hydration footgun: a
|
|
61
|
-
* JS-only form (a hand-wired `onSubmit` with no native fallback) submitting *natively* before its
|
|
62
|
-
* handler is attached, which navigates the browser to a broken `?field=…` GET of the current page.
|
|
63
|
-
*
|
|
64
|
-
* It blocks ONLY that shape - an effective-GET form whose action targets the current document - and
|
|
65
|
-
* only until hydration commits (`data-nifra-hydrated`, set by the client entry). Method-`post` forms
|
|
66
|
-
* (progressive enhancement: the native POST hits the route `action`) and GET forms with a real action
|
|
67
|
-
* (a search box → `/search`) pass through untouched. Opt out per-form with `data-native`. Static text
|
|
68
|
-
* (no interpolation), so it can't carry injected markup. See the Hydration guide.
|
|
69
|
-
*/
|
|
70
|
-
export declare const PRE_HYDRATION_GUARD: string;
|
|
71
|
-
/**
|
|
72
|
-
* The single default port for the dev server (`@nifrajs/web/dev`, `@nifrajs/web/vite`) **and**
|
|
73
|
-
* `nifra start`. Deliberately uncommon: `3000`/`5173`/`8080` collide with whatever else is running
|
|
74
|
-
* (Next, Vite, a stray Node API). `4321` rarely is - and being the *same* constant across `nifra dev`
|
|
75
|
-
* and `nifra start` means a project's URL doesn't change between commands. Override per-run with
|
|
76
|
-
* `--port <n>` or the `PORT` env var. */
|
|
77
|
-
export declare const DEFAULT_DEV_PORT = 4321;
|
|
78
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
79
|
-
declare const RESPONSE_RESULT: unique symbol;
|
|
80
|
-
export interface RenderedPage {
|
|
81
|
-
readonly [RESPONSE_RESULT]: true;
|
|
82
|
-
toResponse(): Response;
|
|
83
|
-
toNodeBody?(): {
|
|
84
|
-
readonly status: number;
|
|
85
|
-
readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;
|
|
86
|
-
readonly body: string | Uint8Array;
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
export interface RenderPageOptions {
|
|
90
|
-
readonly adapter: RenderAdapter;
|
|
91
|
-
/** The layout chain to render - outermost layout → page (opaque; the adapter renders it). */
|
|
92
|
-
readonly chain: readonly unknown[];
|
|
93
|
-
/** The loader output for this request. */
|
|
94
|
-
readonly data: unknown;
|
|
95
|
-
/** An action's data return (POST only) - surfaced to the page as `actionData` + serialized
|
|
96
|
-
* for the client so post-POST hydration matches. Omit on GETs. */
|
|
97
|
-
readonly actionData?: unknown;
|
|
98
|
-
/**
|
|
99
|
-
* URL of the built client entry (loaded as a module script).
|
|
100
|
-
*
|
|
101
|
-
* Optional ONLY on a `hydrate: false` page, where there is no client takeover to feed and this value
|
|
102
|
-
* reaches no output at all. The union below is what enforces that: omitting it on a hydrating page
|
|
103
|
-
* stays a compile error rather than rendering `src=""`.
|
|
104
|
-
*/
|
|
105
|
-
readonly clientEntry?: string;
|
|
106
|
-
/** Chunk URLs for the **matched** route (its layout chain + own chunk) to `modulepreload` in the
|
|
107
|
-
* shell - so the route code downloads in parallel with the entry instead of after it
|
|
108
|
-
* (`buildClient`'s per-route map). Empty/omitted ⇒ only the entry is preloaded (unchanged). */
|
|
109
|
-
readonly preload?: readonly string[];
|
|
110
|
-
/** Stylesheet URLs for the **matched** route (its layout chain + own CSS, from `buildClient`'s
|
|
111
|
-
* `BuildManifest.css`) - injected as `<link rel="stylesheet">` in `<head>` so styles arrive with the
|
|
112
|
-
* first paint (no FOUC). Rendered even on non-hydrated pages. Empty/omitted ⇒ none (unchanged). */
|
|
113
|
-
readonly styles?: readonly string[];
|
|
114
|
-
/** SSG: the prerendered-path set, serialized to `window.__NIFRA_PRERENDERED__` so the client fetches
|
|
115
|
-
* a static `_data.json` on soft-nav into a prerendered route. Empty/omitted ⇒ not injected. */
|
|
116
|
-
readonly prerenderedPaths?: readonly string[];
|
|
117
|
-
/** ISR: route freshness in seconds, emitted as the `x-nifra-isr-revalidate` header for a `withISR`
|
|
118
|
-
* wrapper to read. Omit ⇒ no header (the wrapper's default TTL applies). */
|
|
119
|
-
readonly revalidate?: number;
|
|
120
|
-
/** ISR invalidation tags emitted as a bounded `x-nifra-isr-tags` header. */
|
|
121
|
-
readonly revalidateTags?: readonly string[];
|
|
122
|
-
/** Matched route id; written to `window.__NIFRA_ROUTE__` so the client hydrates this chain. */
|
|
123
|
-
readonly routeId?: string;
|
|
124
|
-
/** The matched route's decoded path params - surfaced to the page as `params` (via {@link RenderProps})
|
|
125
|
-
* so an adapter's `useParams` is SSR-correct. Omit ⇒ `{}` (a route with no dynamic segments, or an
|
|
126
|
-
* error/404 render). */
|
|
127
|
-
readonly params?: Readonly<Record<string, string>>;
|
|
128
|
-
/** The request's `pathname + search` - surfaced as `path` (via {@link RenderProps}) so an adapter's
|
|
129
|
-
* `useLocation`/`useSearchParams` render the right URL server-side and hydrate without drift. Omit ⇒
|
|
130
|
-
* `""`. */
|
|
131
|
-
readonly path?: string;
|
|
132
|
-
/** The route's validated search (`searchOf(mod.searchSchema, url.search)`, the same value handed to
|
|
133
|
-
* the loader as `ctx.search`), surfaced as `search` (via {@link RenderProps}) so an adapter's
|
|
134
|
-
* `useSearch` is SSR-correct. Omit ⇒ `{}` (a render with no search context). */
|
|
135
|
-
readonly search?: Record<string, unknown>;
|
|
136
|
-
/** Per-layout loader data, forwarded to the adapter as `RenderProps.layoutData`. Aligned with the
|
|
137
|
-
* chain's layout prefix; omitted when no layout in the chain has a loader. */
|
|
138
|
-
readonly layoutData?: readonly unknown[];
|
|
139
|
-
/** Dynamic-boundary states, forwarded to the adapter and serialized for hydration when present. */
|
|
140
|
-
readonly boundaries?: BoundaryStates;
|
|
141
|
-
/** HTTP status for the response (default 200; e.g. 404 for a not-found page). */
|
|
142
|
-
readonly status?: number;
|
|
143
|
-
/** Extra response headers - e.g. the `cache-control` a terminal status page wants. `content-type`
|
|
144
|
-
* is ignored (the document is always HTML) and the ISR freshness header is applied after these,
|
|
145
|
-
* so neither can be overridden from here. */
|
|
146
|
-
readonly headers?: HeadersLike;
|
|
147
|
-
/** Document title (fallback when `head.title` is unset). */
|
|
148
|
-
readonly title?: string;
|
|
149
|
-
/** Resolved route head - `title` overrides `title` above; `meta`/`link` render as managed
|
|
150
|
-
* (`data-nifra`) tags the client updates on navigation.
|
|
151
|
-
*
|
|
152
|
-
* **Head contract (the layout chain contributes).** `createWebApp` resolves this via
|
|
153
|
-
* {@link mergeHeads}: a route's head is its **layout chain's** `meta`/`head` exports merged with the
|
|
154
|
-
* page's. A `_layout.tsx` may `export const meta` (or `export function meta(args)`) - its tags land
|
|
155
|
-
* on every page below it (the home for `hreflang`, `preconnect`, a section-default `<title>`). The
|
|
156
|
-
* merge is **nearest-wins for scalars** (the page's `title` overrides an inner layout's, which
|
|
157
|
-
* overrides an outer one; an undefined page title keeps the layout's) and **concatenated for the
|
|
158
|
-
* `meta`/`link` arrays** (outermost layout first, page last). `<meta>`/`<link>` attributes pass a
|
|
159
|
-
* shared tag-specific allowlist (including inert `data-*` metadata) and values are escaped. */
|
|
160
|
-
readonly head?: Meta;
|
|
161
|
-
/** Id of the container wrapping the app markup (default `"root"`). A non-default id also gets
|
|
162
|
-
* {@link ROOT_ATTRIBUTE}, which is how the generated client entry finds the container to hydrate -
|
|
163
|
-
* the entry is built once and cannot know what a given render chose. */
|
|
164
|
-
readonly rootId?: string;
|
|
165
|
-
/** When `false`, emit a complete but **non-hydrated** document - no client entry script, data
|
|
166
|
-
* globals, or modulepreloads. Used for server-rendered `_error` pages: a terminal state that needs no
|
|
167
|
-
* client takeover, and it sidesteps an SSR/hydrate mismatch (the server rendered the boundary, not
|
|
168
|
-
* the page the client manifest maps this route id to). Default `true`. */
|
|
169
|
-
readonly hydrate?: boolean;
|
|
170
|
-
/** Island client bundles (`@nifrajs/web/islands`) to load as `<script type="module">` in the document
|
|
171
|
-
* tail - emitted **regardless of `hydrate`**, so a static (`hydrate: false`) page can still mount
|
|
172
|
-
* no-framework islands. URLs are attribute-escaped. Empty/omitted ⇒ none (unchanged output). */
|
|
173
|
-
readonly islandScripts?: readonly string[];
|
|
174
|
-
/** CSP nonce applied to every framework-owned executable script in this document. */
|
|
175
|
-
readonly nonce?: string;
|
|
176
|
-
/**
|
|
177
|
-
* Advanced: a per-route slot the renderer fills with the request-invariant document pieces (shell
|
|
178
|
-
* prefix/suffix, tail statics) on the first render and reuses afterwards, skipping their re-assembly.
|
|
179
|
-
*
|
|
180
|
-
* Only pass a cache when every shell-shaping input is IDENTICAL across the requests sharing it:
|
|
181
|
-
* same `head` content (a static meta chain - never a `meta(data)` function), `title`, `styles`,
|
|
182
|
-
* `preload`, `islandScripts`, `clientEntry`, `rootId`, `hydrate`, and `prerenderedPaths`. Per-request
|
|
183
|
-
* values (`data`, `params`, `search`, `actionData`, `layoutData`, deferred state) are always assembled
|
|
184
|
-
* fresh and safe. A per-request `nonce` disables the cache automatically. `createWebApp` wires this
|
|
185
|
-
* per route, gated on the route + layout metas being static.
|
|
186
|
-
*/
|
|
187
|
-
readonly assemblyCache?: RenderAssemblyCache;
|
|
188
|
-
}
|
|
189
|
-
/** The mutable per-route slot {@link RenderPageOptions.assemblyCache} fills. Opaque - create as `{}`. */
|
|
190
|
-
export interface RenderAssemblyCache {
|
|
191
|
-
/** Shell up to (not including) the deferred-runtime insertion point. */
|
|
192
|
-
shellPre?: string;
|
|
193
|
-
/** Shell from after the deferred-runtime insertion point through the open `#root` container. */
|
|
194
|
-
shellPost?: string;
|
|
195
|
-
/** Tail opener: the inline script open tag + the route-id global (before the action global). */
|
|
196
|
-
tailPre?: string;
|
|
197
|
-
/** Tail mid: the prerendered-paths global (between the action and layout-data globals). */
|
|
198
|
-
tailMid?: string;
|
|
199
|
-
/** Tail data prefix: the `window.<data global>=` assignment head. */
|
|
200
|
-
tailData?: string;
|
|
201
|
-
/** Tail from after the serialized data through `</html>`. */
|
|
202
|
-
tailPost?: string;
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* `renderPage` input. A hydrating page (the default) must supply `clientEntry`, because the document
|
|
206
|
-
* loads it as a module script; a `hydrate: false` page may omit it, because nothing in the emitted
|
|
207
|
-
* document references it. Expressed as a union so the compiler enforces the pairing rather than the
|
|
208
|
-
* renderer discovering an empty `src` at runtime.
|
|
209
|
-
*/
|
|
210
|
-
export type RenderPageInput = RenderPageOptions & ({
|
|
211
|
-
readonly hydrate?: true;
|
|
212
|
-
readonly clientEntry: string;
|
|
213
|
-
} | {
|
|
214
|
-
readonly hydrate: false;
|
|
215
|
-
});
|
|
216
|
-
/**
|
|
217
|
-
* Server: render a full HTML document for a page - the adapter's hydration head + the SSR
|
|
218
|
-
* markup (**streamed**) + the serialized loader data + the client module - as a `Response`.
|
|
219
|
-
* The shell (`<head>` + the open container) flushes first, the adapter's app stream follows,
|
|
220
|
-
* then the tail (data globals + client entry). Pure Web Standards, so it returns straight from
|
|
221
|
-
* a nifra route handler and streams on any fetch runtime (Bun/Node/Deno/Workers).
|
|
222
|
-
*/
|
|
223
|
-
export declare function renderPage(options: RenderPageInput): MaybePromise<Response>;
|
|
224
|
-
export declare function renderPageResult(options: RenderPageInput): MaybePromise<RenderedPage>;
|
|
225
|
-
/** Options for {@link redirect}. */
|
|
226
|
-
export interface RedirectOptions {
|
|
227
|
-
/** HTTP status (default 303 See Other; pass 307/308 to preserve the method). */
|
|
228
|
-
readonly status?: number;
|
|
229
|
-
/** Allow an off-origin / absolute destination. Off by default: only a same-origin path (a single
|
|
230
|
-
* leading `/`) is permitted, so an action can't be turned into an open redirect by passing
|
|
231
|
-
* attacker-controlled input straight through. Set `true` for a deliberate external redirect. */
|
|
232
|
-
readonly external?: boolean;
|
|
233
|
-
/** Extra response headers. A redirect is no longer a `Response`, so there is no `.headers` to
|
|
234
|
-
* mutate after the fact - name them here. Cookies still ride `c.set`, as on any other response. */
|
|
235
|
-
readonly headers?: Readonly<Record<string, string>>;
|
|
236
|
-
}
|
|
237
|
-
/** A same-origin destination is an absolute path: one leading `/`, but NOT `//` (protocol-relative →
|
|
238
|
-
* another origin), and nothing a URL parser resolves off-origin. Everything else (absolute URL with
|
|
239
|
-
* a scheme, `//host`, `javascript:`, a bare relative `foo`) requires `external: true`. The predicate
|
|
240
|
-
* lives in the kernel - see `isSameOriginPath` - so this gate and the auth guards' `redirectTo`
|
|
241
|
-
* cannot drift apart. */
|
|
242
|
-
/**
|
|
243
|
-
* Build a redirect - return it from a route `action` for the Post/Redirect/Get pattern (POST
|
|
244
|
-
* mutates, 303 sends the browser to a fresh GET, so a reload doesn't re-submit). Defaults to 303
|
|
245
|
-
* (See Other); pass `{ status: 307 }` or `{ status: 308 }` to preserve the method.
|
|
246
|
-
*
|
|
247
|
-
* **Secure by default:** `location` must be a same-origin path (begins with `/`, not `//`). An
|
|
248
|
-
* off-origin/absolute destination throws unless you pass `{ external: true }` - this closes the
|
|
249
|
-
* open-redirect footgun of `return redirect(formData.get("next"))` on the no-JS (native-form) path,
|
|
250
|
-
* which serves the action's control-flow value verbatim.
|
|
251
|
-
*
|
|
252
|
-
* Returns a plain render, not a `Response`. A redirect is a status line and one header - the most
|
|
253
|
-
* body-less response there is - and building a `Response` for it costs the whole Web object plus, on
|
|
254
|
-
* Node, a stream drained back out. As data it renders on the same lane a handler's return takes.
|
|
255
|
-
* `redirect(...)` is still returned or thrown from exactly the same places; only `.status` /
|
|
256
|
-
* `.headers` are gone from the value, replaced by `options.headers` and the request's `c.set`.
|
|
257
|
-
*
|
|
258
|
-
* @param options redirect status, extra headers, and whether an off-origin destination is intentional.
|
|
259
|
-
*/
|
|
260
|
-
export declare function redirect(location: string, options?: RedirectOptions): ResponseResult;
|
|
261
|
-
/**
|
|
262
|
-
* Brand marking a `Response` as a **terminal-status signal** rather than a response to serve verbatim.
|
|
263
|
-
*
|
|
264
|
-
* A loader that throws a bare `Response` has always been passed straight through - that is how
|
|
265
|
-
* `throw redirect(...)` works, and apps rely on it. So "render the `_404` boundary at 404" cannot be
|
|
266
|
-
* expressed by throwing a plain `Response`: the framework would have no way to tell it apart from a
|
|
267
|
-
* hand-rolled body the app wants served exactly as written. The brand is that distinction, and
|
|
268
|
-
* checking it *before* the pass-through is what keeps every existing throw working unchanged.
|
|
269
|
-
*
|
|
270
|
-
* `Symbol.for` matches `RESPONSE_RESULT` above: a registry symbol survives two copies of this module,
|
|
271
|
-
* which a `unique symbol` would not - and a duplicate-install turning a 404 into a raw 404 body would
|
|
272
|
-
* be a maddening bug to trace.
|
|
273
|
-
*/
|
|
274
|
-
/** Derived from the `Headers` constructor rather than the DOM lib's `HeadersInit`: `@nifrajs/web`
|
|
275
|
-
* is consumed from DOM-free programs (the root tsconfig runs `types: ["bun"]`), and naming the DOM
|
|
276
|
-
* type here would break their build. Same workaround as `SSEInit.headers` in core. */
|
|
277
|
-
type HeadersLike = ConstructorParameters<typeof Headers>[0];
|
|
278
|
-
/** Options shared by {@link notFound}, {@link gone}, and {@link statusPage}. */
|
|
279
|
-
export interface StatusPageOptions {
|
|
280
|
-
/**
|
|
281
|
-
* Extra headers for the rendered response - `cache-control` above all.
|
|
282
|
-
*
|
|
283
|
-
* The defaults differ by status for a reason: a 404 may be a race with publication, so it wants a
|
|
284
|
-
* short TTL, while a 410 is a promise that the URL is permanently gone and can be cached hard.
|
|
285
|
-
* Getting this wrong is the difference between a crawler dropping a dead URL and re-fetching it
|
|
286
|
-
* for weeks.
|
|
287
|
-
*/
|
|
288
|
-
readonly headers?: HeadersLike;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Render the nearest `_404` page at status **404**. `throw` it from a loader when the record does not
|
|
292
|
-
* exist.
|
|
293
|
-
*
|
|
294
|
-
* This is the fix for the soft 404: a matched route whose loader finds nothing has otherwise no way to
|
|
295
|
-
* answer 404, so the path of least resistance is to return empty data and render "not found" inside a
|
|
296
|
-
* **200**. That looks correct in a browser and is invisible in review, which is why it ships and stays
|
|
297
|
-
* shipped - while search engines penalise it and keep the dead URL indexed.
|
|
298
|
-
*
|
|
299
|
-
* Returns `never`: these throw, so a loader narrows without a redundant `return`, and the type states
|
|
300
|
-
* the thing the "loaders `throw` redirect, actions `return` it" rule already trips people on.
|
|
301
|
-
*/
|
|
302
|
-
export declare function notFound(options?: StatusPageOptions): never;
|
|
303
|
-
/**
|
|
304
|
-
* Render a terminal page at status **410 Gone**. `throw` it from a loader for a record that existed and
|
|
305
|
-
* was deliberately removed - a withdrawn listing, a deleted post.
|
|
306
|
-
*
|
|
307
|
-
* 410 is not a pedantic 404: it tells a crawler to **drop** the URL rather than re-fetch it for weeks
|
|
308
|
-
* on the assumption the 404 was transient. Uses `_410.tsx` if the app has one, otherwise `_404`.
|
|
309
|
-
*/
|
|
310
|
-
export declare function gone(options?: StatusPageOptions): never;
|
|
311
|
-
/**
|
|
312
|
-
* Render a terminal page at any 4xx/5xx status - the escape hatch behind {@link notFound} and
|
|
313
|
-
* {@link gone} (402, 451, …). Uses `_<status>.tsx` if present, otherwise `_404`.
|
|
314
|
-
*/
|
|
315
|
-
export declare function statusPage(status: number, options?: StatusPageOptions): never;
|
|
316
|
-
/** The wrapper `revalidate()` returns: the action's `data` plus the paths it changed. A plain tagged
|
|
317
|
-
* shape (not a class) so `@nifrajs/client`'s `ActionData` can unwrap it structurally without importing
|
|
318
|
-
* from `@nifrajs/web`. `createWebApp` strips the wrapper - the client receives `data` as the body and
|
|
319
|
-
* the paths via the `X-Nifra-Revalidate` header. */
|
|
320
|
-
export interface RevalidateResult<T> {
|
|
321
|
-
readonly __nifraRevalidate: readonly string[];
|
|
322
|
-
readonly data: T;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Return this from an action to declare which routes the mutation changed (alongside the action's
|
|
326
|
-
* `data`). `createWebApp` sets the `X-Nifra-Revalidate` response header; after the submit the client
|
|
327
|
-
* marks those cached routes stale - refetching the active one and any mounted fetcher showing them -
|
|
328
|
-
* so a mutation can refresh views beyond the one that was submitted. `data` is still surfaced to the
|
|
329
|
-
* component as `actionData` (the wrapper is transparent to `ActionData<typeof action>`).
|
|
330
|
-
*/
|
|
331
|
-
export declare function revalidate<T>(paths: readonly string[], data: T): RevalidateResult<T>;
|
|
332
|
-
/**
|
|
333
|
-
* Serialize loader data for embedding inside an inline `<script>`. `JSON.stringify` alone
|
|
334
|
-
* is NOT safe there: a string containing `</script>` or `<!--` would break out of the
|
|
335
|
-
* script element (an XSS vector). Escape `<`/`>` to `\uXXXX`, plus the U+2028/U+2029
|
|
336
|
-
* separators.
|
|
337
|
-
*/
|
|
338
|
-
export declare function serializeData(data: unknown): string;
|
|
339
|
-
/**
|
|
340
|
-
* A `<link rel="canonical">` descriptor for a route's `meta.link`. The canonical URL tells search
|
|
341
|
-
* engines which URL is authoritative for a page (deduping query-string / tracking variants).
|
|
342
|
-
*
|
|
343
|
-
* ```ts
|
|
344
|
-
* export const meta = (a) => ({ link: [canonical(`https://site.com/posts/${a.params.slug}`)] })
|
|
345
|
-
* ```
|
|
346
|
-
*/
|
|
347
|
-
export declare function canonical(href: string): LinkDescriptor;
|
|
348
|
-
/** Inputs for {@link openGraph} - the common Open Graph properties. All optional; only the provided
|
|
349
|
-
* ones become tags. `type` defaults to `"website"`. */
|
|
350
|
-
export interface OpenGraphInput {
|
|
351
|
-
readonly title?: string;
|
|
352
|
-
readonly description?: string;
|
|
353
|
-
/** Absolute URL of the share image (`og:image`). */
|
|
354
|
-
readonly image?: string;
|
|
355
|
-
/** Canonical URL of the page (`og:url`). */
|
|
356
|
-
readonly url?: string;
|
|
357
|
-
/** Object type (`og:type`) - `"website"`, `"article"`, … Default `"website"`. */
|
|
358
|
-
readonly type?: string;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Build the Open Graph `<meta property="og:*">` entries for a route's `meta.meta`. Returns only the
|
|
362
|
-
* properties you supplied (plus `og:type`, defaulting to `"website"`), so it composes with other meta.
|
|
363
|
-
*
|
|
364
|
-
* ```ts
|
|
365
|
-
* export const meta = { meta: [...openGraph({ title: "Nifra", image: "https://site.com/og.png" })] }
|
|
366
|
-
* ```
|
|
367
|
-
*/
|
|
368
|
-
export declare function openGraph(input: OpenGraphInput): MetaDescriptor[];
|
|
369
|
-
/**
|
|
370
|
-
* Build a JSON-LD `<script type="application/ld+json">` entry for a route's `meta.script` from a plain
|
|
371
|
-
* object. `JSON.stringify` produces the body; the head renderer breakout-escapes it (see
|
|
372
|
-
* `escapeScriptContent`), so a string field containing `</script>` is embedded safely.
|
|
373
|
-
*
|
|
374
|
-
* ```ts
|
|
375
|
-
* export const meta = {
|
|
376
|
-
* script: [jsonLd({ "@context": "https://schema.org", "@type": "Article", headline: "Hi" })],
|
|
377
|
-
* }
|
|
378
|
-
* ```
|
|
379
|
-
*/
|
|
380
|
-
export declare function jsonLd(data: Record<string, unknown>): ScriptDescriptor;
|
|
381
|
-
/**
|
|
382
|
-
* Deliberately unsafe escape hatch for executable inline code. The required nonce keeps the result
|
|
383
|
-
* compatible with a strict CSP and makes the security-sensitive choice visible at the call site.
|
|
384
|
-
*/
|
|
385
|
-
export declare function unsafeInlineScript(content: string, options: {
|
|
386
|
-
readonly nonce: string;
|
|
387
|
-
readonly type?: "module" | "text/javascript";
|
|
388
|
-
}): UnsafeScriptDescriptor;
|
|
389
|
-
export interface CreateWebAppOptions<Env = unknown> {
|
|
390
|
-
readonly adapter: RenderAdapter;
|
|
391
|
-
readonly manifest: Manifest;
|
|
392
|
-
/** URL of the built client entry (module script) injected into every page. */
|
|
393
|
-
readonly clientEntry: string;
|
|
394
|
-
/** Default document title for all pages. */
|
|
395
|
-
readonly title?: string;
|
|
396
|
-
/**
|
|
397
|
-
* Options for the underlying `server()` - `requestTimeoutMs`, `admission`, `gracefulSignals`, and
|
|
398
|
-
* the rest of {@link ServerOptions}.
|
|
399
|
-
*
|
|
400
|
-
* Needed because the `Server` is constructed in here, so a caller has no other way to reach its
|
|
401
|
-
* constructor: a page app could set no request timeout and no capacity gate, which are exactly the
|
|
402
|
-
* two knobs a production readiness check looks for. An SSR app wants them MORE than a backend does -
|
|
403
|
-
* a render is slow and allocation-heavy, so a burst that a JSON API would absorb is the one that
|
|
404
|
-
* exhausts the pod.
|
|
405
|
-
*
|
|
406
|
-
* Applies to the whole app, {@link mounts} and the {@link api} auto-mount included: the capacity gate
|
|
407
|
-
* sits at the fetch entry, ahead of the request hooks those are dispatched from.
|
|
408
|
-
*/
|
|
409
|
-
readonly server?: ServerOptions;
|
|
410
|
-
/**
|
|
411
|
-
* Runs against the app BEFORE any page route is registered - the seam for `securityHeaders()`,
|
|
412
|
-
* `requestId()`, `logger()`, a rate limit, or anything else applied with `use`.
|
|
413
|
-
*
|
|
414
|
-
* ```ts
|
|
415
|
-
* createWebApp({
|
|
416
|
-
* …,
|
|
417
|
-
* use: (app) => {
|
|
418
|
-
* app.use(securityHeaders())
|
|
419
|
-
* app.use(requestId())
|
|
420
|
-
* },
|
|
421
|
-
* })
|
|
422
|
-
* ```
|
|
423
|
-
*
|
|
424
|
-
* A callback rather than an array because `use` is overloaded - `Middleware`, `IdentityPlugin`,
|
|
425
|
-
* `ContextPlugin` - and only the real call site instantiates the right overload. The return value
|
|
426
|
-
* is ignored: this is for cross-cutting concerns, not for declaring routes (declare those on the
|
|
427
|
-
* returned app, where they get their types).
|
|
428
|
-
*
|
|
429
|
-
* **Why the timing matters.** `beforeHandle`, `afterHandle`, `around`, `derive`/`decorate`, and
|
|
430
|
-
* `onError` are snapshotted into each route AS IT IS DECLARED, and `createWebApp` declares every
|
|
431
|
-
* page (plus the `/*` catch-all) before it returns - so a caller's `app.use(…)` afterwards binds
|
|
432
|
-
* them to nothing, silently. `requestId()` is exactly that case: it is a `derive`, so applied late
|
|
433
|
-
* it leaves every page without `c.requestId`. Route assurance evidence is order-scoped the same
|
|
434
|
-
* way, so a late `securityHeaders()` leaves the pages unable to PROVE the header to `nifra assure`
|
|
435
|
-
* even though it does still set it.
|
|
436
|
-
*
|
|
437
|
-
* `onRequest`/`onResponse` (and the response header/body hooks) are app-global arrays read at
|
|
438
|
-
* request time, so those alone DO work when added late. Using this seam for everything avoids
|
|
439
|
-
* having to remember which is which.
|
|
440
|
-
*
|
|
441
|
-
* Runs ahead of the {@link mounts} / {@link api} request hooks, so an `onRequest` middleware guards
|
|
442
|
-
* a mounted auth handler too.
|
|
443
|
-
*
|
|
444
|
-
* A `ContextPlugin` applied here takes runtime effect but cannot widen the declared return type of
|
|
445
|
-
* this function, so `c.requestId` is not typed on routes you declare afterwards. Named plugins are
|
|
446
|
-
* idempotent, so `app.use(requestId())` on the returned app recovers the TYPE without applying the
|
|
447
|
-
* plugin a second time.
|
|
448
|
-
*/
|
|
449
|
-
readonly use?: (app: ReturnType<typeof server<Env>>) => void;
|
|
450
|
-
/** Injected into each loader's `ctx.api` - typically an `inProcessClient(app)` (typed
|
|
451
|
-
* per-route via `@nifrajs/client`'s `createRoutes`). Opaque to the core.
|
|
452
|
-
*
|
|
453
|
-
* **Auto-mount.** Every `inProcessClient(backend)` exposes the symbol-keyed platform-aware backend
|
|
454
|
-
* mount interface from `@nifrajs/core/mount`; `createWebApp` also serves that backend over HTTP at
|
|
455
|
-
* {@link apiPrefix} (default `/api`): a request whose pathname starts with the prefix is dispatched
|
|
456
|
-
* before page routing with the same `env`/`waitUntil` platform context, and the backend's `Response`
|
|
457
|
-
* is returned untouched. The mount runs in `nifra dev` too. Pass `apiPrefix: ""` to disable it. */
|
|
458
|
-
readonly api?: unknown;
|
|
459
|
-
/** HTTP path prefix the {@link api} backend is auto-mounted at (default `"/api"`). A request whose
|
|
460
|
-
* pathname is exactly the prefix or starts with `prefix + "/"` is dispatched to the backend before
|
|
461
|
-
* page routing; the backend therefore defines its routes at the **full** path (`server().post("/api/
|
|
462
|
-
* sync", …)`), matching the in-process `inProcessClient` call sites. Set to `""` to disable the
|
|
463
|
-
* auto-mount entirely (the app serves pages only and `api` stays a loader-only `ctx.api`). Mounting
|
|
464
|
-
* is also a no-op when `api` does not expose the symbol mount. */
|
|
465
|
-
readonly apiPrefix?: string;
|
|
466
|
-
/**
|
|
467
|
-
* Strip {@link apiPrefix} from the pathname before dispatching to `api` (default `false`).
|
|
468
|
-
*
|
|
469
|
-
* The default suits a backend that declares FULL paths (`server().post("/api/sync", …)`), which is
|
|
470
|
-
* right when it is only ever mounted here. Set this when the backend declares its routes WITHOUT the
|
|
471
|
-
* prefix because it also runs standalone behind its own shell, so its paths cannot carry a prefix that
|
|
472
|
-
* only exists when it is mounted. Without it every request 404s inside the backend, and the workaround
|
|
473
|
-
* is a `Proxy` that rewrites each URL.
|
|
474
|
-
*/
|
|
475
|
-
readonly apiStrip?: boolean;
|
|
476
|
-
/**
|
|
477
|
-
* Sub-apps mounted ahead of page routing - an auth handler, a webhook receiver, a stack's routes.
|
|
478
|
-
*
|
|
479
|
-
* Structural on purpose: anything with `{ path, app: { fetch } }` fits, so a library that exposes its
|
|
480
|
-
* routes as such a list mounts as `mounts: theirRoutes` without `@nifrajs/web` taking a dependency on
|
|
481
|
-
* it. `better-auth` is the motivating case - it is not a `backend` route, so `/api/auth/*` used to 404
|
|
482
|
-
* silently.
|
|
483
|
-
*
|
|
484
|
-
* Tried longest-path-first and BEFORE the `api` mount, so a mount at `/api/auth` wins over a backend
|
|
485
|
-
* at `/api` no matter which was declared first. `stripPrefix` is the per-mount form of {@link apiStrip}:
|
|
486
|
-
* leave it off to pass the full path through.
|
|
487
|
-
*/
|
|
488
|
-
readonly mounts?: ReadonlyArray<{
|
|
489
|
-
readonly path: string;
|
|
490
|
-
readonly app: {
|
|
491
|
-
fetch(request: Request): Response | Promise<Response>;
|
|
492
|
-
};
|
|
493
|
-
readonly stripPrefix?: boolean;
|
|
494
|
-
}>;
|
|
495
|
-
/** Secret for **draft / preview mode** (see `enableDraft`). When set, a request carrying a valid
|
|
496
|
-
* signed `__nifra_draft` cookie gets `ctx.draft === true` in loaders/actions (else always `false`).
|
|
497
|
-
* Pair with `withISR({ draftSecret })` so editors bypass the cache. Omit to disable draft mode. */
|
|
498
|
-
readonly draftSecret?: string;
|
|
499
|
-
/** Per-route chunk URLs (`buildClient`'s `BuildManifest.routes`) - `routeId → [layout chunks…, own
|
|
500
|
-
* chunk]`. When present, each page `modulepreload`s its matched route's chunks alongside the entry,
|
|
501
|
-
* so the route code downloads in parallel (no entry→route-chunk waterfall). Omit ⇒ entry-only. */
|
|
502
|
-
readonly routePreload?: Readonly<Record<string, readonly string[]>>;
|
|
503
|
-
/** The app's bundled stylesheet URLs (`buildClient`'s `BuildManifest.css`) - the aggregate, injected
|
|
504
|
-
* as `<link rel="stylesheet">` in a page's `<head>`. Used as the fallback for any route absent from
|
|
505
|
-
* {@link routeStyles}. Omit ⇒ no links (dev, where Vite injects CSS, or a CSS-free app). */
|
|
506
|
-
readonly styles?: readonly string[];
|
|
507
|
-
/** Per-route stylesheet URLs (`buildClient`'s `BuildManifest.routeStyles`) - `routeId → [chain CSS]`.
|
|
508
|
-
* When a matched route has an entry here, only those (its layout chain + own CSS) are linked instead
|
|
509
|
-
* of the aggregate `styles`, so a page ships only the CSS it uses. An empty array ⇒ no `<link>` (the
|
|
510
|
-
* page imports no CSS). Routes absent here fall back to `styles`. Omit ⇒ always use `styles`. */
|
|
511
|
-
readonly routeStyles?: Readonly<Record<string, readonly string[]>>;
|
|
512
|
-
/** SSG: the prerendered-path set (e.g. `enumerateStaticRoutes(routes).paths` or the build's
|
|
513
|
-
* `prerendered.json`). Injected as `window.__NIFRA_PRERENDERED__` on every page so a client soft-nav
|
|
514
|
-
* into a prerendered route fetches its static `_data.json` instead of hitting the worker. */
|
|
515
|
-
readonly prerenderedPaths?: readonly string[];
|
|
516
|
-
/** Publish the project's `AGENTS.md` inside `/llms.txt` and `/llms-full.txt`. **Off by default**:
|
|
517
|
-
* those endpoints are public and unauthenticated, while `AGENTS.md` is a repo file written for the
|
|
518
|
-
* team - unreleased feature names, internal hostnames, and "don't touch X yet" notes live there
|
|
519
|
-
* routinely. Turn it on only for a repo whose guidelines you would publish as a page. */
|
|
520
|
-
readonly publishLocalGuidelines?: boolean;
|
|
521
|
-
/** SSG: per dynamic route pattern, its `getStaticPaths` `fallback` (from `enumerateStaticRoutes` or
|
|
522
|
-
* the build's `prerendered.json`). A route mapped to `"404"` rejects any path NOT in
|
|
523
|
-
* `prerenderedPaths` with the 404 page - the unlisted path simply doesn't exist. `"ssr"` (the
|
|
524
|
-
* default for unmapped routes) renders unlisted paths on-demand. */
|
|
525
|
-
readonly staticFallbacks?: Readonly<Record<string, "ssr" | "404">>;
|
|
526
|
-
/** In-memory reference cache for explicitly `static` boundary values. It never persists payloads
|
|
527
|
-
* across processes; operated/durable cache implementations stay outside the public framework. */
|
|
528
|
-
readonly staticBoundaryCache?: import("./boundary.js").StaticBoundaryCache;
|
|
529
|
-
/** Observe every loader/action failure - for error-reporting plugins (Sentry-style). Called for
|
|
530
|
-
* real throws (not control-flow `Response`s like `redirect`), **before** the nearest `_error`
|
|
531
|
-
* boundary renders / a soft-nav 500 / a rethrow - so it sees errors that the boundary would
|
|
532
|
-
* otherwise hide. Observation only; its own throws are swallowed so a faulty reporter can't break
|
|
533
|
-
* rendering. (`beforeLoader` is intentionally omitted - the core HTTP hooks already cover
|
|
534
|
-
* pre-request work.) */
|
|
535
|
-
readonly onLoaderError?: (error: unknown, ctx: {
|
|
536
|
-
readonly request: Request;
|
|
537
|
-
readonly params: Readonly<Record<string, string>>;
|
|
538
|
-
readonly route: string;
|
|
539
|
-
}) => void;
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Build a nifra app from a route manifest: every route SSRs its layout chain via `renderPage`,
|
|
543
|
-
* and a wildcard catch-all renders `_404` (or a plain 404). Reuses @nifrajs/core's router +
|
|
544
|
-
* lifecycle, so matching, params, and precedence are battle-tested. fs-free - feed it a
|
|
545
|
-
* manifest from `discoverRoutes` (`@nifrajs/web/fs`) at startup, so the served app stays portable.
|
|
546
|
-
*
|
|
547
|
-
* **Typed platform bindings.** Pass `Env` - `createWebApp<Env>({ … })` - to declare the app's Workers
|
|
548
|
-
* bindings ONCE. It seeds the returned `Server`'s context with `{ env: Env }` (exactly as the backend's
|
|
549
|
-
* `server<Env>()` does), so `app.fetch(req, { env })` / `toFetchHandler(app)` type-check the `env`
|
|
550
|
-
* argument against the declared shape - no per-binding cast at the edge entry. Per-route loaders/actions
|
|
551
|
-
* stay typed independently of this call: annotate them with `@nifrajs/client`'s `LoaderArgs<Api, Env>`
|
|
552
|
-
* (same `Env`) so `ctx.env.MY_KV` is typed there too. Omit the parameter and `Env` is `unknown` - the
|
|
553
|
-
* secure default; validate at the trust boundary before use.
|
|
554
|
-
*/
|
|
555
|
-
export declare function createWebApp<Env = unknown>(options: CreateWebAppOptions<Env>): ReturnType<typeof server<Env>>;
|
|
556
|
-
export interface GenerateClientEntryOptions {
|
|
557
|
-
/**
|
|
558
|
-
* Module specifier for the adapter's client runtime, e.g. `"@nifrajs/web-solid/client"`.
|
|
559
|
-
*
|
|
560
|
-
* **Contract:** the module MUST export `mountRouter({ router, routes, container })`. The generated
|
|
561
|
-
* bootstrap imports the specifier and calls it - so a self-executing entry that mounts on import
|
|
562
|
-
* builds cleanly and then does nothing, which is the trap this contract exists to name. The type is
|
|
563
|
-
* a bare `string` because a specifier is resolved by the bundler, not the type system, so the
|
|
564
|
-
* requirement is enforced by the bootstrap instead: it throws immediately, naming this module and
|
|
565
|
-
* the missing export, rather than failing later as `mountRouter is not a function`.
|
|
566
|
-
*/
|
|
567
|
-
readonly clientModule: string;
|
|
568
|
-
/** Turn a route/layout source file (relative to the routes dir) into an import specifier. */
|
|
569
|
-
readonly resolve: (file: string) => string;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Codegen: emit a client-entry module (as source) that lazily imports each route's layout chain
|
|
573
|
-
* (so `Bun.build` with `splitting` code-splits one chunk per route), builds a `patterns` list,
|
|
574
|
-
* then creates the agnostic router store (with a `loadModule` hook), installs history + form
|
|
575
|
-
* interception, loads the initial route's chunk, and hydrates the adapter's stateful Router. The
|
|
576
|
-
* initial route is derived from the URL (falling back to the server-injected route id, e.g.
|
|
577
|
-
* `_404`), so after hydration the Router owns navigation and swaps routes without full reloads.
|
|
578
|
-
* Bun has no `import.meta.glob`, so file-based routing needs this. Write the result to a file and
|
|
579
|
-
* bundle it with `buildClient` / `Bun.build` (+ the adapter's transform).
|
|
580
|
-
*/
|
|
581
|
-
export declare function generateClientEntry(manifest: Manifest, options: GenerateClientEntryOptions): string;
|
|
582
|
-
export interface GenerateRouteSearchTypesOptions {
|
|
583
|
-
/** Turn a route source file into a module specifier for a `typeof import(...)` type - the same contract
|
|
584
|
-
* as `generateClientEntry`'s `resolve`, but WITHOUT a file extension (a `.d.ts` imports a module, not a
|
|
585
|
-
* path). Relative to wherever the emitted `.d.ts` is written. */
|
|
586
|
-
readonly resolve: (file: string) => string;
|
|
587
|
-
/** The module whose `RouteSearch` interface is augmented (default `"@nifrajs/web"`). Every adapter's
|
|
588
|
-
* `NavigateTarget` reads `@nifrajs/web`'s `RouteSearch`, so the default types `navigate` on all of them. */
|
|
589
|
-
readonly module?: string;
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Codegen: emit a `.d.ts` that types cross-route `navigate({ to, search })` against each route's
|
|
593
|
-
* `searchSchema`. It augments the {@link RouteSearch} map with `"<pattern>": SearchOf<typeof import(...)>`
|
|
594
|
-
* for every **static** route (one with no `:param`/`*` segment - a concrete `to` a caller can pass; a
|
|
595
|
-
* dynamic route's concrete path can't match its pattern key, so those keep the loose object form). Written
|
|
596
|
-
* by `nifra sync-routes` next to the route tree and included in the app's `tsconfig`; because it is
|
|
597
|
-
* regenerated from the route files, a `navigate` whose `search` no longer matches the route's schema
|
|
598
|
-
* becomes a `tsc` error - the same drift guarantee as nifra's typed client, no hand-maintained map.
|
|
599
|
-
*/
|
|
600
|
-
export declare function generateRouteSearchTypes(manifest: Manifest, options: GenerateRouteSearchTypesOptions): string;
|
|
601
|
-
export interface GenerateServerManifestOptions {
|
|
602
|
-
/** Turn a route/layout source file (relative to the routes dir) into an import specifier -
|
|
603
|
-
* same contract as `generateClientEntry`'s `resolve`. */
|
|
604
|
-
readonly resolve: (file: string) => string;
|
|
605
|
-
/** The content-hashed client entry URL (from `buildClient`'s manifest), **baked** into the emitted
|
|
606
|
-
* module - a disk-less worker can't read `manifest.json` at runtime. */
|
|
607
|
-
readonly clientEntry: string;
|
|
608
|
-
/** The app's aggregate stylesheet URLs (`buildClient`'s `BuildManifest.css`) - baked as
|
|
609
|
-
* `export const styles` so the server entry can hand them to `createWebApp` (→ `<link rel="stylesheet">`
|
|
610
|
-
* in `<head>`). Without this the built SSR page ships no CSS link and renders unstyled. */
|
|
611
|
-
readonly styles?: readonly string[] | undefined;
|
|
612
|
-
/** Per-route stylesheet URLs (`buildClient`'s `BuildManifest.routeStyles`) - baked as
|
|
613
|
-
* `export const routeStyles` so a page links only the CSS its route chain uses. */
|
|
614
|
-
readonly routeStyles?: Readonly<Record<string, readonly string[]>> | undefined;
|
|
615
|
-
/** Emit **lazy** per-route loaders (`() => import("./routes/x")`, a static specifier) instead of
|
|
616
|
-
* eager `import * as`, so a bundler with code-splitting emits one chunk per route - loaded on the
|
|
617
|
-
* first request to it, not all at boot (smaller cold-start parse). Default `false` (eager). Both
|
|
618
|
-
* modes are fs-free with statically-analyzable specifiers; only the *when* differs. */
|
|
619
|
-
readonly lazy?: boolean;
|
|
620
|
-
}
|
|
621
|
-
export declare function generateServerManifest(manifest: Manifest, options: GenerateServerManifestOptions): string;
|
|
15
|
+
export { type GenerateClientEntryOptions, type GenerateRouteSearchTypesOptions, type GenerateServerManifestOptions, generateClientEntry, generateRouteSearchTypes, generateServerManifest, } from "./internal/codegen.js";
|
|
16
|
+
export { mergeHeads, resolveMeta } from "./internal/head-merge.js";
|
|
17
|
+
export { canonical, gone, jsonLd, notFound, type OpenGraphInput, openGraph, type RedirectOptions, type RenderAssemblyCache, type RenderedPage, type RenderPageInput, type RenderPageOptions, type RevalidateResult, redirect, renderPage, renderPageResult, revalidate, type StatusPageOptions, serializeData, statusPage, unsafeInlineScript, } from "./internal/render-document.js";
|
|
18
|
+
export { DEFAULT_DEV_PORT, PRE_HYDRATION_GUARD, type ServerOnly, } from "./internal/runtime-contract.js";
|
|
622
19
|
/**
|
|
623
20
|
* The two file-name conventions that decide what never reaches a browser: a `*.server` module is
|
|
624
21
|
* EMPTIED in the client build, a `*.fn` module is REPLACED with client stubs.
|
|
@@ -630,4 +27,13 @@ export declare function generateServerManifest(manifest: Manifest, options: Gene
|
|
|
630
27
|
* server-only" should import the matcher rather than re-encode it.
|
|
631
28
|
*/
|
|
632
29
|
export { SERVER_FN_MODULE, SERVER_ONLY_MODULE } from "./internal/server-boundary.js";
|
|
30
|
+
export { type CreateWebAppOptions, createWebApp, } from "./internal/web-app.js";
|
|
31
|
+
export { type CachedResponse, type CacheStore, ISR_REVALIDATE_HEADER, ISR_REVALIDATE_TAGS_HEADER, ISR_STATUS_HEADER, type ISRApp, type ISROptions, type ISRPlatform, KVCacheStore, type KVCacheStoreOptions, type KVNamespaceLike, MemoryCacheStore, type MemoryCacheStoreOptions, type RevalidateEndpointOptions, revalidateEndpoint, withISR, } from "./isr.js";
|
|
32
|
+
export { type Action, buildManifest, type ClientAction, type ClientActionArgs, type ClientActionResult, type ClientLoader, type ClientLoaderArgs, type ClientRequestBody, type ClientRouteHooks, enumerateStaticRoutes, filePathToPattern, filePathToPatterns, type GetStaticPaths, type InertScriptType, type LayoutEntry, type LinkDescriptor, type Loader, type LoaderContext, type Manifest, type Meta, type MetaArgs, type MetaDescriptor, type MetaInput, type RouteEntry, type RouteModule, type ScriptDescriptor, type StaticPath, type StaticPaths, type StaticRoutes, type UnsafeScriptDescriptor, } from "./manifest.js";
|
|
33
|
+
export { type Blocker, type BlockerController, type BlockerFunction, type BlockerLocation, type BlockerState, type BrowserNavigate, getBrowserNavigate, IDLE_BLOCKER, type NavigateFunction, type NavigateOptions, type NavigateSearchOf, type NavigateTargetInput, type RouteSearch, registerBlocker, resolveNavigate, setBlockerController, setBrowserNavigate, } from "./navigation.js";
|
|
34
|
+
export { type PublicDirCache, resolvePublicPath, type ServePublicDirOptions, servePublicDir, } from "./public-dir.js";
|
|
35
|
+
export { createMutation, createQueryClient, type DehydratedState, hashQueryKey, type InfiniteData, type InfiniteQueryHandle, type InfiniteQueryOptions, type MutationCallbacks, type MutationHandle, type MutationState, type MutationStatus, type QueryClient, type QueryClientOptions, type QueryHandle, type QueryOptions, type QueryState, type QueryStatus, } from "./query.js";
|
|
36
|
+
export { ACTION_GLOBAL, BOUNDARY_GLOBAL, DATA_GLOBAL, LAYOUT_DATA_GLOBAL, type RenderAdapter, type RenderProps, ROOT_ATTRIBUTE, ROUTE_GLOBAL, type SsrModuleLoader, setSsrModuleLoader, ssrModuleLoader, } from "./render-seam.js";
|
|
37
|
+
export { type ClientRouter, type ClientRouterOptions, createClientRouter, createMatcher, DATA_HEADER, type Fetcher, type FetcherState, type FetchRouteData, type MountRouterOptions, NAV_FROM_HEADER, REDIRECT_HEADER, RETAIN_HEADER, REVALIDATE_HEADER, type RouteMatch, type RoutePattern, type RouterState, STATUS_HEADER, type Submission, type SubmitOptions, } from "./router.js";
|
|
38
|
+
export { type SearchOf, searchOf, searchOfChain, serializeSearch } from "./search.js";
|
|
633
39
|
//# sourceMappingURL=index.d.ts.map
|