@rangojs/router 0.16.0 → 0.18.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 +255 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -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-key-utils.d.ts +17 -2
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +132 -19
- package/dist/types/cache/cache-tag.d.ts +92 -7
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +54 -13
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +110 -21
- package/dist/types/cache/tag-invalidation.d.ts +30 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +220 -44
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- 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/prerender/build-shell-capture.d.ts +11 -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/instrument.d.ts +8 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +9 -3
- 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 +66 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
- package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
- 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/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.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-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
- package/dist/types/rsc/shell-capture.d.ts +151 -19
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/context.d.ts +139 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +182 -53
- package/dist/types/ssr/index.d.ts +24 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- 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/run-loader.d.ts +18 -3
- package/dist/types/testing/serve-shell-request.d.ts +132 -0
- package/dist/types/testing/shell-status.d.ts +23 -10
- 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 +28 -1
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/pattern-types.d.ts +22 -18
- 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/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1420 -1348
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +75 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +306 -124
- package/skills/caching/SKILL.md +530 -98
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +65 -38
- package/skills/cloudflare/SKILL.md +87 -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 +75 -57
- 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 +52 -31
- package/skills/deployment-caching/SKILL.md +11 -3
- package/skills/document-cache/SKILL.md +98 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +55 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +34 -17
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +39 -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 +386 -128
- package/skills/middleware/SKILL.md +129 -26
- package/skills/migrate-nextjs/SKILL.md +156 -70
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +51 -39
- package/skills/migrate-react-router/component-migration.md +28 -7
- package/skills/migrate-react-router/data-and-actions.md +21 -6
- package/skills/migrate-react-router/route-mapping.md +19 -10
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +92 -14
- package/skills/parallel/SKILL.md +88 -47
- package/skills/ppr/SKILL.md +866 -379
- package/skills/prerender/SKILL.md +210 -108
- package/skills/rango/SKILL.md +115 -65
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +170 -60
- package/skills/router-setup/SKILL.md +420 -240
- package/skills/scripts/SKILL.md +39 -21
- package/skills/server-actions/SKILL.md +231 -59
- package/skills/shell-manifest/SKILL.md +28 -14
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +73 -33
- package/skills/testing/cache-prerender.md +60 -33
- 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 +26 -6
- 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/serve-shell-request.md +188 -0
- 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 +155 -30
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +137 -50
- 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 +224 -83
- package/skills/vercel/SKILL.md +35 -13
- package/skills/view-transitions/SKILL.md +42 -21
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- 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 +6 -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 +23 -8
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +264 -68
- package/src/cache/cache-scope.ts +419 -43
- package/src/cache/cache-tag.ts +375 -11
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +990 -348
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +133 -28
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +108 -22
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +225 -44
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- 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 +73 -22
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +121 -33
- 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 +71 -28
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +141 -43
- package/src/router/loader-resolution.ts +115 -39
- package/src/router/match-api.ts +40 -26
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +110 -10
- package/src/router/match-middleware/cache-store.ts +48 -101
- package/src/router/middleware-types.ts +9 -6
- package/src/router/middleware.ts +75 -13
- package/src/router/prerender-match.ts +59 -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 +62 -21
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +407 -76
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +208 -56
- package/src/router/segment-resolution/mask-nested.ts +138 -44
- package/src/router/segment-resolution/revalidation.ts +61 -16
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/full-payload.ts +25 -1
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/progressive-enhancement.ts +3 -2
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-cache-serve.ts +9 -6
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +608 -225
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +73 -6
- package/src/rsc/shell-capture.ts +1068 -296
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +18 -0
- package/src/server/context.ts +300 -32
- package/src/server/cookie-store.ts +87 -61
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +297 -67
- package/src/ssr/index.tsx +136 -44
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +14 -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 +68 -6
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +28 -1
- package/src/types/loader-types.ts +8 -6
- package/src/urls/pattern-types.ts +22 -18
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
- package/src/vite/router-discovery.ts +14 -4
|
@@ -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.
|
|
@@ -163,6 +163,14 @@ export declare function observePhase<T>(spec: PhaseSpec, fn: (span: TraceSpan) =
|
|
|
163
163
|
* nothing to record here and short-circuits.
|
|
164
164
|
*/
|
|
165
165
|
export declare function observeHandler<C, R>(id: string, handler: (ctx: C) => R, ctx: C): R;
|
|
166
|
+
/**
|
|
167
|
+
* observeHandler, inside segment `segmentId`'s tag scope, so the tags the
|
|
168
|
+
* handler records reach the route's cache() record (#957, cache-tag.ts
|
|
169
|
+
* runInSegmentTagScope). `spanId` is observeHandler's `id`. A request that
|
|
170
|
+
* cannot write a record takes observeHandler's path as is, with the same one
|
|
171
|
+
* request-context read: no scope, no closure.
|
|
172
|
+
*/
|
|
173
|
+
export declare function observeSegmentHandler<C, R>(segmentId: string, spanId: string, handler: (ctx: C) => R, ctx: C): R;
|
|
166
174
|
/**
|
|
167
175
|
* Emit one discrete telemetry event (the event-shaped counterpart to
|
|
168
176
|
* observePhase). Resolves the sink from the active router context and stamps the
|
|
@@ -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";
|
|
@@ -48,10 +48,16 @@ export interface MiddlewareContext<TEnv = any, TParams = Record<string, string |
|
|
|
48
48
|
header(name: string, value: string): void;
|
|
49
49
|
routeName?: DefaultRouteName;
|
|
50
50
|
debugPerformance(): void;
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The visitor's theme (cookie or default); undefined without theme config.
|
|
53
|
+
* Guarded like `cookies()`: a read inside a `"use cache"` function throws
|
|
54
|
+
* (#971).
|
|
55
|
+
*/
|
|
56
|
+
readonly theme?: Theme;
|
|
52
57
|
setTheme?: (theme: Theme) => void;
|
|
53
58
|
setLocationState(entries: LocationStateEntry | LocationStateEntry[]): void;
|
|
54
|
-
|
|
59
|
+
/** Global route names only; see {@link GlobalReverseFunction}. */
|
|
60
|
+
reverse: GlobalReverseFunction<DefaultReverseRouteMap>;
|
|
55
61
|
}
|
|
56
62
|
export type MiddlewareFn<TEnv = any, TParams = Record<string, string | undefined>> = (ctx: MiddlewareContext<TEnv, TParams>, next: () => Promise<Response>) => Response | void | Promise<Response | void>;
|
|
57
63
|
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,9 +16,40 @@
|
|
|
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
|
+
* Identity (#972): without a key() or a store keyGenerator the entry is
|
|
21
|
+
* shared across users, so a fill whose execution recorded a request-identity
|
|
22
|
+
* read fails and is not stored, whoever started that execution
|
|
23
|
+
* (server/context.ts recordLoaderIdentityRead).
|
|
24
|
+
*
|
|
25
|
+
* Handle pushes (`ctx.use(Handle)(...)` in the loader body) are a side effect
|
|
26
|
+
* the HIT must reproduce: the MISS records the pushes of the body and of the
|
|
27
|
+
* loaders it awaits via ctx.use into the entry's `handles` blob (the
|
|
28
|
+
* "use cache" capture/encode), and every HIT — stale included — replays
|
|
29
|
+
* them, each loader's pushes at most once per request (a dependency another
|
|
30
|
+
* reader already ran keeps its live pushes). See replayLoaderHandles.
|
|
31
|
+
*
|
|
32
|
+
* Tags too (#964): the entry stores its cache() tags plus every tag its
|
|
33
|
+
* execution recorded, those of the loader values it read included
|
|
34
|
+
* (cache-tag.ts "Recorded-tag sets"), so updateTag() of any of them drops it.
|
|
35
|
+
* Every HIT records the stored tags through the loader's tag owner
|
|
36
|
+
* (recordLoaderTags), so a route cache() record, PPR shell or document built
|
|
37
|
+
* over the HIT carries them, and a loader that reads this one takes them on.
|
|
38
|
+
* Once the binding started, a loader body's ctx.use of it gets the same
|
|
39
|
+
* dataPromise as a handler read (createLoaderExecutor's useLoader); a stale
|
|
40
|
+
* refresh does not (setupLoaderAccess _runLoaderIsolated).
|
|
19
41
|
*/
|
|
20
|
-
import type
|
|
42
|
+
import { type EntryData, type LoaderEntry } from "../../server/context.js";
|
|
21
43
|
import type { HandlerContext } from "../../types.js";
|
|
44
|
+
/**
|
|
45
|
+
* Whether a request over the matched chain `entries` resolves a loader bound
|
|
46
|
+
* with its own cache(): on a chain entry, or on its parallel slots, orphan
|
|
47
|
+
* layouts or intercepts. The match arms the per-execution loader tag sets on
|
|
48
|
+
* it (cache-tag.ts armLoaderTagSets), before any loader starts, so a
|
|
49
|
+
* dependency the handler or another binding starts first still records.
|
|
50
|
+
* Memoized per entry.
|
|
51
|
+
*/
|
|
52
|
+
export declare function bindsLoaderCache(entries: readonly EntryData[]): boolean;
|
|
22
53
|
/**
|
|
23
54
|
* Resolve loader data with optional caching.
|
|
24
55
|
*
|
|
@@ -29,5 +60,39 @@ import type { HandlerContext } from "../../types.js";
|
|
|
29
60
|
* (observePhase; see instrument.ts). A cache HIT returns without calling ctx.use,
|
|
30
61
|
* so it emits no loader phase (the loader did not execute; the hit is only a
|
|
31
62
|
* LoaderCache debug log).
|
|
63
|
+
*
|
|
64
|
+
* PPR loader lane rule — the canonical source statement; other sites point
|
|
65
|
+
* here (consumer docs: skills/ppr/SKILL.md "The loader lane rule";
|
|
66
|
+
* docs/design/loader-container-bake.md). This is the single funnel every
|
|
67
|
+
* loader segment path routes through (fresh resolveLoaders, cache-hit
|
|
68
|
+
* resolveLoadersOnly, revalidation resolveLoadersOnlyWithRevalidation, and
|
|
69
|
+
* intercept loaders in intercept-resolution.ts, which pass no bake key and
|
|
70
|
+
* never run under a shell capture), so the lane is decided here, per LOADER,
|
|
71
|
+
* never by the entry's loading():
|
|
72
|
+
*
|
|
73
|
+
* - BAKE lane: `loader(Def, { ssr: false })` (LoaderEntry `bake`: the
|
|
74
|
+
* caller passes a `bakeSegmentKey` for it on document and navigation
|
|
75
|
+
* evaluations alike; a capture, a document evaluation, also has
|
|
76
|
+
* awaitBeforeFlush). The loader EXECUTES at capture (the
|
|
77
|
+
* flag's "data in the HTML before first flush" maps to the frozen prelude)
|
|
78
|
+
* and its settled non-promise data bakes into the shell. Promises nested in
|
|
79
|
+
* plain objects, arrays and JSX props are masked (mask-nested.ts) and stay
|
|
80
|
+
* live holes at the consumer's own Suspense — per-request material must be
|
|
81
|
+
* promise-shaped (the #692 cross-session scar). The masked container
|
|
82
|
+
* registers on `_shellCaptureLoaderRecords`: it holds the capture gate
|
|
83
|
+
* (bounded by `ppr.captureTimeout`) and pins into the snapshot's loader
|
|
84
|
+
* family, and on a HIT the recorded container is overlaid onto the fresh
|
|
85
|
+
* run (below) so the payload matches the frozen prelude outside the holes.
|
|
86
|
+
* A server-component element holding a promise is a hole as a whole, so its
|
|
87
|
+
* other props come from the fresh run (loader-snapshot.ts
|
|
88
|
+
* elideLoaderContainer). cookies()/headers() in its body (nested promise
|
|
89
|
+
* bodies included) trip the capture guard.
|
|
90
|
+
* - LIVE lane: every other loader, whatever its entry's loading(). Never
|
|
91
|
+
* executes at capture: the slot gets a never-resolving promise
|
|
92
|
+
* (loader-mask.ts) and postpones at the reader's boundary — loading() or an
|
|
93
|
+
* inline Suspense — then streams fresh per request. A masked read with NO
|
|
94
|
+
* boundary above it root-postpones and the <body> sanity gate refuses the
|
|
95
|
+
* shell (eternal-MISS warning). A route whose loaders are ALL `ssr: false`
|
|
96
|
+
* needs no loading(): nothing masks.
|
|
32
97
|
*/
|
|
33
98
|
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,11 +2,13 @@
|
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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 payload in
|
|
8
|
+
* agreement with that frozen prelude, the capture pins the container in the
|
|
9
|
+
* shell snapshot. Everything outside a hole is pinned; the one exception is a
|
|
10
|
+
* server-component element holding a promise, which is a hole as a whole (see
|
|
11
|
+
* elideLoaderContainer):
|
|
10
12
|
*
|
|
11
13
|
* - elide: deep-walk the settled container; a PENDING nested promise is a
|
|
12
14
|
* hole, replaced by {@link LOADER_HOLE_KEY} — and since
|
|
@@ -27,7 +29,8 @@
|
|
|
27
29
|
* storefront PDP regression) — and fresh-only paths pass through
|
|
28
30
|
* (they cannot contradict prelude bytes that never rendered them).
|
|
29
31
|
*/
|
|
30
|
-
|
|
32
|
+
import { maskNestedContainerThenables } from "./mask-nested.js";
|
|
33
|
+
export { maskNestedContainerThenables };
|
|
31
34
|
/**
|
|
32
35
|
* Marker object standing in for a pending nested promise in a recorded loader
|
|
33
36
|
* container. Shape-checked (not identity-checked) because the record round-trips
|
|
@@ -70,21 +73,29 @@ export type ElideResult = {
|
|
|
70
73
|
* promises pin their value behind a settled marker (they baked, but consumers
|
|
71
74
|
* hold a promise-shaped key); pending ones become hole markers; a REJECTED
|
|
72
75
|
* nested promise poisons the record (error UI must never bake into a shared
|
|
73
|
-
* shell) — the caller refuses the capture.
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
76
|
+
* shell) — the caller refuses the capture. Plain data objects, arrays and the
|
|
77
|
+
* props of host, Suspense/Fragment and client-reference elements are
|
|
78
|
+
* traversed copy-on-write (an element through cloneElementWithProps); a shared
|
|
79
|
+
* subtree or a cycle resolves to the same elided result. An element Flight
|
|
80
|
+
* renders by calling user code (see rendersOnServer) is a leaf, or ONE hole
|
|
81
|
+
* marker when a thenable sits anywhere in its props: the pin encode calls that
|
|
82
|
+
* component, so a marker inside its props would reach it. Anything else
|
|
83
|
+
* (Date, Map, class instance, lazy node) is a pinned leaf.
|
|
77
84
|
*
|
|
78
85
|
* The ROOT container promise-chain unwraps with NO marker: loader-cache
|
|
79
86
|
* overlays against the AWAITED fresh container, so the recorded root must be
|
|
80
87
|
* the unwrapped structure. Everything below it goes through elideNested.
|
|
81
88
|
*/
|
|
82
|
-
export declare function elideLoaderContainer(value: unknown, seen?:
|
|
89
|
+
export declare function elideLoaderContainer(value: unknown, seen?: Map<object, ElideResult>): Promise<ElideResult>;
|
|
83
90
|
/**
|
|
84
91
|
* Overlay a recorded (elided) container onto the fresh run's container for a
|
|
85
92
|
* shell HIT. Recorded wins per path; hole markers take the fresh value (the
|
|
86
93
|
* live nested promise); fresh-only object keys pass through. Where the shapes
|
|
87
94
|
* disagree structurally, recorded wins wholesale — it is what the prelude
|
|
88
|
-
* froze, and parity beats freshness inside the shell.
|
|
95
|
+
* froze, and parity beats freshness inside the shell. Copy-on-write: a
|
|
96
|
+
* recorded subtree without markers comes back by identity. A recorded element
|
|
97
|
+
* is rebuilt through cloneElementWithProps only at its marker paths, so its
|
|
98
|
+
* other props stay pinned; props the fresh element adds do not pass through
|
|
99
|
+
* (the prelude rendered the element without them).
|
|
89
100
|
*/
|
|
90
101
|
export declare function overlayLoaderContainer(fresh: unknown, recorded: unknown): unknown;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Capture-side nested
|
|
3
|
-
* shape is the liveness declaration" for
|
|
4
|
-
* (loader-cache.ts) and
|
|
5
|
-
*
|
|
2
|
+
* Capture-side nested thenables. Masking is the mechanism behind "nested-
|
|
3
|
+
* promise shape is the liveness declaration" for the loader lane: bake-lane
|
|
4
|
+
* loader containers (loader-cache.ts) and DSL loader handle pushes (the
|
|
5
|
+
* capture handle store's push wrap in rsc/shell-capture.ts). Handler handle
|
|
6
|
+
* pushes are handler output and bake: the capture waits for their nested
|
|
7
|
+
* promises instead (settleNestedThenables).
|
|
6
8
|
*
|
|
7
|
-
* Deliberately a LEAF module:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Deliberately a LEAF module: loader-mask (the other natural home) imports
|
|
10
|
+
* request-context, so any funnel importing the mask from there inherits that
|
|
11
|
+
* graph. This module imports only is-thenable and react.
|
|
10
12
|
*/
|
|
13
|
+
import { type ReactElement } from "react";
|
|
11
14
|
/**
|
|
12
15
|
* A promise that never settles — the masked stand-in for a per-request value
|
|
13
16
|
* during shell capture. The consuming Suspense subtree suspends forever, so
|
|
@@ -18,11 +21,55 @@
|
|
|
18
21
|
*/
|
|
19
22
|
export declare function createMaskedLoaderPromise<T = unknown>(): Promise<T>;
|
|
20
23
|
/**
|
|
21
|
-
*
|
|
24
|
+
* A data object the container walks descend into: prototype Object.prototype
|
|
25
|
+
* or null, and no symbol `$$typeof`. React elements, lazy nodes and references
|
|
26
|
+
* are plain objects too, told apart by that symbol (Flight switches on it).
|
|
27
|
+
* They are React's, not data: an element's dev-only fields (`_debugStack`,
|
|
28
|
+
* `_debugTask`, `_debugInfo`, `ref`) are non-enumerable, so a key-by-key copy
|
|
29
|
+
* drops them and dev Flight refuses it ("Attempted to render <x> without
|
|
30
|
+
* development properties", issue #942).
|
|
31
|
+
*/
|
|
32
|
+
export declare function isPlainDataObject(value: unknown): value is Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* cloneElement with only the given props replaced, keeping React's dev key
|
|
35
|
+
* validation. React 19 dev cloneElement resets `_store.validated`, so a
|
|
36
|
+
* keyless child of a static children list (validated at creation) would warn
|
|
37
|
+
* "Each child in a list should have a unique key" once cloned. Pass only the
|
|
38
|
+
* props that change: cloneElement re-parents the element (owner) when its
|
|
39
|
+
* config carries `ref`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function cloneElementWithProps(element: ReactElement, props: Record<string, unknown>): ReactElement;
|
|
42
|
+
/**
|
|
43
|
+
* Resolves once `value` and every thenable reachable from it through plain
|
|
44
|
+
* data objects, arrays and React element props has settled, following what
|
|
45
|
+
* each thenable resolves to. A rejection counts as settled: the consumer that
|
|
46
|
+
* encodes the value reports it. Other objects are leaves (the same walk as
|
|
47
|
+
* maskNestedContainerThenables), so a promise inside a Map is not waited for.
|
|
48
|
+
* An element is walked through its props only (`<X data={promise} />` in a
|
|
49
|
+
* handle value is handler output too), never its owner or type, and is never
|
|
50
|
+
* rebuilt: nothing is copied, only awaited.
|
|
51
|
+
*
|
|
52
|
+
* The capture waits on this for HANDLER handle pushes (shell-capture.ts):
|
|
53
|
+
* handler output is baked, so its promises must settle before the doc record
|
|
54
|
+
* encodes the handles every HIT replays.
|
|
55
|
+
*/
|
|
56
|
+
export declare function settleNestedThenables(value: unknown): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional single-walk report for maskNestedContainerThenables: `thenable`
|
|
59
|
+
* flips true when the walk masked at least one thenable. The capture push
|
|
60
|
+
* funnel reads it for a loader push: a container with a masked nested
|
|
61
|
+
* promise keeps its loader tag, so the handle encode never waits on a mask.
|
|
62
|
+
* Same single-pass shape as elideLoaderContainer's `hasHole`.
|
|
63
|
+
*/
|
|
64
|
+
export interface MaskReport {
|
|
65
|
+
thenable: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Copy a container with every NESTED thenable replaced by a masked
|
|
22
69
|
* (never-resolving) promise. Applied during shell capture to (a) bake-lane
|
|
23
|
-
* loader containers (loader-cache.ts) and (b)
|
|
24
|
-
* (
|
|
25
|
-
* per-request data by promise SHAPE.
|
|
70
|
+
* loader containers (loader-cache.ts) and (b) DSL loader handle pushes
|
|
71
|
+
* (shell-capture.ts capture store push wrap) — the rango-owned funnels where
|
|
72
|
+
* a loader declares per-request data by promise SHAPE.
|
|
26
73
|
*
|
|
27
74
|
* Why: a nested promise that happened to SETTLE before the capture's quiet
|
|
28
75
|
* window closed used to bake its value into the SHARED shell (and, for
|
|
@@ -34,20 +81,14 @@ export declare function createMaskedLoaderPromise<T = unknown>(): Promise<T>;
|
|
|
34
81
|
* Masking makes the consuming subtree postpone as a hole no matter when the
|
|
35
82
|
* promise settles: liveness by declaration, not by racing the window.
|
|
36
83
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* declares per-request data, and a shell entry whose HANDLER layer made such
|
|
47
|
-
* a declaration cannot be served handler-free (the hole would never fill).
|
|
48
|
-
* Same single-pass shape as elideLoaderContainer's `hasHole`.
|
|
84
|
+
* Plain data objects, arrays and React element props are traversed: JSX
|
|
85
|
+
* carrying a promise (`<Reviews data={fetchReviews()} />`) declares
|
|
86
|
+
* per-request data the same way a plain container does. Other values, lazy
|
|
87
|
+
* nodes included, are leaves. Copy-on-write: a subtree without a thenable
|
|
88
|
+
* comes back by identity, so an element is rebuilt only when its props hold
|
|
89
|
+
* one, and then through cloneElementWithProps, which keeps its type, key,
|
|
90
|
+
* owner, dev fields and key validation. The INPUT IS NEVER MUTATED — handler-side loader consumption (the
|
|
91
|
+
* consumption-lane rule, semantic-matrix PPR3) shares the raw container and
|
|
92
|
+
* must keep real values. Cycles are preserved as cycles in the copy.
|
|
49
93
|
*/
|
|
50
|
-
export interface MaskReport {
|
|
51
|
-
thenable: boolean;
|
|
52
|
-
}
|
|
53
94
|
export declare function maskNestedContainerThenables(value: unknown, seen?: Map<object, unknown>, report?: MaskReport): unknown;
|
|
@@ -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
|
}>;
|