@rangojs/router 0.16.0 → 0.17.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/README.md +254 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/navigation-transaction.d.ts +6 -0
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/scroll-restoration.d.ts +7 -0
- package/dist/types/cache/cache-exec-scope.d.ts +18 -1
- package/dist/types/cache/cache-scope.d.ts +34 -5
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +53 -13
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +15 -3
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.rsc.d.ts +4 -5
- package/dist/types/components/DefaultDocument.d.ts +5 -2
- package/dist/types/context-var.d.ts +6 -5
- package/dist/types/escape-script.d.ts +1 -1
- package/dist/types/handles/MetaTags.d.ts +5 -4
- package/dist/types/handles/Scripts.d.ts +8 -7
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/handles/script.d.ts +17 -16
- package/dist/types/href-client.d.ts +1 -1
- package/dist/types/html.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +3 -2
- package/dist/types/loader-store.d.ts +7 -4
- package/dist/types/reverse.d.ts +36 -4
- package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
- package/dist/types/route-definition/helpers-types.d.ts +33 -9
- package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
- package/dist/types/route-types.d.ts +1 -1
- package/dist/types/router/debug-manifest.d.ts +3 -2
- package/dist/types/router/error-handling.d.ts +20 -0
- package/dist/types/router/handler-context.d.ts +6 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +3 -2
- package/dist/types/router/router-context.d.ts +3 -1
- package/dist/types/router/router-interfaces.d.ts +24 -2
- package/dist/types/router/router-options.d.ts +8 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +37 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +3 -3
- package/dist/types/router/segment-resolution/mask-nested.d.ts +7 -7
- package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
- package/dist/types/router/segment-wrappers.d.ts +1 -1
- package/dist/types/rsc/response-route-handler.d.ts +1 -1
- package/dist/types/rsc/rsc-rendering.d.ts +1 -2
- package/dist/types/rsc/shell-capture-constants.d.ts +8 -0
- package/dist/types/rsc/shell-capture.d.ts +5 -4
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +10 -0
- package/dist/types/server/context.d.ts +33 -3
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +24 -21
- package/dist/types/ssr/index.d.ts +15 -0
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/generated-routes.d.ts +2 -2
- package/dist/types/testing/internal/context.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +32 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
- package/dist/types/testing/vitest.d.ts +35 -1
- package/dist/types/theme/ThemeScript.d.ts +3 -3
- package/dist/types/types/cache-types.d.ts +14 -10
- package/dist/types/types/handler-context.d.ts +14 -0
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/response-types.d.ts +3 -12
- package/dist/types/use-loader.d.ts +12 -3
- package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
- package/dist/types/vite/rango.d.ts +1 -1
- package/dist/vite/index.js +1381 -1346
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +65 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +207 -97
- package/skills/caching/SKILL.md +295 -93
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +53 -31
- package/skills/cloudflare/SKILL.md +72 -20
- package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
- package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
- package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
- package/skills/comparison/SKILL.md +5 -0
- package/skills/comparison/references/framework-comparison.md +39 -33
- package/skills/composability/SKILL.md +38 -29
- package/skills/css/SKILL.md +10 -13
- package/skills/debug-manifest/SKILL.md +74 -31
- package/skills/defer-hydration/SKILL.md +2 -1
- package/skills/deployment-caching/SKILL.md +6 -1
- package/skills/document-cache/SKILL.md +92 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +53 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +31 -16
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +37 -15
- package/skills/hooks/urls.md +7 -5
- package/skills/host-router/SKILL.md +64 -12
- package/skills/i18n/SKILL.md +60 -34
- package/skills/intercept/SKILL.md +161 -26
- package/skills/layout/SKILL.md +106 -50
- package/skills/links/SKILL.md +51 -19
- package/skills/loader/SKILL.md +242 -106
- package/skills/middleware/SKILL.md +119 -23
- package/skills/migrate-nextjs/SKILL.md +100 -45
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +49 -38
- package/skills/migrate-react-router/component-migration.md +25 -6
- package/skills/migrate-react-router/data-and-actions.md +18 -5
- package/skills/migrate-react-router/route-mapping.md +12 -6
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +28 -14
- package/skills/parallel/SKILL.md +75 -39
- package/skills/ppr/SKILL.md +345 -150
- package/skills/prerender/SKILL.md +189 -100
- package/skills/rango/SKILL.md +65 -34
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +165 -60
- package/skills/router-setup/SKILL.md +418 -240
- package/skills/scripts/SKILL.md +31 -20
- package/skills/server-actions/SKILL.md +220 -59
- package/skills/shell-manifest/SKILL.md +12 -7
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +68 -32
- package/skills/testing/cache-prerender.md +55 -29
- package/skills/testing/client-components.md +59 -6
- package/skills/testing/e2e-parity.md +12 -2
- package/skills/testing/flight.md +19 -11
- package/skills/testing/handles.md +8 -5
- package/skills/testing/loader.md +8 -5
- package/skills/testing/middleware.md +8 -3
- package/skills/testing/predicates.md +120 -0
- package/skills/testing/render-handler.md +70 -22
- package/skills/testing/response-routes.md +11 -4
- package/skills/testing/reverse-and-types.md +20 -14
- package/skills/testing/server-actions.md +12 -3
- package/skills/testing/server-tree.md +9 -0
- package/skills/testing/setup.md +9 -5
- package/skills/theme/SKILL.md +106 -29
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +126 -47
- package/skills/typesafety/generated-files-and-cli.md +26 -14
- package/skills/typesafety/params-and-search.md +44 -19
- package/skills/typesafety/route-types.md +50 -14
- package/skills/use-cache/SKILL.md +200 -82
- package/skills/vercel/SKILL.md +21 -11
- package/skills/view-transitions/SKILL.md +41 -20
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/index.ts +2 -2
- package/src/browser/navigation-bridge.ts +3 -4
- package/src/browser/navigation-transaction.ts +22 -2
- package/src/browser/partial-update.ts +35 -25
- package/src/browser/react/ScrollRestoration.tsx +6 -6
- package/src/browser/rsc-router.tsx +1 -1
- package/src/browser/scroll-restoration.ts +53 -6
- package/src/cache/cache-exec-scope.ts +37 -4
- package/src/cache/cache-key-utils.ts +1 -6
- package/src/cache/cache-runtime.ts +230 -61
- package/src/cache/cache-scope.ts +76 -12
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +132 -28
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/tag-invalidation.ts +4 -3
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +16 -3
- package/src/client.rsc.tsx +10 -9
- package/src/client.tsx +5 -4
- package/src/components/DefaultDocument.tsx +7 -2
- package/src/context-var.ts +6 -5
- package/src/escape-script.ts +1 -1
- package/src/handles/MetaTags.tsx +13 -11
- package/src/handles/Scripts.tsx +11 -10
- package/src/handles/meta.ts +2 -2
- package/src/handles/script.ts +17 -16
- package/src/href-client.ts +1 -1
- package/src/html.ts +12 -0
- package/src/index.rsc.ts +5 -0
- package/src/index.ts +1 -0
- package/src/loader-store.ts +7 -4
- package/src/prerender/build-shell-capture.ts +8 -11
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +117 -30
- package/src/route-definition/helpers-types.ts +33 -9
- package/src/route-definition/resolve-handler-use.ts +121 -6
- package/src/route-types.ts +0 -3
- package/src/router/debug-manifest.ts +10 -2
- package/src/router/error-handling.ts +51 -15
- package/src/router/handler-context.ts +34 -25
- package/src/router/intercept-resolution.ts +125 -39
- package/src/router/loader-resolution.ts +56 -11
- package/src/router/match-api.ts +12 -17
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +93 -10
- package/src/router/match-middleware/cache-store.ts +17 -90
- package/src/router/middleware-types.ts +3 -5
- package/src/router/middleware.ts +52 -9
- package/src/router/prerender-match.ts +53 -19
- package/src/router/route-snapshot.ts +11 -1
- package/src/router/router-context.ts +2 -0
- package/src/router/router-interfaces.ts +25 -2
- package/src/router/router-options.ts +8 -5
- package/src/router/segment-resolution/fresh.ts +44 -12
- package/src/router/segment-resolution/loader-cache.ts +205 -45
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +6 -6
- package/src/router/segment-resolution/mask-nested.ts +7 -7
- package/src/router/segment-resolution/revalidation.ts +34 -6
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +8 -45
- package/src/rsc/shell-capture-constants.ts +13 -0
- package/src/rsc/shell-capture.ts +111 -90
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +11 -0
- package/src/server/context.ts +88 -11
- package/src/server/cookie-store.ts +5 -4
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +35 -30
- package/src/ssr/index.tsx +40 -7
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/generated-routes.ts +2 -2
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/internal/flight-client-globals.ts +7 -5
- package/src/testing/render-route.tsx +85 -24
- package/src/testing/run-loader.ts +5 -1
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +14 -0
- package/src/types/loader-types.ts +8 -6
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type SerializedManifest } from "../debug.js";
|
|
2
2
|
import type { RouteEntry } from "../types";
|
|
3
3
|
/**
|
|
4
|
-
* Build a serialized manifest from
|
|
5
|
-
* Used by the `debugManifest()` method on the router instance.
|
|
4
|
+
* Build a serialized manifest from the eager route entries for debug
|
|
5
|
+
* inspection. Used by the `debugManifest()` method on the router instance.
|
|
6
|
+
* include() children are not expanded (lazy placeholders are skipped).
|
|
6
7
|
*/
|
|
7
8
|
export declare function buildDebugManifest<TEnv = any>(routesEntries: RouteEntry<TEnv>[]): Promise<SerializedManifest>;
|
|
@@ -42,10 +42,30 @@ export interface InvokeOnErrorContext<TEnv = any> {
|
|
|
42
42
|
* @param logPrefix - Prefix for console.error messages (e.g., "Router" or "RSC")
|
|
43
43
|
*/
|
|
44
44
|
export declare function invokeOnError<TEnv = any>(onError: OnErrorCallback<TEnv> | undefined, error: unknown, phase: ErrorPhase, context: InvokeOnErrorContext<TEnv>, logPrefix?: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* First non-undefined `pick(orphan)` over the routeless entries in
|
|
47
|
+
* `entry.layout` and, recursively, in theirs: depth-first in render order
|
|
48
|
+
* (resolveOrphanLayout in segment-resolution/fresh.ts). Since #922 a routeless
|
|
49
|
+
* entry nested in another renders (a layout() after a bare cache() marker, a
|
|
50
|
+
* layout() in a routeless wrapper); a one-level scan missed the boundaries and
|
|
51
|
+
* intercepts it declares (#926).
|
|
52
|
+
*
|
|
53
|
+
* `skip` is the entry an upward walk came from. Only a bare cache() marker is
|
|
54
|
+
* both in its layout's layout[] and in the chain, and its subtree was already
|
|
55
|
+
* scanned at its chain position.
|
|
56
|
+
*/
|
|
57
|
+
export declare function findInOrphans<T>(entry: EntryData, pick: (orphan: EntryData) => T | undefined, skip?: EntryData | null): T | undefined;
|
|
58
|
+
/** `findInOrphans` pick: the orphan when it declares an errorBoundary(). */
|
|
59
|
+
export declare const withErrorBoundary: (entry: EntryData) => EntryData | undefined;
|
|
45
60
|
/**
|
|
46
61
|
* Find the nearest error boundary by walking up the entry chain
|
|
47
62
|
* Also checks sibling layouts (orphan layouts) for error boundaries
|
|
48
63
|
* Returns the first fallback found, or the default error boundary if configured
|
|
64
|
+
*
|
|
65
|
+
* An orphan's parent is null, so from an orphan the walk continues at its
|
|
66
|
+
* orphanOwner (EntryData). Without that step, errors from an intercept declared
|
|
67
|
+
* in a routeless layout, or from that layout's loaders, stopped at the orphan
|
|
68
|
+
* and skipped every ancestor boundary (#898).
|
|
49
69
|
*/
|
|
50
70
|
export declare function findNearestErrorBoundary(entry: EntryData | null, defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler): ReactNode | ErrorBoundaryHandler | null;
|
|
51
71
|
/**
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
* Creates the handler context object passed to route handlers, middleware, and loaders.
|
|
5
5
|
*/
|
|
6
6
|
import type { InternalHandlerContext } from "../types";
|
|
7
|
+
/**
|
|
8
|
+
* `headers` whose mutating methods run `assertWrite(method)` first. Shared by
|
|
9
|
+
* the handler ctx (createHandlerContext) and the middleware ctx
|
|
10
|
+
* (createMiddlewareContext).
|
|
11
|
+
*/
|
|
12
|
+
export declare function guardHeaderWrites(headers: Headers, assertWrite: (method: string | symbol) => void): Headers;
|
|
7
13
|
/**
|
|
8
14
|
* Strip internal _rsc* query params from a URL.
|
|
9
15
|
* Returns a new URL with only user-facing params.
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
* ISOLATION FROM RESPONSE
|
|
83
83
|
* =======================
|
|
84
84
|
*
|
|
85
|
-
* Background revalidation
|
|
86
|
-
*
|
|
85
|
+
* Background revalidation re-renders through rerenderAndCacheRoute (shared
|
|
86
|
+
* with proactive caching in cache-store.ts):
|
|
87
|
+
* - Derived request context with its own handleStore, transition({ when })
|
|
88
|
+
* predicates and no perf metrics (the shared fields are never touched;
|
|
89
|
+
* the foreground is still producing the page)
|
|
87
90
|
* - Fresh handlerContext + loaderPromises (prevents reusing memoized
|
|
88
91
|
* loader results from the foreground pass)
|
|
89
|
-
* - handleStore is saved/restored in try/finally
|
|
90
|
-
*
|
|
91
|
-
* This matches the proactive caching pattern in cache-store.ts.
|
|
92
92
|
*
|
|
93
93
|
*
|
|
94
94
|
* FRESH RESOLUTION (NO REVALIDATION)
|
|
@@ -101,7 +101,48 @@
|
|
|
101
101
|
*/
|
|
102
102
|
import type { ResolvedSegment } from "../../types.js";
|
|
103
103
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
104
|
+
import { type RouterContext } from "../router-context.js";
|
|
105
|
+
import type { CacheScope } from "../../cache/cache-scope.js";
|
|
104
106
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
107
|
+
import { type RequestContext } from "../../server/request-context.js";
|
|
108
|
+
/**
|
|
109
|
+
* Re-render a cached route in the background and write it with
|
|
110
|
+
* cacheScope.cacheRoute: the stale-hit refresh below and proactive caching
|
|
111
|
+
* (cache-store.ts). Returns the number of segments written.
|
|
112
|
+
*
|
|
113
|
+
* A render whose status is not 200 (an error or notFound boundary resolved)
|
|
114
|
+
* is not written and returns 0, as a non-200 MISS is not cached
|
|
115
|
+
* (cache-store.ts): the entry it would replace keeps serving until a later
|
|
116
|
+
* refresh succeeds or it expires. Nothing is held in process; a store's own
|
|
117
|
+
* revalidation marker (CFCacheStore's REVALIDATING) re-arms after
|
|
118
|
+
* MAX_REVALIDATION_INTERVAL, as after a refresh that throws.
|
|
119
|
+
*
|
|
120
|
+
* Runs on a DERIVED request context that owns the per-render state the
|
|
121
|
+
* foreground reads while it is still producing the page (a stale HIT re-runs
|
|
122
|
+
* its loaders; a proactive render starts once the Response exists, while its
|
|
123
|
+
* body streams):
|
|
124
|
+
* - _handleStore: read late (loader pushes and aux-lane tracking in
|
|
125
|
+
* loader-resolution.ts, nested cache restores and captures in
|
|
126
|
+
* cache-scope.ts), so a swap sent live pushes into this render.
|
|
127
|
+
* setupLoaderAccess binds the store at setup, so it runs inside the
|
|
128
|
+
* derived context too.
|
|
129
|
+
* - _transitionWhen: fresh resolution appends transition({ when })
|
|
130
|
+
* predicates; the foreground's gateTransitions reads the array after the
|
|
131
|
+
* match, and a stale HIT (which replays the stored transition) must not
|
|
132
|
+
* evaluate this render's predicates.
|
|
133
|
+
* - _metricsStore: undefined, and the DSL store below has `metrics` unset
|
|
134
|
+
* (track() reads that one), so nothing lands on the foreground's perf
|
|
135
|
+
* timeline. ctx.Store.run closes over ctx.Store, so the derived store
|
|
136
|
+
* needs its own run.
|
|
137
|
+
* - response writes (headers, cookies, status, onResponse callbacks) go to
|
|
138
|
+
* a throwaway context (whose status gates the write, above) and are
|
|
139
|
+
* dropped: a layout above the cache() boundary is outside the header
|
|
140
|
+
* guard and an error boundary sets a status, so they would otherwise
|
|
141
|
+
* reach the live response.
|
|
142
|
+
* runWithRequestContext also re-establishes the request ALS, which a waitUntil
|
|
143
|
+
* task on workerd loses; the DSL store is a different ALS (build context).
|
|
144
|
+
*/
|
|
145
|
+
export declare function rerenderAndCacheRoute<TEnv>(ctx: MatchContext<TEnv>, requestCtx: RequestContext<TEnv>, cacheScope: CacheScope, routerCtx: RouterContext<TEnv>): Promise<number>;
|
|
105
146
|
/**
|
|
106
147
|
* Creates background revalidation middleware
|
|
107
148
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ContextVar } from "../context-var.js";
|
|
2
2
|
import type { DefaultReverseRouteMap, DefaultRouteName, DefaultVars } from "../types/global-namespace.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { GlobalReverseFunction } from "../reverse.js";
|
|
4
4
|
import type { Theme } from "../theme/types.js";
|
|
5
5
|
import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
|
|
6
6
|
import type { RequestScope } from "../types/request-scope.js";
|
|
@@ -51,7 +51,8 @@ export interface MiddlewareContext<TEnv = any, TParams = Record<string, string |
|
|
|
51
51
|
theme?: Theme;
|
|
52
52
|
setTheme?: (theme: Theme) => void;
|
|
53
53
|
setLocationState(entries: LocationStateEntry | LocationStateEntry[]): void;
|
|
54
|
-
|
|
54
|
+
/** Global route names only; see {@link GlobalReverseFunction}. */
|
|
55
|
+
reverse: GlobalReverseFunction<DefaultReverseRouteMap>;
|
|
55
56
|
}
|
|
56
57
|
export type MiddlewareFn<TEnv = any, TParams = Record<string, string | undefined>> = (ctx: MiddlewareContext<TEnv, TParams>, next: () => Promise<Response>) => Response | void | Promise<Response | void>;
|
|
57
58
|
export interface MiddlewareEntry<TEnv = any> {
|
|
@@ -49,7 +49,9 @@ export interface RouterContext<TEnv = any> {
|
|
|
49
49
|
getMetricsStore: () => MetricsStore | undefined;
|
|
50
50
|
createCacheScope: (cacheConfig: any, parent: CacheScope | null) => CacheScope | null;
|
|
51
51
|
findInterceptForRoute: (routeKey: string, parentEntry: EntryData | null, selectorContext: InterceptSelectorContext, isAction: boolean) => InterceptResult | null;
|
|
52
|
-
resolveAllSegmentsWithRevalidation: (entries: EntryData[], routeKey: string, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: any | undefined, interceptResult: InterceptResult | null, localRouteName: string, pathname: string, stale?: boolean
|
|
52
|
+
resolveAllSegmentsWithRevalidation: (entries: EntryData[], routeKey: string, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: any | undefined, interceptResult: InterceptResult | null, localRouteName: string, pathname: string, stale?: boolean,
|
|
53
|
+
/** The matched route's full chain when `entries` is part of it (ResolveSegmentOptions.chain). */
|
|
54
|
+
chain?: readonly EntryData[]) => Promise<{
|
|
53
55
|
segments: ResolvedSegment[];
|
|
54
56
|
matchedIds: string[];
|
|
55
57
|
}>;
|
|
@@ -137,6 +137,22 @@ export interface Rango<TEnv = any, TRoutes extends Record<string, unknown> = Rec
|
|
|
137
137
|
* ```
|
|
138
138
|
*/
|
|
139
139
|
readonly routeMap: TRoutes;
|
|
140
|
+
/**
|
|
141
|
+
* Serialize the route manifest for inspection: every route and layout the
|
|
142
|
+
* router's `.routes()` / `urls` mounts register, with shortCodes, parent
|
|
143
|
+
* links, and loader/middleware/error-boundary/parallel/intercept flags.
|
|
144
|
+
*
|
|
145
|
+
* Server-only development aid. It re-evaluates each mount's `urls()` tree.
|
|
146
|
+
* Groups mounted with `include()` are lazy and are not expanded: their
|
|
147
|
+
* routes are absent from the result.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const manifest = await router.debugManifest();
|
|
152
|
+
* console.log(manifest.totalRoutes, Object.keys(manifest.routes));
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
debugManifest(): Promise<SerializedManifest>;
|
|
140
156
|
/**
|
|
141
157
|
* Handle an RSC request.
|
|
142
158
|
*
|
|
@@ -147,7 +163,13 @@ export interface Rango<TEnv = any, TRoutes extends Record<string, unknown> = Rec
|
|
|
147
163
|
* ```tsx
|
|
148
164
|
* import { router } from "./router";
|
|
149
165
|
*
|
|
150
|
-
*
|
|
166
|
+
* // Workers call fetch(request, env, ctx); `{ fetch: router.fetch }` would
|
|
167
|
+
* // drop env and ctx.
|
|
168
|
+
* export default {
|
|
169
|
+
* fetch(request, env, ctx) {
|
|
170
|
+
* return router.fetch(request, { env, ctx });
|
|
171
|
+
* },
|
|
172
|
+
* } satisfies ExportedHandler;
|
|
151
173
|
* ```
|
|
152
174
|
*
|
|
153
175
|
* @example Direct export
|
|
@@ -238,7 +260,7 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
|
|
|
238
260
|
readonly notFound?: RangoOptions<TEnv>["notFound"];
|
|
239
261
|
/**
|
|
240
262
|
* Resolved theme configuration (null if theme not enabled)
|
|
241
|
-
* Used by NavigationProvider to include ThemeProvider and by
|
|
263
|
+
* Used by NavigationProvider to include ThemeProvider and by `Html.Meta` to render theme script
|
|
242
264
|
*/
|
|
243
265
|
readonly themeConfig: import("../theme/types.js").ResolvedThemeConfig | null;
|
|
244
266
|
/**
|
|
@@ -146,8 +146,10 @@ export interface RangoOptions<TEnv = any> {
|
|
|
146
146
|
*
|
|
147
147
|
* Must be a client component ("use client") that accepts { children }.
|
|
148
148
|
*
|
|
149
|
-
* If not provided, a default document
|
|
150
|
-
* `<
|
|
149
|
+
* If not provided, a default document is used: `Html.Meta` and `Html.Scripts`
|
|
150
|
+
* in `<head>`, `Html.Scripts position="body"` before `{children}` and
|
|
151
|
+
* `Html.ScrollRestoration` after it. Pass your own to set `getKey` or to
|
|
152
|
+
* leave back/forward scrolling to the browser.
|
|
151
153
|
*
|
|
152
154
|
* @example
|
|
153
155
|
* ```typescript
|
|
@@ -181,7 +183,8 @@ export interface RangoOptions<TEnv = any> {
|
|
|
181
183
|
defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler;
|
|
182
184
|
/**
|
|
183
185
|
* Default not-found boundary fallback used when no notFoundBoundary is defined in the route tree
|
|
184
|
-
* If not provided,
|
|
186
|
+
* If not provided, notFound() renders the `notFound` option, else a plain
|
|
187
|
+
* `<h1>Not Found</h1>` (status 404)
|
|
185
188
|
*/
|
|
186
189
|
defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler;
|
|
187
190
|
/**
|
|
@@ -190,7 +193,7 @@ export interface RangoOptions<TEnv = any> {
|
|
|
190
193
|
* This is rendered within your document/app shell with a 404 status code.
|
|
191
194
|
* Use this for a custom 404 page that maintains your app's look and feel.
|
|
192
195
|
*
|
|
193
|
-
* If not provided, a
|
|
196
|
+
* If not provided, a plain `<h1>Not Found</h1>` is rendered.
|
|
194
197
|
*
|
|
195
198
|
* Can be a static ReactNode or a function receiving the pathname.
|
|
196
199
|
*
|
|
@@ -337,7 +340,7 @@ export interface RangoOptions<TEnv = any> {
|
|
|
337
340
|
* When provided, enables:
|
|
338
341
|
* - ctx.theme and ctx.setTheme() in route handlers
|
|
339
342
|
* - useTheme() hook for client components
|
|
340
|
-
* - FOUC prevention via inline script in
|
|
343
|
+
* - FOUC prevention via inline script in `<Html.Meta />`
|
|
341
344
|
* - Automatic ThemeProvider wrapping in NavigationProvider
|
|
342
345
|
*
|
|
343
346
|
* @example
|
|
@@ -27,6 +27,16 @@ export interface ResolveSegmentOptions {
|
|
|
27
27
|
* so error boundaries keep catching at request time.
|
|
28
28
|
*/
|
|
29
29
|
throwOnError?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The matched route's full entry chain. resolveAllSegments defaults it to
|
|
32
|
+
* its `entries`; withCacheLookup passes it when it resolves only the entries
|
|
33
|
+
* above a cache() boundary. An orphan list can hold an entry of the chain: a
|
|
34
|
+
* bare cache() marker sits in its layout's layout[] (it wraps that layout's
|
|
35
|
+
* routes) and is the parent of the routes after it. For those routes it
|
|
36
|
+
* resolves once, as a chain entry, below the cache() header latch (issue
|
|
37
|
+
* #918: resolved twice on a MISS, once and discarded on a HIT).
|
|
38
|
+
*/
|
|
39
|
+
chain?: readonly EntryData[];
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* Resolve segments from EntryData.
|
|
@@ -16,8 +16,15 @@
|
|
|
16
16
|
* On hit: returns cached data directly, skips loader execution.
|
|
17
17
|
* On stale hit (SWR): returns stale data, schedules background revalidation.
|
|
18
18
|
* On miss: executes loader, schedules non-blocking cache write.
|
|
19
|
+
*
|
|
20
|
+
* Handle pushes (`ctx.use(Handle)(...)` in the loader body) are a side effect
|
|
21
|
+
* the HIT must reproduce: the MISS records the pushes of the body and of the
|
|
22
|
+
* loaders it awaits via ctx.use into the entry's `handles` blob (the
|
|
23
|
+
* "use cache" capture/encode), and every HIT — stale included — replays
|
|
24
|
+
* them, each loader's pushes at most once per request (a dependency another
|
|
25
|
+
* reader already ran keeps its live pushes). See replayLoaderHandles.
|
|
19
26
|
*/
|
|
20
|
-
import type
|
|
27
|
+
import { type LoaderEntry } from "../../server/context.js";
|
|
21
28
|
import type { HandlerContext } from "../../types.js";
|
|
22
29
|
/**
|
|
23
30
|
* Resolve loader data with optional caching.
|
|
@@ -29,5 +36,34 @@ import type { HandlerContext } from "../../types.js";
|
|
|
29
36
|
* (observePhase; see instrument.ts). A cache HIT returns without calling ctx.use,
|
|
30
37
|
* so it emits no loader phase (the loader did not execute; the hit is only a
|
|
31
38
|
* LoaderCache debug log).
|
|
39
|
+
*
|
|
40
|
+
* PPR loader lane rule — the canonical source statement; other sites point
|
|
41
|
+
* here (consumer docs: skills/ppr/SKILL.md "The loader lane rule";
|
|
42
|
+
* docs/design/loader-container-bake.md). This is the single funnel every
|
|
43
|
+
* loader segment path routes through (fresh resolveLoaders, cache-hit
|
|
44
|
+
* resolveLoadersOnly, revalidation resolveLoadersOnlyWithRevalidation, and
|
|
45
|
+
* intercept loaders in intercept-resolution.ts, which pass no bake key and
|
|
46
|
+
* never run under a shell capture), so the lane is decided here, per LOADER,
|
|
47
|
+
* never by the entry's loading():
|
|
48
|
+
*
|
|
49
|
+
* - BAKE lane: `loader(Def, { ssr: false })` (awaitBeforeFlush) with a
|
|
50
|
+
* `bakeSegmentKey` from the caller. The loader EXECUTES at capture (the
|
|
51
|
+
* flag's "data in the HTML before first flush" maps to the frozen prelude)
|
|
52
|
+
* and its settled non-promise data bakes into the shell. Promises nested in
|
|
53
|
+
* plain objects/arrays are masked (mask-nested.ts) and stay live holes at
|
|
54
|
+
* the consumer's own Suspense — per-request material must be promise-shaped
|
|
55
|
+
* (the #692 cross-session scar). The masked container registers on
|
|
56
|
+
* `_shellCaptureLoaderRecords`: it holds the capture gate (bounded by
|
|
57
|
+
* `ppr.captureTimeout`) and pins into the snapshot's loader family, and on a
|
|
58
|
+
* HIT the recorded container is overlaid onto the fresh run (below) so the
|
|
59
|
+
* payload matches the frozen prelude byte-for-byte. cookies()/headers() in
|
|
60
|
+
* its body (nested promise bodies included) trip the capture guard.
|
|
61
|
+
* - LIVE lane: every other loader, whatever its entry's loading(). Never
|
|
62
|
+
* executes at capture: the slot gets a never-resolving promise
|
|
63
|
+
* (loader-mask.ts) and postpones at the reader's boundary — loading() or an
|
|
64
|
+
* inline Suspense — then streams fresh per request. A masked read with NO
|
|
65
|
+
* boundary above it root-postpones and the <body> sanity gate refuses the
|
|
66
|
+
* shell (eternal-MISS warning). A route whose loaders are ALL `ssr: false`
|
|
67
|
+
* needs no loading(): nothing masks.
|
|
32
68
|
*/
|
|
33
69
|
export declare function resolveLoaderData<TEnv>(loaderEntry: LoaderEntry, ctx: HandlerContext<any, TEnv>, pathname: string, bakeSegmentKey?: string | null): Promise<any>;
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
* PPR shell-capture loader masking.
|
|
3
3
|
*
|
|
4
4
|
* During a shell CAPTURE re-render (Axis 2, see docs/design/ppr-shell-resume.md)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* a
|
|
8
|
-
*
|
|
9
|
-
* shell (prelude) captures only the fallback; the resumed serve pass runs the
|
|
10
|
-
* loaders fresh through the unchanged execution path and streams their output
|
|
11
|
-
* into the holes.
|
|
5
|
+
* live-lane loaders (lane rule: see resolveLoaderData, loader-cache.ts) must
|
|
6
|
+
* NOT execute; their value slot gets a never-resolving promise so the
|
|
7
|
+
* consuming Suspense subtree postpones as a hole, and the serve pass runs them
|
|
8
|
+
* fresh into it.
|
|
12
9
|
*
|
|
13
10
|
* Capture mode is signalled by `requestCtx._shellCaptureRun`, set to true ONLY on
|
|
14
11
|
* the derived request context of the background capture task (shell-capture.ts) —
|
|
@@ -28,17 +25,10 @@ import { type RequestContext } from "../../server/request-context.js";
|
|
|
28
25
|
export declare function isShellCaptureActive(reqCtx?: RequestContext<any> | undefined): boolean;
|
|
29
26
|
export { createMaskedLoaderPromise } from "./mask-nested.js";
|
|
30
27
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* the frozen prelude — while every other loader is LIVE (masked at capture,
|
|
37
|
-
* fresh on every serve), postponing at loading() or an inline Suspense.
|
|
38
|
-
* This helper still gates which entries pass a bake segment key for the
|
|
39
|
-
* legacy loading()-less shape and the HIT-tail seed overlay.
|
|
40
|
-
*
|
|
41
|
-
* Mirrors segment-system's isRenderableLoading so the mask decision and the
|
|
42
|
-
* tree's boundary placement can never disagree.
|
|
28
|
+
* True when the entry's loading() is renderable (mirrors segment-system's
|
|
29
|
+
* isRenderableLoading). Not the lane decision (lane rule: see
|
|
30
|
+
* resolveLoaderData, loader-cache.ts): callers only use it to decide whether
|
|
31
|
+
* an unflagged loader's segment key rides as the bake/seed key, which is inert
|
|
32
|
+
* at capture.
|
|
43
33
|
*/
|
|
44
34
|
export declare function entryLoadingMasksLoaders(loading: unknown): boolean;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Loader-family capture snapshot: elide + overlay for bake-lane loader
|
|
3
3
|
* containers (docs/design/loader-container-bake.md).
|
|
4
4
|
*
|
|
5
|
-
* A loader
|
|
6
|
-
* capture; its settled container bakes into the prelude
|
|
7
|
-
*
|
|
5
|
+
* A bake-lane loader (lane rule: see resolveLoaderData, loader-cache.ts)
|
|
6
|
+
* executes during shell capture; its settled container bakes into the prelude
|
|
7
|
+
* while nested promises postpone as holes. To keep a HIT's fresh
|
|
8
8
|
* payload byte-identical to that frozen prelude, the capture pins the container
|
|
9
9
|
* in the shell snapshot:
|
|
10
10
|
*
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Capture-side nested-thenable masking — the mechanism behind "nested-promise
|
|
3
3
|
* shape is the liveness declaration" for BOTH bake-lane loader containers
|
|
4
|
-
* (loader-cache.ts) and pushed handle containers (
|
|
5
|
-
*
|
|
4
|
+
* (loader-cache.ts) and pushed handle containers (the capture handle store's
|
|
5
|
+
* push wrap in rsc/shell-capture.ts).
|
|
6
6
|
*
|
|
7
|
-
* Deliberately a LEAF module:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Deliberately a LEAF module: loader-mask (the other natural home) imports
|
|
8
|
+
* request-context, so any funnel importing the mask from there inherits that
|
|
9
|
+
* graph. This module imports only is-thenable.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
12
|
* A promise that never settles — the masked stand-in for a per-request value
|
|
@@ -21,8 +21,8 @@ export declare function createMaskedLoaderPromise<T = unknown>(): Promise<T>;
|
|
|
21
21
|
* Deep-copy a container with every NESTED thenable replaced by a masked
|
|
22
22
|
* (never-resolving) promise. Applied during shell capture to (a) bake-lane
|
|
23
23
|
* loader containers (loader-cache.ts) and (b) pushed handle containers
|
|
24
|
-
* (
|
|
25
|
-
* per-request data by promise SHAPE.
|
|
24
|
+
* (shell-capture.ts capture store push wrap) — the two rango-owned funnels
|
|
25
|
+
* where consumers declare per-request data by promise SHAPE.
|
|
26
26
|
*
|
|
27
27
|
* Why: a nested promise that happened to SETTLE before the capture's quiet
|
|
28
28
|
* window closed used to bake its value into the SHARED shell (and, for
|
|
@@ -66,7 +66,9 @@ export declare function resolveEntryHandlerWithRevalidation<TEnv>(entry: Exclude
|
|
|
66
66
|
*/
|
|
67
67
|
export declare function resolveSegmentWithRevalidation<TEnv>(entry: Exclude<EntryData, {
|
|
68
68
|
type: "parallel";
|
|
69
|
-
}>, routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean
|
|
69
|
+
}>, routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean,
|
|
70
|
+
/** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
|
|
71
|
+
chain?: readonly EntryData[]): Promise<SegmentRevalidationResult>;
|
|
70
72
|
/**
|
|
71
73
|
* Resolve orphan layout with revalidation.
|
|
72
74
|
*/
|
|
@@ -79,7 +81,9 @@ parentRouteEntry?: EntryData): Promise<SegmentRevalidationResult>;
|
|
|
79
81
|
export declare function resolveAllSegmentsWithRevalidation<TEnv>(entries: EntryData[], routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: ActionContext | undefined, interceptResult: {
|
|
80
82
|
intercept: any;
|
|
81
83
|
entry: EntryData;
|
|
82
|
-
} | null, localRouteName: string, pathname: string, deps: SegmentResolutionDeps<TEnv>, stale?: boolean
|
|
84
|
+
} | null, localRouteName: string, pathname: string, deps: SegmentResolutionDeps<TEnv>, stale?: boolean,
|
|
85
|
+
/** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
|
|
86
|
+
chain?: readonly EntryData[]): Promise<{
|
|
83
87
|
segments: ResolvedSegment[];
|
|
84
88
|
matchedIds: string[];
|
|
85
89
|
}>;
|
|
@@ -27,7 +27,7 @@ export interface SegmentWrappers<TEnv = any> {
|
|
|
27
27
|
} | undefined, interceptResult: {
|
|
28
28
|
intercept: InterceptEntry;
|
|
29
29
|
entry: EntryData;
|
|
30
|
-
} | null, localRouteName: string, pathname: string) => Promise<{
|
|
30
|
+
} | null, localRouteName: string, pathname: string, stale?: boolean, chain?: readonly EntryData[]) => Promise<{
|
|
31
31
|
segments: ResolvedSegment[];
|
|
32
32
|
matchedIds: string[];
|
|
33
33
|
}>;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* dispatch, route middleware execution, and response caching with SWR.
|
|
7
7
|
*/
|
|
8
8
|
import type { MiddlewareFn } from "../router/middleware.js";
|
|
9
|
-
import type
|
|
9
|
+
import { type EntryData } from "../server/context.js";
|
|
10
10
|
import type { HandlerContext } from "./handler-context.js";
|
|
11
11
|
export interface ResponseRouteMatch {
|
|
12
12
|
responseType: string;
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* RSC Rendering Handler (Navigation)
|
|
3
3
|
*
|
|
4
4
|
* Handles RSC rendering for both partial (client-side navigation) and full
|
|
5
|
-
* (initial page load) requests.
|
|
6
|
-
* static generation.
|
|
5
|
+
* (initial page load) requests.
|
|
7
6
|
*/
|
|
8
7
|
import { getRequestContext } from "../server/request-context.js";
|
|
9
8
|
import type { HandlerContext } from "./handler-context.js";
|
|
@@ -42,3 +42,11 @@ export declare const SHELL_CAPTURE_MAX_WAIT_MS = 15000;
|
|
|
42
42
|
* check on the stampede guard, keyed off the same constant.
|
|
43
43
|
*/
|
|
44
44
|
export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
|
|
45
|
+
/**
|
|
46
|
+
* Shared PPR loader-lane hint, appended to every capture warning or error
|
|
47
|
+
* whose fix depends on the lane (shell-capture.ts warnings, the cookie-store.ts
|
|
48
|
+
* capture guard). Lives in this import-free leaf so cookie-store.ts can import
|
|
49
|
+
* it without pulling the capture orchestration module. Source anchor for the
|
|
50
|
+
* rule: resolveLoaderData (router/segment-resolution/loader-cache.ts).
|
|
51
|
+
*/
|
|
52
|
+
export declare const PPR_LANE_HINT: string;
|
|
@@ -50,10 +50,11 @@ declare function delay(ms: number): Promise<void>;
|
|
|
50
50
|
* mode's ceiling (60s in production, {@link REFUSED_CAPTURE_DEV_MAX_MS} in dev).
|
|
51
51
|
*
|
|
52
52
|
* Why exponential and not a flat 60s: a flat long window conflates two very
|
|
53
|
-
* different failures. A STRUCTURALLY ineligible route (
|
|
54
|
-
* reader) fails forever and wants the long 60s cap. But a
|
|
55
|
-
* can also fail the in-place retry under a truly cold
|
|
56
|
-
* or a cold worker under parallel load) — and it
|
|
53
|
+
* different failures. A STRUCTURALLY ineligible route (a boundary-less live
|
|
54
|
+
* loader read, a cookie reader) fails forever and wants the long 60s cap. But a
|
|
55
|
+
* cold-but-ELIGIBLE route can also fail the in-place retry under a truly cold
|
|
56
|
+
* graph (dev module transform, or a cold worker under parallel load) — and it
|
|
57
|
+
* must recover FAST, on the next
|
|
57
58
|
* request or two, not be frozen for 60s (that would re-break the very cold-start DX
|
|
58
59
|
* the retry fixes; it bit the cloudflare dev e2e). Escalating from 1s means the
|
|
59
60
|
* eligible route re-probes almost immediately (warm now → HIT and clear), while the
|
|
@@ -33,11 +33,11 @@ export interface SsrHtmlStageOptions<TEnv> {
|
|
|
33
33
|
/** Metrics store for ssr:module-load / ssr:stream-mode timing (per call site). */
|
|
34
34
|
metricsStore: MetricsStore | undefined;
|
|
35
35
|
/**
|
|
36
|
-
* renderHTML options minus streamMode (the stage
|
|
37
|
-
* the per-site nonce and, for the PE action re-render, formState.
|
|
38
|
-
* verbatim so each call site's exact key set is preserved.
|
|
36
|
+
* renderHTML options minus streamMode and onError (the stage owns both).
|
|
37
|
+
* Carries the per-site nonce and, for the PE action re-render, formState.
|
|
38
|
+
* Spread verbatim so each call site's exact key set is preserved.
|
|
39
39
|
*/
|
|
40
|
-
render: Omit<SSRRenderOptions, "streamMode">;
|
|
40
|
+
render: Omit<SSRRenderOptions, "streamMode" | "onError">;
|
|
41
41
|
/** ResponseInit merged into the prepared render (e.g. content-type). */
|
|
42
42
|
init?: ResponseInit;
|
|
43
43
|
}
|
|
@@ -59,8 +59,8 @@ export declare function getSSRSetup<TEnv>(ctx: HandlerContext<TEnv>, request: Re
|
|
|
59
59
|
* Classify whether a request may require SSR (HTML rendering).
|
|
60
60
|
*
|
|
61
61
|
* Returns false for requests that are definitively RSC-only: transport
|
|
62
|
-
* params (partial/action/loader/__rsc)
|
|
63
|
-
*
|
|
62
|
+
* params (partial/action/loader/__rsc) or an explicit Accept:
|
|
63
|
+
* text/x-component. Must never return false for a request whose
|
|
64
64
|
* render-time decision (isRscRequest) will be HTML — the two share
|
|
65
65
|
* acceptsFlightExplicitly so the Accept rule cannot drift. document-cache.ts
|
|
66
66
|
* keys its HTML/RSC response slots off this function, so any divergence from
|
|
@@ -181,6 +181,12 @@ export interface SSRRenderOptions {
|
|
|
181
181
|
* the browser across hydration. Absent on host-agnostic build captures.
|
|
182
182
|
*/
|
|
183
183
|
origin?: string;
|
|
184
|
+
/**
|
|
185
|
+
* Called for each error Fizz reports through its onError: a component that
|
|
186
|
+
* threw inside a Suspense boundary, which leaves the boundary errored in an
|
|
187
|
+
* otherwise completed document. React's default console.error is kept.
|
|
188
|
+
*/
|
|
189
|
+
onError?: (error: unknown) => void;
|
|
184
190
|
}
|
|
185
191
|
/**
|
|
186
192
|
* SSR module interface for HTML rendering
|
|
@@ -200,6 +206,8 @@ export interface SSRModule {
|
|
|
200
206
|
maxWaitMs?: number;
|
|
201
207
|
search?: string;
|
|
202
208
|
origin?: string;
|
|
209
|
+
/** Each component error the prerender reports (never the capture's own abort). */
|
|
210
|
+
onError?: (error: unknown) => void;
|
|
203
211
|
}) => Promise<{
|
|
204
212
|
prelude: Uint8Array;
|
|
205
213
|
postponed: string | null;
|
|
@@ -217,6 +225,8 @@ export interface SSRModule {
|
|
|
217
225
|
nonce?: string;
|
|
218
226
|
search?: string;
|
|
219
227
|
origin?: string;
|
|
228
|
+
/** Each component error the resumed holes report. */
|
|
229
|
+
onError?: (error: unknown) => void;
|
|
220
230
|
}) => Promise<ReadableStream<Uint8Array>>;
|
|
221
231
|
}
|
|
222
232
|
/**
|
|
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import type { PartialCacheOptions, ErrorBoundaryHandler, Handler, LoaderDefinition, MiddlewareFn, NotFoundBoundaryHandler, ShouldRevalidateFn, TransitionConfig } from "../types";
|
|
4
4
|
import type { DefaultRouteName } from "../types/global-namespace.js";
|
|
5
|
+
import type { ContextVar } from "../context-var.js";
|
|
5
6
|
/**
|
|
6
7
|
* Performance metric entry for a single measured operation
|
|
7
8
|
*
|
|
@@ -44,6 +45,17 @@ export type EntryPropCommon = {
|
|
|
44
45
|
id: string;
|
|
45
46
|
shortCode: string;
|
|
46
47
|
parent: EntryData | null;
|
|
48
|
+
/**
|
|
49
|
+
* Orphan siblings only (attachOrphanSibling in
|
|
50
|
+
* route-definition/dsl-helpers.ts): the entry whose `layout[]` holds this
|
|
51
|
+
* one. `parent` stays null on an orphan (matchError's matched-id stack in
|
|
52
|
+
* router/match-api.ts starts at the boundary-holding entry, possibly an
|
|
53
|
+
* orphan, and must stop there), so the boundary walkers in
|
|
54
|
+
* router/error-handling.ts follow this instead. A lookup that starts at an
|
|
55
|
+
* orphan (its loaders, an intercept it declares) then reaches the owner's
|
|
56
|
+
* boundaries and the owner's ancestors.
|
|
57
|
+
*/
|
|
58
|
+
orphanOwner?: EntryData;
|
|
47
59
|
/** Cache configuration for this entry (set by cache() DSL) */
|
|
48
60
|
cache?: EntryCacheConfig;
|
|
49
61
|
/** URL prefix from include() scope, used for MountContext on client */
|
|
@@ -156,9 +168,6 @@ export type InterceptEntry = {
|
|
|
156
168
|
routeName: string;
|
|
157
169
|
handler: ReactNode | Handler<any, any, any>;
|
|
158
170
|
middleware: MiddlewareFn<any, any>[];
|
|
159
|
-
revalidate: ShouldRevalidateFn<any, any>[];
|
|
160
|
-
errorBoundary: (ReactNode | ErrorBoundaryHandler)[];
|
|
161
|
-
notFoundBoundary: (ReactNode | NotFoundBoundaryHandler)[];
|
|
162
171
|
loader: LoaderEntry[];
|
|
163
172
|
loading?: ReactNode | false;
|
|
164
173
|
transition?: TransitionConfig;
|
|
@@ -403,6 +412,20 @@ export declare function track(label: string, depth?: number): () => void;
|
|
|
403
412
|
* (never cached), so non-cacheable reads are safe.
|
|
404
413
|
*/
|
|
405
414
|
export declare function isInsideCacheScope(): boolean;
|
|
415
|
+
/**
|
|
416
|
+
* Read guard for a non-cacheable variable (`createVar({ cache: false })` or a
|
|
417
|
+
* `ctx.set(..., { cache: false })` write). Callers check isNonCacheable() first
|
|
418
|
+
* so ordinary reads never reach the scope lookups.
|
|
419
|
+
*
|
|
420
|
+
* Throws inside a "use cache" body: the key does not include the value, so the
|
|
421
|
+
* first caller's value would be stored and served to later callers (#925). A
|
|
422
|
+
* loader body entered INSIDE the cached function is exempt, the same baked-copy
|
|
423
|
+
* trade isInsideCacheScope() makes for cache(). A cached function called FROM a
|
|
424
|
+
* loader is not: the loader re-runs, the cached body does not. The body scope
|
|
425
|
+
* records the exec scope it was entered in, so the exemption holds only while
|
|
426
|
+
* that is still the innermost one.
|
|
427
|
+
*/
|
|
428
|
+
export declare function assertNonCacheableReadAllowed(keyOrVar: string | ContextVar<unknown>): void;
|
|
406
429
|
/**
|
|
407
430
|
* Check if the current execution is inside a DSL loader scope
|
|
408
431
|
* (wrapped by runInsideLoaderScope). Used by rendered() barrier
|
|
@@ -498,6 +521,13 @@ export declare function runInsideLoaderBodyScope<T>(fn: () => T, loaderId?: stri
|
|
|
498
521
|
* (issue #672, secondary).
|
|
499
522
|
*/
|
|
500
523
|
export declare function getCurrentLoaderBodyId(): string | undefined;
|
|
524
|
+
/**
|
|
525
|
+
* True while `loaderId`'s body, or a loader it awaits via ctx.use at any
|
|
526
|
+
* depth, is executing. The loader-level cache records these pushes
|
|
527
|
+
* (loader-cache.ts): a HIT skips the cached body, so a dep that no other
|
|
528
|
+
* reader runs in that request only reaches the page through the replay.
|
|
529
|
+
*/
|
|
530
|
+
export declare function isInsideLoaderBody(loaderId: string): boolean;
|
|
501
531
|
/**
|
|
502
532
|
* True while a HANDLER-invoked loader body (`await ctx.use(Loader)` from a
|
|
503
533
|
* handler, not the DSL segment funnel) is executing. The consumption-lane
|