@rangojs/router 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rango.js +13 -1
- package/dist/types/browser/event-controller.d.ts +30 -13
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +14 -0
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +1 -1
- package/dist/types/cache/cf/cf-cache-store.d.ts +7 -1
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +23 -0
- package/dist/types/cache/index.d.ts +1 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +10 -1
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +63 -14
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +7 -1
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +7 -0
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +14 -0
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +30 -0
- package/dist/types/router/router-options.d.ts +24 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +2 -1
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +6 -4
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +8 -0
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +9 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +2 -0
- package/dist/types/server/request-context.d.ts +63 -2
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/flight.entry.d.ts +2 -0
- package/dist/types/testing/index.d.ts +4 -0
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/serve-shell-request.d.ts +34 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +7 -0
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/state.d.ts +11 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/vite/index.js +179 -496
- package/package.json +12 -2
- package/skills/cache-guide/SKILL.md +18 -17
- package/skills/caching/SKILL.md +40 -4
- package/skills/catalog.json +1 -1
- package/skills/cloudflare/SKILL.md +131 -0
- package/skills/comparison/references/framework-comparison.md +1 -1
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +22 -0
- package/skills/hooks/handle-and-actions.md +3 -4
- package/skills/hooks/navigation.md +10 -0
- package/skills/hooks/state.md +5 -4
- package/skills/host-router/SKILL.md +18 -0
- package/skills/loader/SKILL.md +6 -4
- package/skills/middleware/SKILL.md +1 -1
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +31 -8
- package/skills/prerender/SKILL.md +645 -8
- package/skills/rango/SKILL.md +1 -0
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/testing/SKILL.md +2 -1
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/serve-shell-request.md +104 -8
- package/skills/use-cache/SKILL.md +9 -5
- package/skills/vercel/SKILL.md +2 -0
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/browser/event-controller.ts +69 -25
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +75 -35
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +9 -2
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +48 -12
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/react/Link.tsx +37 -42
- package/src/browser/react/NavigationProvider.tsx +63 -3
- package/src/browser/react/context.ts +17 -0
- package/src/browser/react/location-state.ts +5 -19
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +4 -20
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +79 -39
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +26 -6
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +38 -36
- package/src/cache/cf/cf-cache-store.ts +16 -11
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +50 -0
- package/src/cache/index.ts +1 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +17 -0
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +69 -14
- package/src/cache/vercel/vercel-cache-store.ts +20 -6
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +7 -2
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +230 -38
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +33 -0
- package/src/router/router-options.ts +30 -0
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +15 -17
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router.ts +107 -1
- package/src/rsc/handler.ts +51 -4
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +53 -11
- package/src/rsc/shell-build-manifest.ts +10 -8
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +108 -19
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +8 -0
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +15 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +13 -0
- package/src/server/request-context.ts +87 -1
- package/src/ssr/ssr-root.tsx +20 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +3 -0
- package/src/testing/index.ts +19 -0
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/render-route.tsx +25 -12
- package/src/testing/serve-shell-request.ts +190 -34
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +7 -0
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/shell-prerender-phase.ts +5 -5
- package/src/vite/discovery/state.ts +17 -1
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugins/virtual-entries.ts +8 -1
- package/src/vite/router-discovery.ts +14 -0
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/dist/types/browser/react/subscribe-to-nothing.d.ts +0 -7
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/browser/react/subscribe-to-nothing.ts +0 -7
- package/src/segment-content-promise.ts +0 -67
package/src/segment-system.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type ComponentType,
|
|
6
6
|
isValidElement,
|
|
7
7
|
} from "react";
|
|
8
|
-
import { OutletProvider } from "./outlet-provider.js";
|
|
8
|
+
import { AuditedOutletProvider, OutletProvider } from "./outlet-provider.js";
|
|
9
9
|
import { withOptimisticCommitNone } from "./browser/optimistic-commit.js";
|
|
10
10
|
import { MountContextProvider } from "./browser/react/mount-context.js";
|
|
11
11
|
import type { ResolvedSegment, RootLayoutProps } from "./types.js";
|
|
@@ -13,17 +13,25 @@ import { decodeLoaderResults } from "./decode-loader-results.js";
|
|
|
13
13
|
import { LoaderRedirect } from "./loader-redirect.js";
|
|
14
14
|
import { invariant } from "./errors.js";
|
|
15
15
|
import {
|
|
16
|
+
AuditedLoaderBoundary,
|
|
17
|
+
AuditedRouteContent,
|
|
16
18
|
RouteContentWrapper,
|
|
17
19
|
LoaderBoundary,
|
|
18
20
|
StreamedLoaderErrorBoundary,
|
|
19
21
|
} from "./route-content-wrapper.js";
|
|
20
22
|
import { RootErrorBoundary } from "./root-error-boundary.js";
|
|
21
23
|
import { INTERNAL_RANGO_DEBUG } from "./internal-debug.js";
|
|
22
|
-
import {
|
|
24
|
+
import { INTERNAL_RANGO_SUSPENSE_AUDIT } from "./internal-suspense-audit.js";
|
|
25
|
+
import { getBoundaryContent } from "./segment-boundary-content.js";
|
|
23
26
|
import {
|
|
24
27
|
buildLoaderPromise,
|
|
25
28
|
getMemoizedLoaderPromise,
|
|
26
29
|
} from "./segment-loader-promise.js";
|
|
30
|
+
import {
|
|
31
|
+
auditSegmentElement,
|
|
32
|
+
finishTreeAudit,
|
|
33
|
+
startTreeAudit,
|
|
34
|
+
} from "./suspense-audit.js";
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
37
|
* Debug log for the segment tree build, gated on the baked flag. Runs on BOTH
|
|
@@ -212,13 +220,25 @@ function wrapDefaultOutletContent(
|
|
|
212
220
|
} as any);
|
|
213
221
|
}
|
|
214
222
|
|
|
215
|
-
if (
|
|
223
|
+
if (
|
|
224
|
+
content.type ===
|
|
225
|
+
(process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
226
|
+
? AuditedOutletProvider
|
|
227
|
+
: OutletProvider) &&
|
|
228
|
+
props.segment?.type === "layout"
|
|
229
|
+
) {
|
|
216
230
|
return React.cloneElement(content, {
|
|
217
231
|
content: wrapDefaultOutletContent(props.content, transition),
|
|
218
232
|
} as any);
|
|
219
233
|
}
|
|
220
234
|
|
|
221
|
-
if (
|
|
235
|
+
if (
|
|
236
|
+
content.type ===
|
|
237
|
+
(process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
238
|
+
? AuditedLoaderBoundary
|
|
239
|
+
: LoaderBoundary) &&
|
|
240
|
+
props.segment?.type === "layout"
|
|
241
|
+
) {
|
|
222
242
|
return React.cloneElement(content, {
|
|
223
243
|
outletContent: wrapDefaultOutletContent(props.outletContent, transition),
|
|
224
244
|
} as any);
|
|
@@ -376,6 +396,10 @@ export async function renderSegments(
|
|
|
376
396
|
}
|
|
377
397
|
// Separate segments by type, passing intercept segments for explicit injection
|
|
378
398
|
const tree = segmentTreeWalk(normalizedSegments, normalizedInterceptSegments);
|
|
399
|
+
// Dev only: the wrapper chain per segment, compared with the previous
|
|
400
|
+
// tree's (suspense-audit.ts, I5).
|
|
401
|
+
const treeAudit =
|
|
402
|
+
process.env.NODE_ENV !== "production" ? startTreeAudit() : undefined;
|
|
379
403
|
|
|
380
404
|
// A route is "in a transition scope" when its own segment OR any layout in
|
|
381
405
|
// its matched chain declares transition(). Both transition() forms land here:
|
|
@@ -473,34 +497,33 @@ export async function renderSegments(
|
|
|
473
497
|
|
|
474
498
|
let nodeContent: ReactNode = null;
|
|
475
499
|
if (!clientGroup && isRenderableLoading(loading)) {
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
// instead of a pending promise, which Suspender renders synchronously. This
|
|
484
|
-
// mirrors the forceAwait loaderData unwrap above; a CLIENT component that
|
|
485
|
-
// suspends on mount inside the content still reveals a fallback (it is not
|
|
486
|
-
// pre-resolved).
|
|
487
|
-
const contentPromise = getMemoizedContentPromise(resolvedComponent);
|
|
488
|
-
let loadingContent: Promise<ReactNode> | ReactNode = contentPromise;
|
|
500
|
+
// The wrapper tree is the same on every path; only `content` differs. A
|
|
501
|
+
// settled component is handed over as the node (getBoundaryContent), a
|
|
502
|
+
// pending one as its promise, so only pending work shows the loading()
|
|
503
|
+
// fallback. forceAwait also awaits a pending component here. A CLIENT
|
|
504
|
+
// component that suspends on mount inside the content still reveals a
|
|
505
|
+
// fallback.
|
|
506
|
+
let loadingContent: ReactNode = getBoundaryContent(resolvedComponent);
|
|
489
507
|
if (forceAwait) {
|
|
490
508
|
const contentAwaitStart = segDebug ? performance.now() : 0;
|
|
491
|
-
loadingContent = await
|
|
509
|
+
loadingContent = await loadingContent;
|
|
492
510
|
if (segDebug) {
|
|
493
511
|
segDebugLog(`segment ${id}: content awaited (forceAwait)`, {
|
|
494
512
|
ms: Math.round(performance.now() - contentAwaitStart),
|
|
495
513
|
});
|
|
496
514
|
}
|
|
497
515
|
}
|
|
498
|
-
nodeContent = createElement(
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
516
|
+
nodeContent = createElement(
|
|
517
|
+
process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
518
|
+
? AuditedRouteContent
|
|
519
|
+
: RouteContentWrapper,
|
|
520
|
+
{
|
|
521
|
+
key: `suspense-loading-${id}`,
|
|
522
|
+
content: loadingContent,
|
|
523
|
+
fallback: loading,
|
|
524
|
+
segmentId: id,
|
|
525
|
+
},
|
|
526
|
+
);
|
|
504
527
|
} else {
|
|
505
528
|
// [VT-DIAG] Gated behind INTERNAL_RANGO_DEBUG. A segment in the no-loading()
|
|
506
529
|
// branch whose component decodes as a Promise/lazy gets registered into
|
|
@@ -593,7 +616,10 @@ export async function renderSegments(
|
|
|
593
616
|
let boundaryAwaitedLoaderIds: string[] | undefined;
|
|
594
617
|
if (forceAwait || isAction) {
|
|
595
618
|
const awaitStart = segDebug ? performance.now() : 0;
|
|
596
|
-
boundaryLoaderData =
|
|
619
|
+
boundaryLoaderData =
|
|
620
|
+
loaderDataPromise instanceof Promise
|
|
621
|
+
? await loaderDataPromise
|
|
622
|
+
: loaderDataPromise;
|
|
597
623
|
if (segDebug) {
|
|
598
624
|
segDebugLog(`segment ${id}: loaders awaited (forceAwait/action)`, {
|
|
599
625
|
loaderIds,
|
|
@@ -621,28 +647,38 @@ export async function renderSegments(
|
|
|
621
647
|
);
|
|
622
648
|
}
|
|
623
649
|
}
|
|
624
|
-
content = createElement(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
650
|
+
content = createElement(
|
|
651
|
+
process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
652
|
+
? AuditedLoaderBoundary
|
|
653
|
+
: LoaderBoundary,
|
|
654
|
+
{
|
|
655
|
+
key: `loader-boundary-${key}`,
|
|
656
|
+
loaderDataPromise: boundaryLoaderData,
|
|
657
|
+
loaderIds,
|
|
658
|
+
loaderStreams: boundaryLoaderStreams,
|
|
659
|
+
awaitedLoaderIds: boundaryAwaitedLoaderIds,
|
|
660
|
+
fallback: loading,
|
|
661
|
+
outletKey: key,
|
|
662
|
+
outletContent,
|
|
663
|
+
segment: node.segment,
|
|
664
|
+
parallel: node.parallel,
|
|
665
|
+
children: nodeContent,
|
|
666
|
+
},
|
|
667
|
+
);
|
|
637
668
|
} else if (loaderEntries.length === 0) {
|
|
638
|
-
content = createElement(
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
669
|
+
content = createElement(
|
|
670
|
+
process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
671
|
+
? AuditedOutletProvider
|
|
672
|
+
: OutletProvider,
|
|
673
|
+
{
|
|
674
|
+
key,
|
|
675
|
+
content: outletContent,
|
|
676
|
+
segment: node.segment,
|
|
677
|
+
parallel: node.parallel,
|
|
678
|
+
pending: outletPending,
|
|
679
|
+
children: nodeContent,
|
|
680
|
+
},
|
|
681
|
+
);
|
|
646
682
|
} else {
|
|
647
683
|
const layoutLoaders = loaderEntries.filter((l) => !l.parallelLoading);
|
|
648
684
|
const parallelOwnedLoaders = loaderEntries.filter(
|
|
@@ -776,17 +812,23 @@ export async function renderSegments(
|
|
|
776
812
|
}
|
|
777
813
|
}
|
|
778
814
|
|
|
779
|
-
content = createElement(
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
815
|
+
content = createElement(
|
|
816
|
+
process.env.NODE_ENV !== "production" && INTERNAL_RANGO_SUSPENSE_AUDIT
|
|
817
|
+
? AuditedOutletProvider
|
|
818
|
+
: OutletProvider,
|
|
819
|
+
{
|
|
820
|
+
key,
|
|
821
|
+
content: outletContent,
|
|
822
|
+
segment: node.segment,
|
|
823
|
+
parallel: node.parallel,
|
|
824
|
+
loaderData:
|
|
825
|
+
Object.keys(loaderData).length > 0 ? loaderData : undefined,
|
|
826
|
+
loaderStreams,
|
|
827
|
+
awaitedLoaderIds,
|
|
828
|
+
pending: outletPending,
|
|
829
|
+
children: errorFallback ?? nodeContent,
|
|
830
|
+
},
|
|
831
|
+
);
|
|
790
832
|
}
|
|
791
833
|
|
|
792
834
|
// Wrap with MountContextProvider for include() scoped components.
|
|
@@ -800,6 +842,22 @@ export async function renderSegments(
|
|
|
800
842
|
});
|
|
801
843
|
}
|
|
802
844
|
|
|
845
|
+
if (process.env.NODE_ENV !== "production") {
|
|
846
|
+
auditSegmentElement(
|
|
847
|
+
treeAudit,
|
|
848
|
+
id,
|
|
849
|
+
node.segment.type,
|
|
850
|
+
key,
|
|
851
|
+
content,
|
|
852
|
+
node.segment.type === "layout" &&
|
|
853
|
+
!!ReactViewTransition &&
|
|
854
|
+
!!transition &&
|
|
855
|
+
transition.viewTransition !== false,
|
|
856
|
+
node.parallel.map((p) => p.id),
|
|
857
|
+
[node.segment, ...node.parallel, ...node.loaders],
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
|
|
803
861
|
if (segDebug) {
|
|
804
862
|
segDebugLog(`segment ${id} built`, {
|
|
805
863
|
type: node.segment.type,
|
|
@@ -849,6 +907,8 @@ export async function renderSegments(
|
|
|
849
907
|
});
|
|
850
908
|
}
|
|
851
909
|
|
|
910
|
+
if (process.env.NODE_ENV !== "production") finishTreeAudit(treeAudit, result);
|
|
911
|
+
|
|
852
912
|
return result;
|
|
853
913
|
}
|
|
854
914
|
|
|
@@ -39,6 +39,21 @@ export function resolveRouterVersions(
|
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The version an on-demand prerender overlay key carries: the router's data
|
|
44
|
+
* version, because the overlay stores segment data, as the segment cache does
|
|
45
|
+
* (a client-only deploy keeps both). The write side (`router.prerender`,
|
|
46
|
+
* router.ts) and the read side (rsc/handler.ts) both call this with
|
|
47
|
+
* `createRouter({ version })`, the only override the trigger can see, so they
|
|
48
|
+
* cannot disagree; a `createRSCHandler({ version })` does not move it.
|
|
49
|
+
*/
|
|
50
|
+
export function resolvePrerenderVersion(
|
|
51
|
+
routerId: string | undefined,
|
|
52
|
+
routerVersion: string | undefined,
|
|
53
|
+
): string {
|
|
54
|
+
return resolveRouterVersions(routerId, routerVersion).data;
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
/** The table gives some router a pair of its own. */
|
|
43
58
|
function hasRouterVersions(): boolean {
|
|
44
59
|
if (!table) return false;
|
package/src/server/context.ts
CHANGED
|
@@ -15,6 +15,10 @@ import { invariant, DslContextError } from "../errors";
|
|
|
15
15
|
import type { DefaultRouteName } from "../types/global-namespace.js";
|
|
16
16
|
import type { ContextVar } from "../context-var.js";
|
|
17
17
|
import { PPR_LANE_HINT } from "../rsc/shell-capture-constants.js";
|
|
18
|
+
import {
|
|
19
|
+
noteWarmIdentityRead,
|
|
20
|
+
type WarmContext,
|
|
21
|
+
} from "../prerender/warm-request.js";
|
|
18
22
|
import {
|
|
19
23
|
endIdentityExempt,
|
|
20
24
|
isInsideCacheExecScope,
|
|
@@ -261,8 +265,13 @@ export type EntryData =
|
|
|
261
265
|
/** Original PrerenderHandlerDefinition (for build-time getParams access) */
|
|
262
266
|
prerenderDef?: {
|
|
263
267
|
getParams?: (ctx: any) => Promise<any[]> | any[];
|
|
264
|
-
options?: {
|
|
268
|
+
options?: {
|
|
269
|
+
concurrency?: number;
|
|
270
|
+
onDemand?: import("../prerender/on-demand.js").OnDemandOption;
|
|
271
|
+
};
|
|
265
272
|
};
|
|
273
|
+
/** Set when the route opted into on-demand prerender (Prerender(..., { onDemand })) */
|
|
274
|
+
isOnDemand?: true;
|
|
266
275
|
/** Set when route is wrapped with Passthrough() — has a separate live handler */
|
|
267
276
|
isPassthrough?: true;
|
|
268
277
|
/** Live handler for runtime fallback (only set on Passthrough routes) */
|
|
@@ -428,6 +437,7 @@ export const getContext = (): {
|
|
|
428
437
|
getStore: () => HelperContext;
|
|
429
438
|
getParent: () => EntryData | null;
|
|
430
439
|
getOrCreateStore: (forRoute?: string) => HelperContext;
|
|
440
|
+
runIsolated: <T>(forRoute: string, callback: () => T) => T;
|
|
431
441
|
getNextIndex: (
|
|
432
442
|
type: (string & {}) | "layout" | "parallel" | "middleware" | "revalidate",
|
|
433
443
|
) => string;
|
|
@@ -447,26 +457,29 @@ export const getContext = (): {
|
|
|
447
457
|
) => T;
|
|
448
458
|
} => {
|
|
449
459
|
const context = RangoContext;
|
|
460
|
+
const createStore = (forRoute?: string): HelperContext => ({
|
|
461
|
+
manifest: new Map<string, EntryData>(),
|
|
462
|
+
namespace: "",
|
|
463
|
+
parent: null,
|
|
464
|
+
forRoute,
|
|
465
|
+
counters: {},
|
|
466
|
+
patterns: new Map<string, string>(),
|
|
467
|
+
patternsByPrefix: new Map<string, Map<string, string>>(),
|
|
468
|
+
trailingSlash: new Map<string, "never" | "always" | "ignore">(),
|
|
469
|
+
searchSchemas: new Map<string, Record<string, string>>(),
|
|
470
|
+
});
|
|
450
471
|
|
|
451
472
|
return {
|
|
452
473
|
context,
|
|
453
474
|
getOrCreateStore: (forRoute?: string): HelperContext => {
|
|
454
475
|
let store = RangoContext.getStore();
|
|
455
476
|
if (!store) {
|
|
456
|
-
store =
|
|
457
|
-
manifest: new Map<string, EntryData>(),
|
|
458
|
-
namespace: "",
|
|
459
|
-
parent: null,
|
|
460
|
-
forRoute,
|
|
461
|
-
counters: {},
|
|
462
|
-
patterns: new Map<string, string>(),
|
|
463
|
-
patternsByPrefix: new Map<string, Map<string, string>>(),
|
|
464
|
-
trailingSlash: new Map<string, "never" | "always" | "ignore">(),
|
|
465
|
-
searchSchemas: new Map<string, Record<string, string>>(),
|
|
466
|
-
} satisfies HelperContext;
|
|
477
|
+
store = createStore(forRoute);
|
|
467
478
|
}
|
|
468
479
|
return store;
|
|
469
480
|
},
|
|
481
|
+
runIsolated: <T>(forRoute: string, callback: () => T): T =>
|
|
482
|
+
context.run(createStore(forRoute), callback),
|
|
470
483
|
getStore: (): HelperContext => {
|
|
471
484
|
const store = context.getStore();
|
|
472
485
|
if (!store) {
|
|
@@ -959,19 +972,20 @@ export interface IdentityReadWording {
|
|
|
959
972
|
* nothing and are not captured reads: they take refuseInCacheScope alone.
|
|
960
973
|
*/
|
|
961
974
|
export function guardIdentityRead(
|
|
962
|
-
ctx:
|
|
975
|
+
ctx: WarmContext | null | undefined,
|
|
963
976
|
surface: string,
|
|
964
977
|
wording: IdentityReadWording,
|
|
965
978
|
): void {
|
|
966
979
|
if (isInsideIdentityExempt()) return;
|
|
967
980
|
const { verb, fix } = wording;
|
|
968
981
|
if (tripShellCaptureGuard(ctx, surface, fix.warning)) {
|
|
982
|
+
noteWarmIdentityRead(ctx, surface);
|
|
969
983
|
throw new Error(
|
|
970
984
|
`${surface} cannot be ${verb} while capturing a shared shell ` +
|
|
971
985
|
`(ppr shell capture). ${fix.capture}`,
|
|
972
986
|
);
|
|
973
987
|
}
|
|
974
|
-
refuseInCacheScope(surface, wording);
|
|
988
|
+
refuseInCacheScope(surface, wording, ctx);
|
|
975
989
|
if (wording.record !== false) recordLoaderIdentityRead(surface, verb);
|
|
976
990
|
}
|
|
977
991
|
|
|
@@ -982,13 +996,16 @@ export function guardIdentityRead(
|
|
|
982
996
|
export function refuseInCacheScope(
|
|
983
997
|
surface: string,
|
|
984
998
|
{ verb, fix }: IdentityReadWording,
|
|
999
|
+
ctx?: WarmContext | null,
|
|
985
1000
|
): void {
|
|
986
1001
|
if (isInsideCacheExecScope()) {
|
|
1002
|
+
noteWarmIdentityRead(ctx, surface);
|
|
987
1003
|
throw new Error(
|
|
988
1004
|
`${surface} cannot be ${verb} inside a "use cache" function. ${fix.useCache}`,
|
|
989
1005
|
);
|
|
990
1006
|
}
|
|
991
1007
|
if (isInsideCacheScope()) {
|
|
1008
|
+
noteWarmIdentityRead(ctx, surface);
|
|
992
1009
|
throw new Error(
|
|
993
1010
|
`${surface} cannot be ${verb} inside a cache() boundary. ${fix.cacheScope}`,
|
|
994
1011
|
);
|
|
@@ -1074,7 +1091,7 @@ const NON_CACHEABLE_READ: IdentityReadWording = {
|
|
|
1074
1091
|
*/
|
|
1075
1092
|
export function assertNonCacheableReadAllowed(
|
|
1076
1093
|
keyOrVar: string | ContextVar<unknown>,
|
|
1077
|
-
requestCtx?:
|
|
1094
|
+
requestCtx?: WarmContext | null,
|
|
1078
1095
|
): void {
|
|
1079
1096
|
const name = typeof keyOrVar === "string" ? ` "${keyOrVar}"` : "";
|
|
1080
1097
|
guardIdentityRead(
|
|
@@ -1276,7 +1293,10 @@ export function isInsideAnyLoaderScope(): boolean {
|
|
|
1276
1293
|
|
|
1277
1294
|
/**
|
|
1278
1295
|
* The one ppr opt-in predicate: a page route entry that DECLARED `ppr`
|
|
1279
|
-
* (`false
|
|
1296
|
+
* (`false`, undefined, and on-demand routes mean plain axis 1). A writable
|
|
1297
|
+
* prerender refresh cannot atomically replace the separate document shell, so
|
|
1298
|
+
* combining those lanes would pair a fresh tail with a stale prelude. Shared by
|
|
1299
|
+
* the serve path
|
|
1280
1300
|
* (rsc/shell-serve.ts resolvePprConfig) and the header-write latch below so
|
|
1281
1301
|
* the two layers can never drift on what counts as a ppr route.
|
|
1282
1302
|
*/
|
|
@@ -1285,7 +1305,10 @@ export function isPprEntry(entry: EntryData): entry is EntryData & {
|
|
|
1285
1305
|
ppr: true | import("../urls/pattern-types.js").PartialPrerenderProps;
|
|
1286
1306
|
} {
|
|
1287
1307
|
return (
|
|
1288
|
-
entry.type === "route" &&
|
|
1308
|
+
entry.type === "route" &&
|
|
1309
|
+
entry.isOnDemand !== true &&
|
|
1310
|
+
entry.ppr !== undefined &&
|
|
1311
|
+
entry.ppr !== false
|
|
1289
1312
|
);
|
|
1290
1313
|
}
|
|
1291
1314
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
requestReadCaptureFix,
|
|
22
22
|
type IdentityReadWording,
|
|
23
23
|
} from "./context.js";
|
|
24
|
+
import { assertNotInsidePrerenderProducer } from "../prerender/producer-guard.js";
|
|
24
25
|
import { requestHeaders, shadowRequestHeaders } from "./request-headers.js";
|
|
25
26
|
|
|
26
27
|
/**
|
|
@@ -72,6 +73,7 @@ export interface CookieStore {
|
|
|
72
73
|
*/
|
|
73
74
|
export function cookies(): CookieStore {
|
|
74
75
|
const ctx = getRequestContext();
|
|
76
|
+
assertNotInsidePrerenderProducer(ctx, "cookies()");
|
|
75
77
|
guardIdentityRead(ctx, "cookies()", COOKIES_READ);
|
|
76
78
|
return createCookieStore(ctx);
|
|
77
79
|
}
|
|
@@ -273,6 +275,7 @@ const HEADERS_READ_PROPS = new Set<string | symbol>([
|
|
|
273
275
|
*/
|
|
274
276
|
export function headers(): ReadonlyHeaders {
|
|
275
277
|
const ctx = getRequestContext();
|
|
278
|
+
assertNotInsidePrerenderProducer(ctx, "headers()");
|
|
276
279
|
guardIdentityRead(ctx, "headers()", HEADERS_READ);
|
|
277
280
|
return new Proxy(requestHeaders(ctx.request), {
|
|
278
281
|
get(target, prop, receiver) {
|
|
@@ -313,6 +316,7 @@ export function invalidateClientCache(): void {
|
|
|
313
316
|
}
|
|
314
317
|
return;
|
|
315
318
|
}
|
|
319
|
+
assertNotInsidePrerenderProducer(ctx, "invalidateClientCache()");
|
|
316
320
|
refuseInCacheScope("invalidateClientCache()", COOKIES_READ);
|
|
317
321
|
ctx._rotateStateCookie();
|
|
318
322
|
}
|
|
@@ -338,6 +342,7 @@ export function keepClientCache(): void {
|
|
|
338
342
|
}
|
|
339
343
|
return;
|
|
340
344
|
}
|
|
345
|
+
assertNotInsidePrerenderProducer(ctx, "keepClientCache()");
|
|
341
346
|
refuseInCacheScope("keepClientCache()", COOKIES_READ);
|
|
342
347
|
ctx._setKeepCacheDirective();
|
|
343
348
|
}
|
|
@@ -340,6 +340,9 @@ export interface HandleStore {
|
|
|
340
340
|
segmentId: string,
|
|
341
341
|
): Record<string, (string | null)[]> | undefined;
|
|
342
342
|
|
|
343
|
+
/** The segment ids for which getRecordOwners returns an entry. */
|
|
344
|
+
getOwnedSegmentIds(): string[];
|
|
345
|
+
|
|
343
346
|
/**
|
|
344
347
|
* Replay cached handle data back into the store (for cache hits).
|
|
345
348
|
* Used to restore handle data when serving cached segments.
|
|
@@ -1087,6 +1090,16 @@ export function createHandleStore(): HandleStore {
|
|
|
1087
1090
|
return result;
|
|
1088
1091
|
},
|
|
1089
1092
|
|
|
1093
|
+
getOwnedSegmentIds(): string[] {
|
|
1094
|
+
const ids = new Set<string>();
|
|
1095
|
+
for (const handleName in data) {
|
|
1096
|
+
for (const id in data[handleName]) {
|
|
1097
|
+
if (!ids.has(id) && this.getRecordOwners(id)) ids.add(id);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return [...ids];
|
|
1101
|
+
},
|
|
1102
|
+
|
|
1090
1103
|
replaySegmentData(
|
|
1091
1104
|
segmentId: string,
|
|
1092
1105
|
segmentHandles: Record<string, unknown[]>,
|
|
@@ -46,7 +46,10 @@ import { withDefer } from "../defer.js";
|
|
|
46
46
|
import { type MetricsStore } from "./context.js";
|
|
47
47
|
import { observePhase, PHASES } from "../router/instrument.js";
|
|
48
48
|
import { getFetchableLoader } from "./fetchable-loader-store.js";
|
|
49
|
-
import type {
|
|
49
|
+
import type {
|
|
50
|
+
SegmentCacheStore,
|
|
51
|
+
ShellSnapshotHandlesValue,
|
|
52
|
+
} from "../cache/types.js";
|
|
50
53
|
import type { RouterVersions } from "../router-versions.js";
|
|
51
54
|
import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
|
|
52
55
|
import type { ExecutionContext, RequestScope } from "../types/request-scope.js";
|
|
@@ -289,6 +292,30 @@ export interface RequestContext<
|
|
|
289
292
|
/** @internal Cache store for segment caching (optional, used by CacheScope) */
|
|
290
293
|
_cacheStore?: SegmentCacheStore;
|
|
291
294
|
|
|
295
|
+
/**
|
|
296
|
+
* @internal Env-scoped writable prerender store (the durable overlay) plus the
|
|
297
|
+
* deployment identity for build-scoped keys, resolved per request from the
|
|
298
|
+
* `prerender` router option. Read by the serve-path overlay lookup before the
|
|
299
|
+
* bundled build manifest. Absent when no prerender store is configured.
|
|
300
|
+
*/
|
|
301
|
+
// ResolvedPrerender<any> (not <TEnv>): onRevalidate's contravariant `env` would
|
|
302
|
+
// otherwise make RequestContext invariant in TEnv, breaking existing
|
|
303
|
+
// RequestContext<{}> -> RequestContext<unknown> assignments.
|
|
304
|
+
_prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @internal Set only on the requestless on-demand producer's context. When
|
|
308
|
+
* present, the standalone request-scoped READS — `cookies()`, `headers()`,
|
|
309
|
+
* `invalidateClientCache()`, `keepClientCache()` — throw a
|
|
310
|
+
* PrerenderPersonalizationError so a personalized render is skipped rather than
|
|
311
|
+
* baked into a shared payload. Response MUTATIONS on the producer context
|
|
312
|
+
* (`ctx.setStatus`/`header`/`setCookie`) stay silent no-op stubs, matching
|
|
313
|
+
* build-time prerender (the design's "throw or skip" contract permits skip):
|
|
314
|
+
* they write to a discarded synthetic response, so there is nothing to leak.
|
|
315
|
+
* Never set on the live request path.
|
|
316
|
+
*/
|
|
317
|
+
_onDemandProducer?: true;
|
|
318
|
+
|
|
292
319
|
/**
|
|
293
320
|
* @internal Compiled `cache.searchParams` filter for default cache-key
|
|
294
321
|
* generation (undefined = "all", the byte-stable unfiltered format). Set
|
|
@@ -365,6 +392,22 @@ export interface RequestContext<
|
|
|
365
392
|
*/
|
|
366
393
|
_shellForcedMiss?: true;
|
|
367
394
|
|
|
395
|
+
/**
|
|
396
|
+
* @internal This request is a router.prerender() warm
|
|
397
|
+
* (prerender/warm-request.ts). In `replace` mode every runtime cache read
|
|
398
|
+
* misses (isWarmReplace); the layers report into the record. A capture's
|
|
399
|
+
* derived context inherits it through the prototype.
|
|
400
|
+
*/
|
|
401
|
+
_prerenderWarm?: import("../prerender/warm-request.js").PrerenderWarmRecord;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @internal Runs a callback in the async context this request entered the
|
|
405
|
+
* handler with (captureRequestEntryContext). router.prerender() dispatches
|
|
406
|
+
* a warm through it when called from inside a request. Absent where the
|
|
407
|
+
* runtime has no AsyncLocalStorage.snapshot.
|
|
408
|
+
*/
|
|
409
|
+
_runAtRequestEntry?: <T>(fn: () => T) => T;
|
|
410
|
+
|
|
368
411
|
/**
|
|
369
412
|
* @internal The freshness window of the route cache() records this
|
|
370
413
|
* request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
|
|
@@ -459,6 +502,8 @@ export interface RequestContext<
|
|
|
459
502
|
* host) and miss the record.
|
|
460
503
|
*/
|
|
461
504
|
fixedDocKey?: string;
|
|
505
|
+
/** @internal The snapshot's `handles` record (ShellSnapshotHandlesValue). */
|
|
506
|
+
prerenderHandles?: ShellSnapshotHandlesValue;
|
|
462
507
|
/**
|
|
463
508
|
* @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
|
|
464
509
|
* serve path. Its presence arms the explicit-scope composition in
|
|
@@ -808,6 +853,18 @@ export interface RequestContext<
|
|
|
808
853
|
*/
|
|
809
854
|
_renderErrors?: unknown[];
|
|
810
855
|
|
|
856
|
+
/**
|
|
857
|
+
* @internal Rejections of streamed (loading()) handlers that were recovered
|
|
858
|
+
* into a declared errorBoundary()/notFoundBoundary() fallback, by segment id.
|
|
859
|
+
* The recovered promise resolves, so Flight reports nothing; cacheRoute
|
|
860
|
+
* (cache-scope.ts) refuses a write only when one of ITS segments is listed,
|
|
861
|
+
* the granularity a Flight error row has. The same errors are also pushed to
|
|
862
|
+
* `_renderErrors` for the document cache and PPR shell capture. A render
|
|
863
|
+
* under a derived context (shell capture, SWR re-render) owns its own map.
|
|
864
|
+
* Allocated on the first recovery.
|
|
865
|
+
*/
|
|
866
|
+
_recoveredHandlerErrors?: Map<string, unknown>;
|
|
867
|
+
|
|
811
868
|
/**
|
|
812
869
|
* @internal Report a non-fatal background error through the router's
|
|
813
870
|
* onError callback. Wired by the RSC handler / router during request
|
|
@@ -926,6 +983,8 @@ export type PublicRequestContext<
|
|
|
926
983
|
| "_transitionWhenRefs"
|
|
927
984
|
| "_pprReplayPostMatchReason"
|
|
928
985
|
| "_cacheStore"
|
|
986
|
+
| "_prerender"
|
|
987
|
+
| "_onDemandProducer"
|
|
929
988
|
| "_searchParamsFilter"
|
|
930
989
|
| "_shellCaptureRun"
|
|
931
990
|
| "_shellImplicitCache"
|
|
@@ -936,6 +995,8 @@ export type PublicRequestContext<
|
|
|
936
995
|
| "_resolvedCacheKeys"
|
|
937
996
|
| "_shellKey"
|
|
938
997
|
| "_shellForcedMiss"
|
|
998
|
+
| "_prerenderWarm"
|
|
999
|
+
| "_runAtRequestEntry"
|
|
939
1000
|
| "_routeRecordWindow"
|
|
940
1001
|
| "_shellFragmentPayload"
|
|
941
1002
|
| "_shellCaptureGuardTripped"
|
|
@@ -957,6 +1018,7 @@ export type PublicRequestContext<
|
|
|
957
1018
|
| "_inActionRevalidation"
|
|
958
1019
|
| "_reportedErrors"
|
|
959
1020
|
| "_renderErrors"
|
|
1021
|
+
| "_recoveredHandlerErrors"
|
|
960
1022
|
| "_renderBarrier"
|
|
961
1023
|
| "_resolveRenderBarrier"
|
|
962
1024
|
| "_renderBarrierSegmentOrder"
|
|
@@ -1007,6 +1069,22 @@ export const UNTRACKED_BACKGROUND_TASK: unique symbol = Symbol.for(
|
|
|
1007
1069
|
// AsyncLocalStorage instance for request context
|
|
1008
1070
|
const requestContextStorage = new AsyncLocalStorage<RequestContext<any>>();
|
|
1009
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* Capture the current async context (RequestContext._runAtRequestEntry), taken
|
|
1074
|
+
* on handler entry before any router scope, so a nested dispatch (a
|
|
1075
|
+
* router.prerender() warm called from a handler, loader or action) does not
|
|
1076
|
+
* inherit the caller's route-definition, loader and cache-scope state. Per
|
|
1077
|
+
* request: workerd refuses a snapshot outside the request that created it.
|
|
1078
|
+
* See docs/design/prerender-every-route.md.
|
|
1079
|
+
*/
|
|
1080
|
+
export function captureRequestEntryContext():
|
|
1081
|
+
| (<T>(fn: () => T) => T)
|
|
1082
|
+
| undefined {
|
|
1083
|
+
return typeof AsyncLocalStorage.snapshot === "function"
|
|
1084
|
+
? AsyncLocalStorage.snapshot()
|
|
1085
|
+
: undefined;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1010
1088
|
/**
|
|
1011
1089
|
* Run a function within a request context
|
|
1012
1090
|
* Used by the RSC handler to provide context to server actions
|
|
@@ -1118,6 +1196,12 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
1118
1196
|
initialResponse?: Response;
|
|
1119
1197
|
/** Optional cache store for segment caching (used by CacheScope) */
|
|
1120
1198
|
cacheStore?: SegmentCacheStore;
|
|
1199
|
+
/**
|
|
1200
|
+
* Optional env-scoped writable prerender store + deployment identity (the
|
|
1201
|
+
* durable overlay), resolved per request by the RSC handler from the
|
|
1202
|
+
* `prerender` router option.
|
|
1203
|
+
*/
|
|
1204
|
+
prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
1121
1205
|
/**
|
|
1122
1206
|
* Compiled `cache.searchParams` filter from the resolved handler cache
|
|
1123
1207
|
* config (handler.ts). Stored as _searchParamsFilter.
|
|
@@ -1168,6 +1252,7 @@ export function createRequestContext<TEnv>(
|
|
|
1168
1252
|
variables,
|
|
1169
1253
|
initialResponse,
|
|
1170
1254
|
cacheStore,
|
|
1255
|
+
prerender,
|
|
1171
1256
|
searchParamsFilter,
|
|
1172
1257
|
explicitTaggedStores,
|
|
1173
1258
|
cacheProfiles,
|
|
@@ -1543,6 +1628,7 @@ export function createRequestContext<TEnv>(
|
|
|
1543
1628
|
|
|
1544
1629
|
_handleStore: handleStore,
|
|
1545
1630
|
_cacheStore: cacheStore,
|
|
1631
|
+
_prerender: prerender,
|
|
1546
1632
|
_versions: versions,
|
|
1547
1633
|
_searchParamsFilter: searchParamsFilter,
|
|
1548
1634
|
_explicitTaggedStores: explicitTaggedStores,
|