@rangojs/router 0.27.0 → 0.29.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 +1 -1
- package/dist/types/__internal.d.ts +7 -1
- package/dist/types/browser/action-fence.d.ts +2 -1
- package/dist/types/browser/event-controller.d.ts +8 -2
- package/dist/types/browser/history-state.d.ts +3 -9
- package/dist/types/browser/navigation-store.d.ts +8 -6
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
- package/dist/types/browser/react/use-action.d.ts +7 -2
- package/dist/types/browser/react/use-handle.d.ts +19 -16
- package/dist/types/browser/react/use-link-status.d.ts +5 -2
- package/dist/types/browser/segment-reconciler.d.ts +32 -4
- package/dist/types/browser/types.d.ts +24 -5
- package/dist/types/browser/wire-protocol.d.ts +26 -0
- package/dist/types/cache/cache-key-utils.d.ts +11 -5
- package/dist/types/cache/cache-scope.d.ts +34 -22
- package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
- package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
- package/dist/types/cache/handle-snapshot.d.ts +9 -4
- package/dist/types/cache/segment-codec.d.ts +14 -0
- package/dist/types/cache/shell-snapshot.d.ts +1 -1
- package/dist/types/cache/taint.d.ts +5 -3
- package/dist/types/cache/types.d.ts +7 -3
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
- package/dist/types/prefetch-markers.d.ts +5 -14
- package/dist/types/prerender/store.d.ts +31 -0
- package/dist/types/prerender/warm-request.d.ts +3 -3
- package/dist/types/prerender.d.ts +2 -2
- package/dist/types/route-name.d.ts +5 -0
- package/dist/types/router/error-handling.d.ts +11 -5
- package/dist/types/router/instrument.d.ts +4 -3
- package/dist/types/router/intercept-resolution.d.ts +25 -9
- package/dist/types/router/match-context.d.ts +6 -11
- package/dist/types/router/match-handlers.d.ts +2 -6
- package/dist/types/router/match-middleware/background-revalidation.d.ts +13 -22
- package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
- package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
- package/dist/types/router/navigation-snapshot.d.ts +7 -0
- package/dist/types/router/prerender-match.d.ts +21 -6
- package/dist/types/router/preview-match.d.ts +2 -7
- package/dist/types/router/request-classification.d.ts +5 -0
- package/dist/types/router/router-context.d.ts +7 -46
- package/dist/types/router/router-interfaces.d.ts +8 -14
- package/dist/types/router/segment-resolution/helpers.d.ts +19 -3
- package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
- package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
- package/dist/types/router/segment-resolution/resolution-pass.d.ts +95 -0
- package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +2 -0
- package/dist/types/router/segment-resolution.d.ts +1 -2
- package/dist/types/router/segment-wrappers.d.ts +11 -48
- package/dist/types/router/telemetry.d.ts +2 -0
- package/dist/types/router/types.d.ts +11 -1
- package/dist/types/rsc/full-payload.d.ts +2 -2
- package/dist/types/rsc/handler-context.d.ts +6 -6
- package/dist/types/rsc/json-route-result.d.ts +5 -9
- package/dist/types/rsc/request-stages.d.ts +203 -0
- package/dist/types/rsc/response-cache-serve.d.ts +7 -12
- package/dist/types/rsc/response-route-handler.d.ts +2 -2
- package/dist/types/rsc/routine-plan.d.ts +1 -1
- package/dist/types/rsc/server-action.d.ts +2 -2
- package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
- package/dist/types/rsc/shell-capture.d.ts +132 -15
- package/dist/types/rsc/shell-serve.d.ts +37 -12
- package/dist/types/server/context.d.ts +9 -8
- package/dist/types/server/handle-store.d.ts +16 -0
- package/dist/types/server/render-pass.d.ts +72 -0
- package/dist/types/server/request-context.d.ts +53 -104
- package/dist/types/server/rewrite-trail.d.ts +2 -2
- package/dist/types/testing/dispatch.d.ts +35 -18
- package/dist/types/testing/render-route.d.ts +43 -8
- package/dist/types/testing/serve-shell-request.d.ts +8 -1
- package/dist/types/types/cache-types.d.ts +6 -3
- package/dist/types/types/error-types.d.ts +30 -3
- package/dist/types/types/handler-context.d.ts +9 -1
- package/dist/types/types/segments.d.ts +1 -1
- package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
- package/dist/types/vite/discovery/build-env.d.ts +22 -0
- package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
- package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
- package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
- package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
- package/dist/types/vite/discovery/state.d.ts +12 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
- package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +8 -47
- package/dist/types/vite/temp-rsc-server.d.ts +39 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
- package/dist/types/wire-params.d.ts +39 -0
- package/dist/vite/index.js +3822 -3727
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +8 -5
- package/skills/caching/SKILL.md +37 -18
- package/skills/client-urls/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +13 -1
- package/skills/handler-use/SKILL.md +1 -1
- package/skills/hooks/SKILL.md +1 -1
- package/skills/hooks/data.md +8 -1
- package/skills/hooks/handle-and-actions.md +33 -2
- package/skills/hooks/navigation.md +121 -15
- package/skills/hooks/state.md +6 -4
- package/skills/hooks/urls.md +16 -5
- package/skills/intercept/SKILL.md +23 -7
- package/skills/middleware/SKILL.md +18 -0
- package/skills/observability/SKILL.md +30 -0
- package/skills/ppr/SKILL.md +18 -3
- package/skills/prerender/SKILL.md +39 -15
- package/skills/rango/SKILL.md +5 -1
- package/skills/server-actions/SKILL.md +15 -1
- package/skills/testing/client-components.md +25 -18
- package/skills/testing/response-routes.md +6 -4
- package/skills/testing/serve-shell-request.md +7 -7
- package/skills/use-cache/SKILL.md +46 -8
- package/skills/view-transitions/SKILL.md +1 -1
- package/src/__internal.ts +7 -1
- package/src/browser/action-fence.ts +2 -1
- package/src/browser/connection-warmup.ts +3 -1
- package/src/browser/event-controller.ts +37 -13
- package/src/browser/history-state.ts +6 -12
- package/src/browser/navigation-bridge.ts +59 -26
- package/src/browser/navigation-client.ts +20 -25
- package/src/browser/navigation-store.ts +25 -27
- package/src/browser/navigation-transaction.ts +4 -1
- package/src/browser/network-error-handler.ts +4 -0
- package/src/browser/partial-update.ts +33 -6
- package/src/browser/prefetch/cache.ts +2 -1
- package/src/browser/prefetch/fetch.ts +8 -16
- package/src/browser/prefetch/queue.ts +4 -4
- package/src/browser/react/NavigationProvider.tsx +2 -1
- package/src/browser/react/filter-segment-order.ts +2 -2
- package/src/browser/react/use-action.ts +24 -48
- package/src/browser/react/use-handle.ts +22 -18
- package/src/browser/react/use-link-status.ts +48 -60
- package/src/browser/react/use-navigation.ts +92 -41
- package/src/browser/rsc-router.tsx +1 -0
- package/src/browser/segment-reconciler.ts +109 -53
- package/src/browser/server-action-bridge.ts +81 -61
- package/src/browser/types.ts +25 -5
- package/src/browser/wire-protocol.ts +43 -0
- package/src/cache/cache-key-utils.ts +11 -5
- package/src/cache/cache-runtime.ts +132 -75
- package/src/cache/cache-scope.ts +110 -64
- package/src/cache/cf/cf-cache-constants.ts +2 -2
- package/src/cache/cf/cf-cache-store.ts +486 -874
- package/src/cache/cf/cf-kv-utils.ts +1 -1
- package/src/cache/document-cache.ts +64 -46
- package/src/cache/handle-snapshot.ts +19 -7
- package/src/cache/read-through-swr.ts +20 -18
- package/src/cache/segment-codec.ts +55 -0
- package/src/cache/shell-snapshot.ts +2 -2
- package/src/cache/tag-invalidation.ts +6 -2
- package/src/cache/taint.ts +5 -3
- package/src/cache/types.ts +7 -3
- package/src/cache/vercel/vercel-cache-store.ts +243 -310
- package/src/handles/pushed-by.ts +1 -1
- package/src/prefetch-markers.ts +5 -16
- package/src/prerender/store.ts +76 -0
- package/src/prerender/warm-request.ts +8 -4
- package/src/prerender.ts +2 -2
- package/src/route-name.ts +8 -0
- package/src/router/error-handling.ts +22 -10
- package/src/router/instrument.ts +4 -3
- package/src/router/intercept-resolution.ts +82 -75
- package/src/router/loader-resolution.ts +5 -4
- package/src/router/match-api.ts +5 -5
- package/src/router/match-context.ts +23 -12
- package/src/router/match-handlers.ts +8 -20
- package/src/router/match-middleware/background-revalidation.ts +46 -57
- package/src/router/match-middleware/cache-lookup.ts +677 -726
- package/src/router/match-middleware/cache-store.ts +4 -8
- package/src/router/match-middleware/intercept-resolution.ts +3 -23
- package/src/router/match-middleware/segment-resolution.ts +34 -61
- package/src/router/middleware.ts +69 -11
- package/src/router/navigation-snapshot.ts +14 -4
- package/src/router/prerender-match.ts +100 -44
- package/src/router/preview-match.ts +6 -41
- package/src/router/request-classification.ts +13 -7
- package/src/router/route-snapshot.ts +2 -5
- package/src/router/router-context.ts +10 -95
- package/src/router/router-interfaces.ts +8 -14
- package/src/router/segment-resolution/helpers.ts +49 -13
- package/src/router/segment-resolution/loader-cache.ts +15 -9
- package/src/router/segment-resolution/loader-mask.ts +5 -5
- package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
- package/src/router/segment-resolution/resolution-pass.ts +139 -0
- package/src/router/segment-resolution/revalidation.ts +939 -789
- package/src/router/segment-resolution/streamed-handler-boundary.ts +3 -0
- package/src/router/segment-resolution.ts +4 -13
- package/src/router/segment-wrappers.ts +51 -269
- package/src/router/telemetry.ts +5 -0
- package/src/router/types.ts +11 -1
- package/src/router.ts +19 -17
- package/src/rsc/full-payload.ts +6 -5
- package/src/rsc/handler-context.ts +8 -14
- package/src/rsc/handler.ts +126 -507
- package/src/rsc/json-route-result.ts +5 -9
- package/src/rsc/loader-fetch.ts +6 -5
- package/src/rsc/progressive-enhancement.ts +5 -0
- package/src/rsc/request-stages.ts +759 -0
- package/src/rsc/response-cache-serve.ts +10 -14
- package/src/rsc/response-route-handler.ts +13 -5
- package/src/rsc/rewrite-passes.ts +2 -1
- package/src/rsc/routine-plan.ts +1 -1
- package/src/rsc/rsc-rendering.ts +164 -349
- package/src/rsc/server-action.ts +87 -113
- package/src/rsc/shell-capture-constants.ts +1 -1
- package/src/rsc/shell-capture.ts +275 -227
- package/src/rsc/shell-serve.ts +121 -18
- package/src/rsc/ssr-setup.ts +5 -4
- package/src/segment-system.tsx +3 -3
- package/src/server/context.ts +22 -25
- package/src/server/handle-store.ts +55 -0
- package/src/server/render-pass.ts +291 -0
- package/src/server/request-context.ts +75 -115
- package/src/server/rewrite-trail.ts +6 -4
- package/src/ssr/index.tsx +1 -1
- package/src/testing/dispatch.ts +226 -710
- package/src/testing/e2e/page-helpers.ts +2 -2
- package/src/testing/render-route.tsx +199 -13
- package/src/testing/serve-shell-request.ts +36 -40
- package/src/types/cache-types.ts +6 -3
- package/src/types/error-types.ts +30 -3
- package/src/types/handler-context.ts +12 -1
- package/src/types/segments.ts +1 -1
- package/src/vite/discovery/build-discovery-phase.ts +204 -0
- package/src/vite/discovery/build-env.ts +148 -0
- package/src/vite/discovery/bundle-scan-phase.ts +128 -0
- package/src/vite/discovery/dev-prerender-cache.ts +8 -3
- package/src/vite/discovery/dev-server-phase.ts +1776 -0
- package/src/vite/discovery/discover-routers.ts +1 -1
- package/src/vite/discovery/discovery-errors.ts +1 -1
- package/src/vite/discovery/prerender-collection.ts +24 -39
- package/src/vite/discovery/state.ts +15 -0
- package/src/vite/plugins/version-plugin.ts +1 -1
- package/src/vite/plugins/virtual-entries.ts +1 -1
- package/src/vite/router-discovery.ts +29 -2428
- package/src/vite/temp-rsc-server.ts +223 -0
- package/src/vite/utils/prerender-utils.ts +47 -0
- package/src/wire-params.ts +40 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
- package/src/router/segment-resolution/fresh.ts +0 -945
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derived render passes over a request past its middleware (PPR shell
|
|
3
|
+
* capture, PPR HIT tail, background re-render, document cache re-run), each
|
|
4
|
+
* `Object.create(base)`.
|
|
5
|
+
* A field missing from a RENDER_PASS_FIELDS row reads the foreground
|
|
6
|
+
* request's value (#684). derived-context-shape.rsc-test.tsx pins each row's
|
|
7
|
+
* own keys.
|
|
8
|
+
*/
|
|
9
|
+
import type { RecordingShellStore } from "../cache/shell-snapshot.js";
|
|
10
|
+
import type { HandleStore } from "./handle-store.js";
|
|
11
|
+
import {
|
|
12
|
+
bindRes,
|
|
13
|
+
createUseFunction,
|
|
14
|
+
wireRenderBarrier,
|
|
15
|
+
type RequestContext,
|
|
16
|
+
} from "./request-context.js";
|
|
17
|
+
|
|
18
|
+
type ShellImplicitCache = NonNullable<RequestContext["_shellImplicitCache"]>;
|
|
19
|
+
|
|
20
|
+
/** _handleStore, readonly on RequestContext, is written by the rows. */
|
|
21
|
+
type PassUnderConstruction = RequestContext<any> & {
|
|
22
|
+
_handleStore: HandleStore;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** What each purpose's caller builds for its row. */
|
|
26
|
+
export interface RenderPassInit {
|
|
27
|
+
"shell-capture": {
|
|
28
|
+
handleStore: HandleStore;
|
|
29
|
+
/** A navigation-only capture renders this URL instead of the request's. */
|
|
30
|
+
identity: { request: Request; url: URL } | undefined;
|
|
31
|
+
/** Only with a cache store on the request. */
|
|
32
|
+
recording:
|
|
33
|
+
| { store: RecordingShellStore; implicitCache: ShellImplicitCache }
|
|
34
|
+
| undefined;
|
|
35
|
+
};
|
|
36
|
+
"ppr-tail": {
|
|
37
|
+
/** The request's store, shared: the tail's handles are this response's. */
|
|
38
|
+
handleStore: HandleStore;
|
|
39
|
+
loaderSeed: RequestContext["_shellLoaderSeed"];
|
|
40
|
+
implicitCache: ShellImplicitCache;
|
|
41
|
+
};
|
|
42
|
+
"background-revalidation": {
|
|
43
|
+
handleStore: HandleStore;
|
|
44
|
+
/** Throwaway: the pass's response writes land here and are dropped. */
|
|
45
|
+
sink: RequestContext<any>;
|
|
46
|
+
};
|
|
47
|
+
"document-revalidation": {
|
|
48
|
+
/** The request's: the stale HIT pushed nothing into it. */
|
|
49
|
+
handleStore: HandleStore;
|
|
50
|
+
/**
|
|
51
|
+
* Holds the re-run's response writes, which make the response the
|
|
52
|
+
* document cache stores; starts from the request's response stub.
|
|
53
|
+
*/
|
|
54
|
+
sink: RequestContext<any>;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type RenderPurpose = keyof RenderPassInit;
|
|
59
|
+
|
|
60
|
+
interface PassFieldPolicy<I> {
|
|
61
|
+
/** "own": wireRenderBarrier(pass, init.handleStore) before `own` runs. */
|
|
62
|
+
readonly renderBarrier: "own" | "inherited";
|
|
63
|
+
/**
|
|
64
|
+
* Named stores, not one Object.assign: on Node 24 an Object.assign that
|
|
65
|
+
* takes the object to 20 own properties leaves it in V8 dictionary mode
|
|
66
|
+
* (#1109).
|
|
67
|
+
*/
|
|
68
|
+
readonly own: (
|
|
69
|
+
pass: PassUnderConstruction,
|
|
70
|
+
init: I,
|
|
71
|
+
base: RequestContext<any>,
|
|
72
|
+
) => void;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const RENDER_PASS_FIELDS: {
|
|
76
|
+
readonly [P in RenderPurpose]: PassFieldPolicy<RenderPassInit[P]>;
|
|
77
|
+
} = {
|
|
78
|
+
/** rsc/shell-capture.ts deriveShellCaptureContext. */
|
|
79
|
+
"shell-capture": {
|
|
80
|
+
// #684: an inherited barrier is the foreground's, already resolved:
|
|
81
|
+
// ctx.rendered() returns at once and ctx.use(handle) bakes the
|
|
82
|
+
// foreground's handles into the shell.
|
|
83
|
+
renderBarrier: "own",
|
|
84
|
+
own(pass, { handleStore, identity, recording }, base) {
|
|
85
|
+
// Fresh: the foreground's is drained and throws LateHandlePushError.
|
|
86
|
+
pass._handleStore = handleStore;
|
|
87
|
+
if (identity) {
|
|
88
|
+
pass.request = identity.request;
|
|
89
|
+
pass.url = identity.url;
|
|
90
|
+
pass.originalUrl = new URL(identity.url);
|
|
91
|
+
pass.pathname = identity.url.pathname;
|
|
92
|
+
pass.searchParams = identity.url.searchParams;
|
|
93
|
+
}
|
|
94
|
+
// The shell entry's invalidation tags (loader tags belong to holes).
|
|
95
|
+
pass._requestTags = new Set<string>();
|
|
96
|
+
// A capture-ephemeral store in the handler-lifetime set would warn on
|
|
97
|
+
// every later updateTag() and retain the snapshot.
|
|
98
|
+
pass._explicitTaggedStores = new Set();
|
|
99
|
+
// The capture's render errors refuse the capture only.
|
|
100
|
+
pass._renderErrors = [];
|
|
101
|
+
pass._recoveredHandlerErrors = undefined;
|
|
102
|
+
// `run` is read by the loader, cookies() and headers() capture guards.
|
|
103
|
+
// Every field is present from here on: one shape while the capture
|
|
104
|
+
// writes it.
|
|
105
|
+
pass._shellCaptureState = {
|
|
106
|
+
run: true,
|
|
107
|
+
forVisitor: undefined,
|
|
108
|
+
// Bake-lane loader containers: settleCaptureRecord awaits them, the
|
|
109
|
+
// drain pins them into the snapshot.
|
|
110
|
+
loaderRecords: new Map(),
|
|
111
|
+
unrecordedLoaderPush: undefined,
|
|
112
|
+
loaderLanes: undefined,
|
|
113
|
+
guardTripped: undefined,
|
|
114
|
+
guardTrippedLoaderId: undefined,
|
|
115
|
+
// The capture notes its own route records, not the foreground's.
|
|
116
|
+
routeRecordWindow: undefined,
|
|
117
|
+
};
|
|
118
|
+
// The inherited dynamic() writes the foreground, which already served;
|
|
119
|
+
// settleCaptureRecord and captureAndStoreShell read this latch.
|
|
120
|
+
pass._dynamic = false;
|
|
121
|
+
pass.dynamic = (): void => {
|
|
122
|
+
pass._dynamic = true;
|
|
123
|
+
};
|
|
124
|
+
// An inherited true makes serializeSegments double-encode a fragment.
|
|
125
|
+
pass._shellFragmentPayload = false;
|
|
126
|
+
// Metrics and spans are foreground surfaces, already ended.
|
|
127
|
+
pass._metricsStore = undefined;
|
|
128
|
+
pass._tracing = undefined;
|
|
129
|
+
// Fired by settleCaptureRecord: the capture builds no Response, and the
|
|
130
|
+
// doc record's write is gated on onResponse.
|
|
131
|
+
pass._onResponseCallbacks = [];
|
|
132
|
+
if (recording) {
|
|
133
|
+
// Own, so the request's _cacheStore is untouched.
|
|
134
|
+
pass._cacheStore = recording.store;
|
|
135
|
+
// Collects deferred cache writes (settleCaptureRecord awaits them)
|
|
136
|
+
// and still forwards each to the request's waitUntil.
|
|
137
|
+
pass.waitUntil = (fn: () => Promise<void>): void => {
|
|
138
|
+
const p = Promise.resolve().then(fn);
|
|
139
|
+
recording.store.trackWrite(p);
|
|
140
|
+
base.waitUntil(() => p);
|
|
141
|
+
};
|
|
142
|
+
// The doc record goes into the snapshot only, so a recapture misses
|
|
143
|
+
// and handlers re-run.
|
|
144
|
+
pass._shellImplicitCache = recording.implicitCache;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/** rsc/rsc-rendering.ts serveShellHit. */
|
|
150
|
+
"ppr-tail": {
|
|
151
|
+
// An inherited barrier carries the base's premature non-streaming handle
|
|
152
|
+
// snapshot into a streaming tail.
|
|
153
|
+
renderBarrier: "own",
|
|
154
|
+
own(pass, { handleStore, loaderSeed, implicitCache }) {
|
|
155
|
+
// #1035: the document hydrates with the handles as of the record
|
|
156
|
+
// replay, before any loader runs.
|
|
157
|
+
const resolveRenderBarrier = pass._resolveRenderBarrier;
|
|
158
|
+
pass._resolveRenderBarrier = (segments) => {
|
|
159
|
+
handleStore.freezeDocumentSnapshot();
|
|
160
|
+
resolveRenderBarrier(segments);
|
|
161
|
+
};
|
|
162
|
+
if (loaderSeed) pass._shellLoaderSeed = loaderSeed;
|
|
163
|
+
pass._shellImplicitCache = implicitCache;
|
|
164
|
+
// #700 fragment splice: own, so it never reaches a capture render.
|
|
165
|
+
pass._shellFragmentPayload = true;
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* router/match-middleware/background-revalidation.ts rerenderAndCacheRoute.
|
|
171
|
+
*/
|
|
172
|
+
"background-revalidation": {
|
|
173
|
+
// The request's, resolved before the pass starts: a stale HIT resolves
|
|
174
|
+
// it in cache-lookup.ts before withBackgroundRevalidation starts the
|
|
175
|
+
// refresh, and proactive caching runs from onResponse, so a loader's
|
|
176
|
+
// rendered() here never waits. The route's and an open intercept's
|
|
177
|
+
// passes skip loaders: one runs only when a handler reads it, started
|
|
178
|
+
// through its registration (resolveOwnerLoaders), so its pushes stay out
|
|
179
|
+
// of the record (captureHandles drops loader pushes) and its value bakes
|
|
180
|
+
// into the handler's output, as on a MISS. A shell capture never opens
|
|
181
|
+
// an intercept (createNavigationCaptureRequest drops the intercept
|
|
182
|
+
// source).
|
|
183
|
+
renderBarrier: "inherited",
|
|
184
|
+
own(pass, { handleStore, sink }) {
|
|
185
|
+
// Read late by loader pushes and cache-scope.ts; setupLoaderAccess
|
|
186
|
+
// binds it at setup, so that also runs inside this pass.
|
|
187
|
+
pass._handleStore = handleStore;
|
|
188
|
+
// Nothing lands on the foreground's perf timeline.
|
|
189
|
+
pass._metricsStore = undefined;
|
|
190
|
+
pass._renderErrors = [];
|
|
191
|
+
pass._recoveredHandlerErrors = undefined;
|
|
192
|
+
// The barrier's deadlock bookkeeping is the pass's own and stays open.
|
|
193
|
+
// The visitor's is closed once its barrier resolves, so a handler's
|
|
194
|
+
// read of a loader that calls rendered() went unrecorded and rendered()
|
|
195
|
+
// let it through: the record baked the visitor's handle snapshot, or on
|
|
196
|
+
// a streaming tree rendered() awaited this pass's store, which awaits
|
|
197
|
+
// that handler, and the refresh never settled. Open, the read is
|
|
198
|
+
// refused as a MISS refuses it.
|
|
199
|
+
pass._handlerLoaderDeps = undefined;
|
|
200
|
+
pass._renderBarrierWaiters = undefined;
|
|
201
|
+
pass._renderBarrierGuardClosed = undefined;
|
|
202
|
+
// A route cache() record, not a shell, even when a capture's stale read
|
|
203
|
+
// starts it: under the capture's guard a loader body's headers() fails
|
|
204
|
+
// the refresh, and recaptures replay the stale record until it expires.
|
|
205
|
+
pass._shellCaptureState = undefined;
|
|
206
|
+
// Response writes go to the sink: a layout above the cache() boundary
|
|
207
|
+
// or an error boundary's status would otherwise reach the live response.
|
|
208
|
+
pass._onResponseCallbacks = [];
|
|
209
|
+
pass.header = sink.header;
|
|
210
|
+
pass.setCookie = sink.setCookie;
|
|
211
|
+
pass.deleteCookie = sink.deleteCookie;
|
|
212
|
+
pass.setStatus = sink.setStatus;
|
|
213
|
+
pass._setStatus = sink._setStatus;
|
|
214
|
+
pass.setTheme = sink.setTheme;
|
|
215
|
+
pass._rotateStateCookie = sink._rotateStateCookie;
|
|
216
|
+
pass._setKeepCacheDirective = sink._setKeepCacheDirective;
|
|
217
|
+
// An invalidation here is not the visitor's mutation.
|
|
218
|
+
pass._setFreshReadsCookie = sink._setFreshReadsCookie;
|
|
219
|
+
// A cached handler's dynamic() opts out nothing here: the inherited one
|
|
220
|
+
// would refuse the capture whose stale read started the pass, or opt
|
|
221
|
+
// out the visitor's request.
|
|
222
|
+
pass.dynamic = sink.dynamic;
|
|
223
|
+
bindRes(pass, () => sink.res);
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
/** cache/document-cache.ts: the re-run of a stale entry, a whole request. */
|
|
228
|
+
"document-revalidation": {
|
|
229
|
+
// The stale HIT matched and rendered nothing: the re-run is the
|
|
230
|
+
// request's render. The request's barrier closes over the request, whose
|
|
231
|
+
// _treeHasStreaming the re-run never sets.
|
|
232
|
+
renderBarrier: "own",
|
|
233
|
+
own(pass, { handleStore, sink }, base) {
|
|
234
|
+
pass._handleStore = handleStore;
|
|
235
|
+
// The request's use() reads the request's params and route name, which
|
|
236
|
+
// the re-run's match sets on this pass. Its own memo: a loader that
|
|
237
|
+
// middleware ahead of the cache started runs again here.
|
|
238
|
+
pass.use = createUseFunction({
|
|
239
|
+
handleStore,
|
|
240
|
+
loaderPromises: new Map(),
|
|
241
|
+
getContext: () => pass,
|
|
242
|
+
});
|
|
243
|
+
// Its own latch, from what middleware ahead of the cache set: the
|
|
244
|
+
// render reads it on this pass, as a MISS reads the request's. The
|
|
245
|
+
// sink's dynamic() clears the ppr header latch.
|
|
246
|
+
pass._dynamic = base._dynamic;
|
|
247
|
+
pass.dynamic = (): void => {
|
|
248
|
+
pass._dynamic = true;
|
|
249
|
+
sink.dynamic();
|
|
250
|
+
};
|
|
251
|
+
pass._metricsStore = undefined;
|
|
252
|
+
// The re-run's classify timing stays off the visitor's Server-Timing.
|
|
253
|
+
pass._handlerTiming = [];
|
|
254
|
+
pass._renderErrors = [];
|
|
255
|
+
pass._recoveredHandlerErrors = undefined;
|
|
256
|
+
pass._shellCaptureState = undefined;
|
|
257
|
+
// Response writes go to the sink, never the visitor's STALE response.
|
|
258
|
+
pass._onResponseCallbacks = [];
|
|
259
|
+
pass.header = sink.header;
|
|
260
|
+
pass.setCookie = sink.setCookie;
|
|
261
|
+
pass.deleteCookie = sink.deleteCookie;
|
|
262
|
+
pass.setStatus = sink.setStatus;
|
|
263
|
+
pass._setStatus = sink._setStatus;
|
|
264
|
+
pass.setTheme = sink.setTheme;
|
|
265
|
+
pass._setKeepCacheDirective = sink._setKeepCacheDirective;
|
|
266
|
+
// No client receives the re-run's response: no rotation, no
|
|
267
|
+
// fresh-reads cookie (the sink has no state cookie name).
|
|
268
|
+
pass._rotateStateCookie = sink._rotateStateCookie;
|
|
269
|
+
pass._setFreshReadsCookie = sink._setFreshReadsCookie;
|
|
270
|
+
bindRes(pass, () => sink.res);
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* `Object.create(base)` with RENDER_PASS_FIELDS[purpose]'s own fields. The only
|
|
277
|
+
* place a request context is derived (tools/check-internals.mjs).
|
|
278
|
+
*/
|
|
279
|
+
export function deriveRenderPass<P extends RenderPurpose, TEnv>(
|
|
280
|
+
base: RequestContext<TEnv>,
|
|
281
|
+
purpose: P,
|
|
282
|
+
init: RenderPassInit[P],
|
|
283
|
+
): RequestContext<TEnv> {
|
|
284
|
+
const policy = RENDER_PASS_FIELDS[purpose];
|
|
285
|
+
const pass: RequestContext<TEnv> = Object.create(base);
|
|
286
|
+
if (policy.renderBarrier === "own") {
|
|
287
|
+
wireRenderBarrier(pass, init.handleStore);
|
|
288
|
+
}
|
|
289
|
+
policy.own(pass, init, base);
|
|
290
|
+
return pass;
|
|
291
|
+
}
|
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
|
|
67
67
|
import type { RoutineTrace } from "../rsc/routine-plan.js";
|
|
68
68
|
import type { ActionContinuation } from "../rsc/server-action.js";
|
|
69
|
+
import type { ShellCaptureState } from "../rsc/shell-capture.js";
|
|
69
70
|
import type { FormActionOutcome } from "../rsc/progressive-enhancement.js";
|
|
70
71
|
import { NOCACHE_SYMBOL, assertNotInsideCacheExec } from "../cache/taint.js";
|
|
71
72
|
import {
|
|
@@ -273,8 +274,8 @@ export interface RequestContext<
|
|
|
273
274
|
|
|
274
275
|
/**
|
|
275
276
|
* @internal Handle store for tracking handle data across segments.
|
|
276
|
-
* Readonly: a
|
|
277
|
-
* (
|
|
277
|
+
* Readonly: a render that needs its own store derives a render pass
|
|
278
|
+
* (deriveRenderPass, server/render-pass.ts) instead of swapping this field,
|
|
278
279
|
* which the foreground still reads while it produces the page.
|
|
279
280
|
*/
|
|
280
281
|
readonly _handleStore: HandleStore;
|
|
@@ -334,56 +335,13 @@ export interface RequestContext<
|
|
|
334
335
|
_searchParamsFilter?: import("../cache/search-params-filter.js").SearchParamsFilter;
|
|
335
336
|
|
|
336
337
|
/**
|
|
337
|
-
* @internal PPR shell
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* foreground render never sets it, so the
|
|
343
|
-
* served response is byte-identical to axis 1. The capture descriptor itself
|
|
344
|
-
* (key/ttl/swr/tags/store) is NOT threaded through the request context — the
|
|
345
|
-
* integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
|
|
346
|
-
* locally and passes it to scheduleShellCapture directly.
|
|
338
|
+
* @internal A PPR shell capture's own state (rsc/shell-capture.ts
|
|
339
|
+
* ShellCaptureState): created by RENDER_PASS_FIELDS["shell-capture"]
|
|
340
|
+
* (server/render-pass.ts) on the capture's derived context. The foreground
|
|
341
|
+
* render and every background re-render never have one, so
|
|
342
|
+
* `_shellCaptureState?.run` is the capture switch.
|
|
347
343
|
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* @internal Set beside `_shellCaptureRun` when the shell is keyed by the
|
|
352
|
-
* visitor's URL (`rewrite(...).shell("visitor")`): the capture renders the
|
|
353
|
-
* visitor's location and `ctx.rewrittenFrom`; the theme stays the default.
|
|
354
|
-
*/
|
|
355
|
-
_shellCaptureForVisitor?: boolean;
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @internal Bake-lane loader containers collected DURING a shell capture:
|
|
359
|
-
* segment-key -> the loader's (pre-wrap) result promise. Populated by
|
|
360
|
-
* resolveLoaderData for bake-lane loaders (lane rule: see its JSDoc in
|
|
361
|
-
* loader-cache.ts). Drained by captureAndStoreShell after the shell
|
|
362
|
-
* quiesces: settled containers are promise-elided, Flight-serialized, and
|
|
363
|
-
* pinned into the snapshot's loader family; a REJECTED container refuses
|
|
364
|
-
* the capture (error UI must never bake into the shared shell). Own
|
|
365
|
-
* property of the capture's derived context only.
|
|
366
|
-
*/
|
|
367
|
-
_shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* @internal Set on a capture's derived context when a loader pushed a
|
|
371
|
-
* value the record cannot keep (masked nested promises, a pushed promise
|
|
372
|
-
* that settled to one, a live-lane loader's push, or a push outside a
|
|
373
|
-
* loader body): the loader records then carry `runs: 1`, so a HIT still
|
|
374
|
-
* runs their bodies for those pushes.
|
|
375
|
-
*/
|
|
376
|
-
_shellCaptureUnrecordedLoaderPush?: true;
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* @internal The lane of each loader the capture's matched route registers
|
|
380
|
-
* (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
|
|
381
|
-
* before any loader runs. The capture's push funnel credits a push made
|
|
382
|
-
* under a live-lane loader's body, at any depth, to that loader
|
|
383
|
-
* (shell-capture.ts deriveShellCaptureContext). Own property of the
|
|
384
|
-
* capture's derived context only.
|
|
385
|
-
*/
|
|
386
|
-
_shellCaptureLoaderLanes?: ReadonlyMap<string, "live" | "bake">;
|
|
344
|
+
_shellCaptureState?: ShellCaptureState;
|
|
387
345
|
|
|
388
346
|
/**
|
|
389
347
|
* @internal Record keys resolved for this request (CacheScope
|
|
@@ -403,9 +361,9 @@ export interface RequestContext<
|
|
|
403
361
|
|
|
404
362
|
/**
|
|
405
363
|
* @internal The request carried the forced-MISS reload marker
|
|
406
|
-
* (
|
|
407
|
-
*
|
|
408
|
-
* cache miss.
|
|
364
|
+
* (`WIRE.shellMiss`). The handler strips the marker from the request on
|
|
365
|
+
* entry (shell-serve.ts withoutShellMissMarker) and sets this; the shell
|
|
366
|
+
* gate renders the request like a cache miss.
|
|
409
367
|
*/
|
|
410
368
|
_shellForcedMiss?: true;
|
|
411
369
|
|
|
@@ -425,17 +383,6 @@ export interface RequestContext<
|
|
|
425
383
|
*/
|
|
426
384
|
_runAtRequestEntry?: <T>(fn: () => T) => T;
|
|
427
385
|
|
|
428
|
-
/**
|
|
429
|
-
* @internal The freshness window of the route cache() records this
|
|
430
|
-
* request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
|
|
431
|
-
* timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
|
|
432
|
-
* its scope's swr. The narrowest record wins. A shell capture caps its
|
|
433
|
-
* entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
|
|
434
|
-
* shell is never fresher, or served longer, than the route cache() entry
|
|
435
|
-
* it replayed or wrote.
|
|
436
|
-
*/
|
|
437
|
-
_routeRecordWindow?: RouteRecordWindow;
|
|
438
|
-
|
|
439
386
|
/**
|
|
440
387
|
* @internal Loader-family snapshot seed for a shell HIT's tail render:
|
|
441
388
|
* loader id -> the capture's elided container (already Flight-deserialized
|
|
@@ -563,29 +510,6 @@ export interface RequestContext<
|
|
|
563
510
|
*/
|
|
564
511
|
_shellFragmentPayload?: boolean;
|
|
565
512
|
|
|
566
|
-
/**
|
|
567
|
-
* @internal Set by the capture guard (server/context.ts
|
|
568
|
-
* guardIdentityRead) when it throws DURING a capture render: the read
|
|
569
|
-
* ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
|
|
570
|
-
* "ctx.theme") and the fix the
|
|
571
|
-
* refusal warning gives for it. Load-bearing for the
|
|
572
|
-
* bake lane: a guard throw inside an executing loader is swallowed by
|
|
573
|
-
* wrapLoaderPromise into per-loader error UI, which would otherwise bake
|
|
574
|
-
* silently into the shared shell — the capture checks this flag after the
|
|
575
|
-
* render and refuses instead. Deterministic, so the capture does not retry.
|
|
576
|
-
*/
|
|
577
|
-
_shellCaptureGuardTripped?: { surface: string; fix: string };
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* @internal The loader $$id whose BODY was executing when the capture guard
|
|
581
|
-
* tripped (read off the loader-body ALS scope at trip time), or undefined
|
|
582
|
-
* when the read came from handler/render code. Only used to make the
|
|
583
|
-
* once-per-key refusal warning name the real source — the old text
|
|
584
|
-
* hardcoded "a bake-lane loader", which misattributed handler-land reads
|
|
585
|
-
* and sent users debugging the wrong lane (issue #672, secondary).
|
|
586
|
-
*/
|
|
587
|
-
_shellCaptureGuardTrippedLoaderId?: string;
|
|
588
|
-
|
|
589
513
|
/**
|
|
590
514
|
* @internal Handler-owned registry of explicit per-scope stores from
|
|
591
515
|
* cache({ store }). Created once per createRSCHandler() and threaded into
|
|
@@ -882,8 +806,8 @@ export interface RequestContext<
|
|
|
882
806
|
* (loader(Def, { ssr: false })): segment resolution awaits these
|
|
883
807
|
* before returning, so the render barrier cannot resolve until they settle.
|
|
884
808
|
* rendered() checks this set to fail fast — a flagged loader awaiting the
|
|
885
|
-
* barrier is a guaranteed cycle, not a race. Registered by
|
|
886
|
-
*
|
|
809
|
+
* barrier is a guaranteed cycle, not a race. Registered by resolveOwnerLoaders
|
|
810
|
+
* before loader kickoff; only ever populated on document renders
|
|
887
811
|
* (the flag is stamped per-isSSR at DSL evaluation).
|
|
888
812
|
*/
|
|
889
813
|
_awaitBeforeFlushLoaderIds?: Set<string>;
|
|
@@ -909,6 +833,13 @@ export interface RequestContext<
|
|
|
909
833
|
/** @internal Per-request error dedup set for onError reporting */
|
|
910
834
|
_reportedErrors: WeakSet<object>;
|
|
911
835
|
|
|
836
|
+
/**
|
|
837
|
+
* @internal The segment a parallel slot's or orphan layout's error came
|
|
838
|
+
* from, for the owning entry's catch (segment-resolution/helpers.ts
|
|
839
|
+
* noteThrower). Per request: an error object can be thrown by several.
|
|
840
|
+
*/
|
|
841
|
+
_throwers?: WeakMap<object, { id: string; type: string }>;
|
|
842
|
+
|
|
912
843
|
/**
|
|
913
844
|
* @internal The errors this request printed to the server console, so a
|
|
914
845
|
* failure prints once where it originated (server/print-server-error.ts). A derived context shares it through the prototype.
|
|
@@ -978,6 +909,13 @@ export interface RequestContext<
|
|
|
978
909
|
*/
|
|
979
910
|
_handlerStart?: number;
|
|
980
911
|
|
|
912
|
+
/**
|
|
913
|
+
* @internal Handler-level Server-Timing entries (rsc/handler.ts): the
|
|
914
|
+
* bootstrap timings, then the core handler's classify. A stale document
|
|
915
|
+
* cache entry's re-run has its own (render-pass.ts).
|
|
916
|
+
*/
|
|
917
|
+
_handlerTiming?: string[];
|
|
918
|
+
|
|
981
919
|
/** @internal Resolved platform phase-span tracing for this request (Cloudflare or OTel) */
|
|
982
920
|
_tracing?: ResolvedTracing;
|
|
983
921
|
|
|
@@ -1020,21 +958,6 @@ export interface RequestContext<
|
|
|
1020
958
|
_cacheSignal?: import("../router/telemetry.js").CacheSegmentSignal[];
|
|
1021
959
|
}
|
|
1022
960
|
|
|
1023
|
-
/**
|
|
1024
|
-
* @internal The freshness window of a route cache() record, as ms
|
|
1025
|
-
* timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
|
|
1026
|
-
* `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
|
|
1027
|
-
* the record that sets `staleUntil`: its cache() config, and whether this
|
|
1028
|
-
* request wrote it (cacheRoute) rather than read it.
|
|
1029
|
-
*/
|
|
1030
|
-
export interface RouteRecordWindow {
|
|
1031
|
-
freshUntil: number;
|
|
1032
|
-
staleUntil: number;
|
|
1033
|
-
ttl: number;
|
|
1034
|
-
swr: number;
|
|
1035
|
-
written: boolean;
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
961
|
/**
|
|
1039
962
|
* Public view of RequestContext, without internal methods and fields.
|
|
1040
963
|
*
|
|
@@ -1059,22 +982,15 @@ export type PublicRequestContext<
|
|
|
1059
982
|
| "_prerender"
|
|
1060
983
|
| "_onDemandProducer"
|
|
1061
984
|
| "_searchParamsFilter"
|
|
1062
|
-
| "
|
|
1063
|
-
| "_shellCaptureForVisitor"
|
|
985
|
+
| "_shellCaptureState"
|
|
1064
986
|
| "_shellImplicitCache"
|
|
1065
987
|
| "_shellLoaderSeed"
|
|
1066
|
-
| "_shellCaptureLoaderRecords"
|
|
1067
|
-
| "_shellCaptureUnrecordedLoaderPush"
|
|
1068
|
-
| "_shellCaptureLoaderLanes"
|
|
1069
988
|
| "_resolvedCacheKeys"
|
|
1070
989
|
| "_shellKey"
|
|
1071
990
|
| "_shellForcedMiss"
|
|
1072
991
|
| "_prerenderWarm"
|
|
1073
992
|
| "_runAtRequestEntry"
|
|
1074
|
-
| "_routeRecordWindow"
|
|
1075
993
|
| "_shellFragmentPayload"
|
|
1076
|
-
| "_shellCaptureGuardTripped"
|
|
1077
|
-
| "_shellCaptureGuardTrippedLoaderId"
|
|
1078
994
|
| "_explicitTaggedStores"
|
|
1079
995
|
| "_requestTags"
|
|
1080
996
|
| "_recordTagOwners"
|
|
@@ -1096,6 +1012,7 @@ export type PublicRequestContext<
|
|
|
1096
1012
|
| "_inActionRevalidation"
|
|
1097
1013
|
| "_actionRan"
|
|
1098
1014
|
| "_reportedErrors"
|
|
1015
|
+
| "_throwers"
|
|
1099
1016
|
| "_printedErrors"
|
|
1100
1017
|
| "_renderErrors"
|
|
1101
1018
|
| "_recoveredHandlerErrors"
|
|
@@ -1115,6 +1032,7 @@ export type PublicRequestContext<
|
|
|
1115
1032
|
| "_activeRoutine"
|
|
1116
1033
|
| "_renderDiagnosticsEnabled"
|
|
1117
1034
|
| "_handlerStart"
|
|
1035
|
+
| "_handlerTiming"
|
|
1118
1036
|
| "_tracing"
|
|
1119
1037
|
| "_basename"
|
|
1120
1038
|
| "_routerId"
|
|
@@ -1230,6 +1148,46 @@ export function runWithRequestContext<TEnv, T>(
|
|
|
1230
1148
|
return requestContextStorage.run(context, fn);
|
|
1231
1149
|
}
|
|
1232
1150
|
|
|
1151
|
+
/** Inside background work: the errors its onError reports named. */
|
|
1152
|
+
const backgroundWork = new AsyncLocalStorage<WeakSet<object>>();
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* Run work whose output goes only to a cache, never to the response of the
|
|
1156
|
+
* request that started it, on `context`: a stale entry's refresh (a "use
|
|
1157
|
+
* cache" function, a cached loader, a cache() record, a document), a
|
|
1158
|
+
* navigation's proactive cache() write, a PPR shell capture. No visitor made
|
|
1159
|
+
* the invalidations in it, so they set no fresh-reads cookie
|
|
1160
|
+
* (cache/tag-invalidation.ts), and onError marks every error reported inside
|
|
1161
|
+
* it `background` (router/error-handling.ts invokeOnError). Its failure is
|
|
1162
|
+
* reported inside it too: a catch outside runs on the visitor's frame.
|
|
1163
|
+
*/
|
|
1164
|
+
export function runAsBackgroundWork<TEnv, T>(
|
|
1165
|
+
context: RequestContext<TEnv>,
|
|
1166
|
+
fn: () => T,
|
|
1167
|
+
): T {
|
|
1168
|
+
const reported = backgroundWork.getStore() ?? new WeakSet<object>();
|
|
1169
|
+
return requestContextStorage.run(context, () =>
|
|
1170
|
+
backgroundWork.run(reported, fn),
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/** Whether the caller runs inside runAsBackgroundWork. */
|
|
1175
|
+
export function isBackgroundWork(): boolean {
|
|
1176
|
+
return backgroundWork.getStore() !== undefined;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* The set onError's dedupe records a reported error in. Background work keeps
|
|
1181
|
+
* its own: an error object both the visitor's render and background work
|
|
1182
|
+
* reach (a memoized rejection, a thrown constant) is reported by each, so a
|
|
1183
|
+
* background report never takes the place of the visitor's.
|
|
1184
|
+
*/
|
|
1185
|
+
export function reportedErrorsOf(
|
|
1186
|
+
context: RequestContext<any>,
|
|
1187
|
+
): WeakSet<object> {
|
|
1188
|
+
return backgroundWork.getStore() ?? context._reportedErrors;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1233
1191
|
/**
|
|
1234
1192
|
* Get the current request context
|
|
1235
1193
|
* Throws if called outside of a request context
|
|
@@ -1835,6 +1793,7 @@ export function createRequestContext<TEnv>(
|
|
|
1835
1793
|
_locationState: undefined,
|
|
1836
1794
|
|
|
1837
1795
|
_reportedErrors: new WeakSet<object>(),
|
|
1796
|
+
_throwers: undefined,
|
|
1838
1797
|
_printedErrors: new WeakSet<object>(),
|
|
1839
1798
|
_renderErrors: [],
|
|
1840
1799
|
_metricsStore: undefined,
|
|
@@ -1842,6 +1801,7 @@ export function createRequestContext<TEnv>(
|
|
|
1842
1801
|
_activeRoutine: undefined,
|
|
1843
1802
|
_renderDiagnosticsEnabled: undefined,
|
|
1844
1803
|
_handlerStart: undefined,
|
|
1804
|
+
_handlerTiming: undefined,
|
|
1845
1805
|
|
|
1846
1806
|
_resolveRenderBarrier: null as any,
|
|
1847
1807
|
_renderBarrierSegmentOrder: undefined,
|
|
@@ -1926,8 +1886,8 @@ export function rebaseRequestContext(
|
|
|
1926
1886
|
/**
|
|
1927
1887
|
* Wire a fresh render barrier onto `ctx`, closure-bound to THIS ctx and THIS
|
|
1928
1888
|
* handle store. Called by createRequestContext for every fresh context, and by
|
|
1929
|
-
*
|
|
1930
|
-
*
|
|
1889
|
+
* deriveRenderPass (server/render-pass.ts) for a derived pass whose
|
|
1890
|
+
* RENDER_PASS_FIELDS row owns its barrier (the PPR capture and the HIT tail).
|
|
1931
1891
|
*
|
|
1932
1892
|
* The derived-context call is load-bearing (issue #684, plan 009): the capture
|
|
1933
1893
|
* context is `Object.create(reqCtx)`, so without its own wiring every
|
|
@@ -89,17 +89,19 @@ export function rewriteShellAudience(
|
|
|
89
89
|
|
|
90
90
|
type AudienceContext = Pick<
|
|
91
91
|
RequestContext<any>,
|
|
92
|
-
"
|
|
92
|
+
"_shellCaptureState" | "_documentCacheRender" | "res"
|
|
93
93
|
>;
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* A render other visitors may be served: a PPR shell capture, or a render
|
|
97
97
|
* the document cache stores (its response opted in before next()). It shows
|
|
98
98
|
* no visitor theme, and no visitor URL unless it is a visitor-keyed shell
|
|
99
|
-
* capture (`
|
|
99
|
+
* capture (`_shellCaptureState.forVisitor`).
|
|
100
100
|
*/
|
|
101
101
|
export function rendersForSharedAudience(reqCtx: AudienceContext): boolean {
|
|
102
|
-
return
|
|
102
|
+
return (
|
|
103
|
+
reqCtx._shellCaptureState?.run === true || documentCacheStoresRender(reqCtx)
|
|
104
|
+
);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
/**
|
|
@@ -150,7 +152,7 @@ function readRewrittenFrom(
|
|
|
150
152
|
): string | undefined {
|
|
151
153
|
if (!reqCtx) return undefined;
|
|
152
154
|
if (reader === "render" && rendersForSharedAudience(reqCtx)) {
|
|
153
|
-
if (!reqCtx.
|
|
155
|
+
if (!reqCtx._shellCaptureState?.forVisitor) return undefined;
|
|
154
156
|
// guardIdentityRead minus the capture guard: a cache() boundary, a "use
|
|
155
157
|
// cache" body or a loader's own cache() inside the capture is keyed
|
|
156
158
|
// without the URL.
|
package/src/ssr/index.tsx
CHANGED
|
@@ -442,7 +442,7 @@ const SSR_FALSE_FIRST_FLUSH_TURNS = 3;
|
|
|
442
442
|
|
|
443
443
|
/**
|
|
444
444
|
* True when the matched chain has a `loader(Def, { ssr: false })` entry: its
|
|
445
|
-
* payload segments carry `awaitBeforeFlush` (
|
|
445
|
+
* payload segments carry `awaitBeforeFlush` (resolveOwnerLoaders).
|
|
446
446
|
*/
|
|
447
447
|
function hasAwaitBeforeFlush(payload: {
|
|
448
448
|
metadata?: { segments?: readonly { awaitBeforeFlush?: true }[] };
|