@rangojs/router 0.26.6 → 0.28.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-coordinator.d.ts +0 -4
- package/dist/types/browser/action-fence.d.ts +11 -3
- package/dist/types/browser/event-controller.d.ts +20 -1
- package/dist/types/browser/history-state.d.ts +7 -9
- package/dist/types/browser/intercept-utils.d.ts +23 -0
- package/dist/types/browser/navigation-store.d.ts +8 -6
- package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/segment-reconciler.d.ts +6 -4
- package/dist/types/browser/types.d.ts +2 -1
- package/dist/types/browser/wire-protocol.d.ts +25 -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/tag-invalidation.d.ts +10 -0
- 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 +4 -6
- 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 +4 -4
- 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 +12 -11
- package/dist/types/router/match-handlers.d.ts +2 -6
- package/dist/types/router/match-middleware/background-revalidation.d.ts +10 -20
- package/dist/types/router/match-middleware/cache-lookup.d.ts +35 -87
- package/dist/types/router/match-middleware/cache-store.d.ts +2 -2
- package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
- 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/revalidation.d.ts +6 -1
- package/dist/types/router/router-context.d.ts +9 -63
- package/dist/types/router/router-interfaces.d.ts +8 -14
- 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 +93 -0
- package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
- 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 +10 -0
- 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 +2 -2
- 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 +24 -104
- package/dist/types/server/rewrite-trail.d.ts +2 -2
- package/dist/types/testing/dispatch.d.ts +35 -18
- package/dist/types/testing/serve-shell-request.d.ts +7 -0
- package/dist/types/types/cache-types.d.ts +6 -3
- package/dist/types/types/error-types.d.ts +9 -1
- package/dist/types/types/handler-context.d.ts +18 -7
- 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 +34 -0
- package/dist/vite/index.js +3809 -3710
- 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 +2 -1
- package/skills/document-cache/SKILL.md +18 -1
- package/skills/handler-use/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +53 -13
- package/skills/layout/SKILL.md +11 -7
- package/skills/loader/SKILL.md +30 -13
- package/skills/middleware/SKILL.md +19 -1
- package/skills/migrate-nextjs/SKILL.md +5 -4
- package/skills/parallel/SKILL.md +5 -4
- package/skills/ppr/SKILL.md +19 -3
- package/skills/prerender/SKILL.md +39 -15
- package/skills/rango/SKILL.md +23 -11
- package/skills/server-actions/SKILL.md +51 -6
- package/skills/testing/predicates.md +1 -1
- 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/ux-architecture/SKILL.md +3 -2
- package/src/__internal.ts +7 -1
- package/src/browser/action-coordinator.ts +2 -13
- package/src/browser/action-fence.ts +11 -3
- package/src/browser/connection-warmup.ts +3 -1
- package/src/browser/event-controller.ts +42 -3
- package/src/browser/history-state.ts +15 -13
- package/src/browser/intercept-utils.ts +51 -0
- package/src/browser/navigation-bridge.ts +34 -30
- package/src/browser/navigation-client.ts +21 -33
- package/src/browser/navigation-store.ts +25 -27
- package/src/browser/navigation-transaction.ts +7 -11
- package/src/browser/partial-update.ts +8 -0
- 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/rsc-router.tsx +17 -2
- package/src/browser/segment-reconciler.ts +66 -53
- package/src/browser/server-action-bridge.ts +265 -127
- package/src/browser/types.ts +2 -1
- package/src/browser/wire-protocol.ts +41 -0
- package/src/cache/cache-key-utils.ts +11 -5
- package/src/cache/cache-runtime.ts +110 -50
- 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 +42 -15
- package/src/cache/handle-snapshot.ts +19 -7
- package/src/cache/segment-codec.ts +55 -0
- package/src/cache/shell-snapshot.ts +2 -2
- package/src/cache/tag-invalidation.ts +21 -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 +4 -7
- 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 +4 -4
- package/src/router/instrument.ts +4 -3
- package/src/router/intercept-resolution.ts +77 -75
- package/src/router/loader-resolution.ts +5 -4
- package/src/router/match-api.ts +4 -5
- package/src/router/match-context.ts +33 -12
- package/src/router/match-handlers.ts +8 -20
- package/src/router/match-middleware/background-revalidation.ts +41 -53
- package/src/router/match-middleware/cache-lookup.ts +680 -720
- package/src/router/match-middleware/cache-store.ts +14 -12
- package/src/router/match-middleware/intercept-resolution.ts +3 -23
- package/src/router/match-middleware/segment-resolution.ts +34 -61
- package/src/router/match-result.ts +1 -20
- package/src/router/middleware.ts +69 -11
- package/src/router/navigation-snapshot.ts +4 -3
- 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/revalidation.ts +33 -7
- package/src/router/route-snapshot.ts +2 -5
- package/src/router/router-context.ts +14 -117
- package/src/router/router-interfaces.ts +8 -14
- package/src/router/segment-resolution/loader-cache.ts +14 -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 +137 -0
- package/src/router/segment-resolution/revalidation.ts +897 -776
- 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 +10 -0
- package/src/router.ts +12 -13
- 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 +757 -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 +172 -349
- package/src/rsc/server-action.ts +87 -113
- package/src/rsc/shell-capture-constants.ts +3 -1
- package/src/rsc/shell-capture.ts +212 -169
- 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 +26 -115
- package/src/server/rewrite-trail.ts +6 -4
- package/src/ssr/index.tsx +1 -1
- package/src/ssr/ssr-root.tsx +1 -0
- package/src/testing/dispatch.ts +223 -710
- package/src/testing/e2e/page-helpers.ts +2 -2
- package/src/testing/serve-shell-request.ts +37 -32
- package/src/types/cache-types.ts +6 -3
- package/src/types/error-types.ts +9 -1
- package/src/types/handler-context.ts +21 -7
- 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 +35 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
- package/src/router/segment-resolution/fresh.ts +0 -945
package/src/prerender/store.ts
CHANGED
|
@@ -159,6 +159,82 @@ export function createPrerenderStore(): PrerenderStore | null {
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The segments of a prerendered URL's intercept variant (`/i`): the main
|
|
164
|
+
* variant's without the intercepted route's own (`belongsToRoute`: its
|
|
165
|
+
* handler, layouts and slots), then the intercept's. A render under an
|
|
166
|
+
* intercept skips the route's entry (resolveAllSegments), so the variant
|
|
167
|
+
* holds what a cache() intercept record holds. The producer
|
|
168
|
+
* (matchForPrerender) encodes `interceptHandles` for exactly these segments.
|
|
169
|
+
*/
|
|
170
|
+
export function interceptVariantSegments(
|
|
171
|
+
segments: SerializedSegmentData[],
|
|
172
|
+
interceptSegments: SerializedSegmentData[],
|
|
173
|
+
): SerializedSegmentData[] {
|
|
174
|
+
return [
|
|
175
|
+
...segments.filter((s) => s.metadata.belongsToRoute !== true),
|
|
176
|
+
...interceptSegments,
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The intercept variant as served under the intercept the match selected
|
|
182
|
+
* (findInterceptForRoute): its main segments and that intercept's slot,
|
|
183
|
+
* `slotId` in `intercept:<routeName>`. The build bakes every intercept that
|
|
184
|
+
* can target the route, since it cannot evaluate when(). Null when the
|
|
185
|
+
* variant does not hold that slot: the request renders live. The handles
|
|
186
|
+
* string is kept whole; decodeStoredEntry (cache-lookup.ts) replays only the
|
|
187
|
+
* served segments' pushes.
|
|
188
|
+
*/
|
|
189
|
+
export function selectInterceptVariant(
|
|
190
|
+
entry: PrerenderEntry,
|
|
191
|
+
slotId: string,
|
|
192
|
+
routeName: string,
|
|
193
|
+
): PrerenderEntry | null {
|
|
194
|
+
const namespace = `intercept:${routeName}`;
|
|
195
|
+
let found = false;
|
|
196
|
+
const segments = entry.segments.filter(({ metadata }) => {
|
|
197
|
+
if (!metadata.namespace?.startsWith("intercept:")) return true;
|
|
198
|
+
if (metadata.id !== slotId || metadata.namespace !== namespace) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
found = true;
|
|
202
|
+
return true;
|
|
203
|
+
});
|
|
204
|
+
return found ? { segments, handles: entry.handles } : null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The manifest entries ([key, PrerenderEntry JSON]) one prerendered URL
|
|
209
|
+
* bakes, keyed as the production store's get() reads them. The intercept
|
|
210
|
+
* variant (`/i`) holds interceptVariantSegments with the handle string the
|
|
211
|
+
* producer encoded for it. Written by the build
|
|
212
|
+
* (vite/discovery/prerender-collection.ts) and serveShellRequest.
|
|
213
|
+
*/
|
|
214
|
+
export function prerenderManifestEntries(
|
|
215
|
+
result: PrerenderEntry & {
|
|
216
|
+
routeName: string;
|
|
217
|
+
interceptSegments?: SerializedSegmentData[];
|
|
218
|
+
interceptHandles?: string;
|
|
219
|
+
},
|
|
220
|
+
paramHash: string,
|
|
221
|
+
): Array<[key: string, value: string]> {
|
|
222
|
+
const { segments, handles, interceptSegments } = result;
|
|
223
|
+
const key = `${result.routeName}/${paramHash}`;
|
|
224
|
+
const entries: Array<[string, string]> = [
|
|
225
|
+
[key, JSON.stringify({ segments, handles })],
|
|
226
|
+
];
|
|
227
|
+
if (interceptSegments?.length) {
|
|
228
|
+
const intercept = interceptVariantSegments(segments, interceptSegments);
|
|
229
|
+
const interceptHandles = result.interceptHandles ?? "";
|
|
230
|
+
entries.push([
|
|
231
|
+
`${key}/i`,
|
|
232
|
+
JSON.stringify({ segments: intercept, handles: interceptHandles }),
|
|
233
|
+
]);
|
|
234
|
+
}
|
|
235
|
+
return entries;
|
|
236
|
+
}
|
|
237
|
+
|
|
162
238
|
/**
|
|
163
239
|
* Create a static segment store.
|
|
164
240
|
* Production only: backed by globalThis.__STATIC_MANIFEST injected at build time.
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { HandlerCacheConfig } from "../rsc/types.js";
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
ShellCaptureDebugEvent,
|
|
13
|
+
ShellCaptureState,
|
|
14
|
+
} from "../rsc/shell-capture.js";
|
|
12
15
|
import type { PrerenderWarmCaches } from "./on-demand.js";
|
|
13
16
|
|
|
14
17
|
/** What one warm request did: written by the layers, read by the trigger. */
|
|
@@ -36,7 +39,7 @@ export interface PrerenderWarmRecord extends PrerenderWarmCaches {
|
|
|
36
39
|
/** What the helpers read; a derived capture context inherits the record. */
|
|
37
40
|
export interface WarmContext {
|
|
38
41
|
_prerenderWarm?: PrerenderWarmRecord;
|
|
39
|
-
|
|
42
|
+
_shellCaptureState?: Pick<ShellCaptureState, "run">;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
/**
|
|
@@ -79,14 +82,15 @@ export function readWarmMark(
|
|
|
79
82
|
* "use cache" in-flight dedup lives outside the store, so a wrapper would
|
|
80
83
|
* miss both.
|
|
81
84
|
*
|
|
82
|
-
* False in the warm's own shell capture (`
|
|
85
|
+
* False in the warm's own shell capture (`_shellCaptureState`): it runs after
|
|
83
86
|
* the warm's writes settled and must replay them, or it would render every
|
|
84
87
|
* handler a second time and could bake another generation than the one just
|
|
85
88
|
* written.
|
|
86
89
|
*/
|
|
87
90
|
export function isWarmReplace(ctx: WarmContext | null | undefined): boolean {
|
|
88
91
|
return (
|
|
89
|
-
ctx?._prerenderWarm?.mode === "replace" &&
|
|
92
|
+
ctx?._prerenderWarm?.mode === "replace" &&
|
|
93
|
+
ctx._shellCaptureState?.run !== true
|
|
90
94
|
);
|
|
91
95
|
}
|
|
92
96
|
|
package/src/prerender.ts
CHANGED
|
@@ -490,8 +490,8 @@ export function isPrerenderPassthrough(
|
|
|
490
490
|
* A build handler signals passthrough by returning `ctx.passthrough()` (the
|
|
491
491
|
* PRERENDER_PASSTHROUGH sentinel), which lands on the segment's `component`.
|
|
492
492
|
* But when the route declares `loading()`, the handler result is deferred
|
|
493
|
-
* upstream (
|
|
494
|
-
* to the sentinel rather than the sentinel itself — a synchronous
|
|
493
|
+
* upstream (resolveEntryHandler), so `component` is a thenable
|
|
494
|
+
* resolving to the sentinel rather than the sentinel itself — a synchronous
|
|
495
495
|
* `isPrerenderPassthrough(component)` on the Promise returns false and the build
|
|
496
496
|
* bakes a corrupt artifact instead of deferring. Resolve thenables first.
|
|
497
497
|
*
|
package/src/route-name.ts
CHANGED
|
@@ -63,3 +63,11 @@ export function validateUserRouteName(name: string): void {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The route key's last name segment ("item" for "shop.item"). An intercept
|
|
69
|
+
* that targets it is selected when none targets the full key (match-api.ts).
|
|
70
|
+
*/
|
|
71
|
+
export function localRouteName(routeKey: string): string {
|
|
72
|
+
return routeKey.slice(routeKey.lastIndexOf(".") + 1);
|
|
73
|
+
}
|
|
@@ -111,10 +111,10 @@ export function invokeOnError<TEnv = any>(
|
|
|
111
111
|
/**
|
|
112
112
|
* First non-undefined `pick(orphan)` over the routeless entries in
|
|
113
113
|
* `entry.layout` and, recursively, in theirs: depth-first in render order
|
|
114
|
-
* (resolveOrphanLayout in segment-resolution/
|
|
115
|
-
* entry nested in another renders (a layout() after a
|
|
116
|
-
* layout() in a routeless wrapper); a one-level scan
|
|
117
|
-
* intercepts it declares (#926).
|
|
114
|
+
* (resolveOrphanLayout in segment-resolution/revalidation.ts).
|
|
115
|
+
* Since #922 a routeless entry nested in another renders (a layout() after a
|
|
116
|
+
* bare cache() marker, a layout() in a routeless wrapper); a one-level scan
|
|
117
|
+
* missed the boundaries and intercepts it declares (#926).
|
|
118
118
|
*
|
|
119
119
|
* `skip` is the entry an upward walk came from. Only a bare cache() marker is
|
|
120
120
|
* both in its layout's layout[] and in the chain, and its subtree was already
|
package/src/router/instrument.ts
CHANGED
|
@@ -428,9 +428,10 @@ function observeInSegmentScope<C, R>(
|
|
|
428
428
|
* loop (request.start/end/error, cache.decision, ...).
|
|
429
429
|
* - segment-resolution/helpers.ts emits via a caller-provided report.telemetry
|
|
430
430
|
* sink rather than the ALS router context.
|
|
431
|
-
* - rsc/
|
|
432
|
-
* (request.origin-rejected), and
|
|
433
|
-
* handler.error) emit via
|
|
431
|
+
* - rsc/request-stages.ts timeoutResponse (request.timeout) and
|
|
432
|
+
* originRejectedResponse (request.origin-rejected), and rsc/handler.ts
|
|
433
|
+
* handleStore.onError (late-handle handler.error) emit via
|
|
434
|
+
* router.telemetry directly — they run outside the
|
|
434
435
|
* RouterContext ALS (only match()/matchPartial() enter it), so a
|
|
435
436
|
* getRouterContext() read there throws and the event would vanish.
|
|
436
437
|
*/
|
|
@@ -11,11 +11,7 @@ import type {
|
|
|
11
11
|
InterceptEntry,
|
|
12
12
|
InterceptSelectorContext,
|
|
13
13
|
} from "../server/context";
|
|
14
|
-
import type {
|
|
15
|
-
HandlerContext,
|
|
16
|
-
InternalHandlerContext,
|
|
17
|
-
ResolvedSegment,
|
|
18
|
-
} from "../types";
|
|
14
|
+
import type { InternalHandlerContext, ResolvedSegment } from "../types";
|
|
19
15
|
import {
|
|
20
16
|
handleHandlerResult,
|
|
21
17
|
warnOnStreamedResponse,
|
|
@@ -28,18 +24,15 @@ import {
|
|
|
28
24
|
deliverStartedLoaders,
|
|
29
25
|
resolveOwnerLoaders,
|
|
30
26
|
} from "./segment-resolution/revalidation.js";
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
NOTHING_HELD,
|
|
34
|
-
} from "./segment-resolution/prefetch-deferral.js";
|
|
35
|
-
import type { SegmentResolutionDeps } from "./types.js";
|
|
27
|
+
import { fillSends } from "./segment-resolution/prefetch-deferral.js";
|
|
28
|
+
import type { ResolutionPass } from "./segment-resolution/resolution-pass.js";
|
|
36
29
|
import { getRouterContext } from "./router-context.js";
|
|
37
|
-
import type { RevalidationContext } from "./router-context.js";
|
|
38
30
|
import { runInSegmentTagScope } from "../cache/cache-tag.js";
|
|
39
31
|
import {
|
|
40
32
|
RangoContext,
|
|
41
33
|
latchPprHeaderScopeForEntries,
|
|
42
34
|
} from "../server/context.js";
|
|
35
|
+
import { _getRequestContext } from "../server/request-context.js";
|
|
43
36
|
|
|
44
37
|
/**
|
|
45
38
|
* Header-guard latch for the intercept funnels (issue #713). ppr and
|
|
@@ -171,31 +164,38 @@ export function findInterceptForRoute(
|
|
|
171
164
|
/**
|
|
172
165
|
* An intercept handler's throw or notFound() renders the declaring entry's
|
|
173
166
|
* boundary as the slot component (catchSegmentError, as for route handlers on
|
|
174
|
-
* partial navigations: 500/404 status, onError "handler"). Responses
|
|
175
|
-
*
|
|
176
|
-
* re-render aborts its cache write instead of
|
|
167
|
+
* partial navigations: 500/404 status, onError "handler"). Responses rethrow.
|
|
168
|
+
* The background re-render (`background`) reports the error the same way and
|
|
169
|
+
* then rethrows it, so a failed re-render aborts its cache write instead of
|
|
170
|
+
* storing the fallback.
|
|
177
171
|
*/
|
|
178
172
|
function renderInterceptHandlerError<TEnv>(
|
|
173
|
+
pass: ResolutionPass<TEnv>,
|
|
179
174
|
error: unknown,
|
|
180
175
|
parentEntry: EntryData,
|
|
181
|
-
params: Record<string, string>,
|
|
182
|
-
context: HandlerContext<any, TEnv>,
|
|
183
|
-
deps: SegmentResolutionDeps<TEnv>,
|
|
184
176
|
background: boolean | undefined,
|
|
185
177
|
): ReactNode {
|
|
186
|
-
if (error instanceof Response
|
|
187
|
-
|
|
178
|
+
if (error instanceof Response) throw error;
|
|
179
|
+
// A background re-render's waitUntil task may run outside the router
|
|
180
|
+
// context, as the segment walk's report allows.
|
|
181
|
+
let telemetry;
|
|
182
|
+
try {
|
|
183
|
+
telemetry = getRouterContext()?.telemetry;
|
|
184
|
+
} catch {}
|
|
185
|
+
const { component } = catchSegmentError(
|
|
188
186
|
error,
|
|
189
187
|
parentEntry,
|
|
190
|
-
params,
|
|
191
|
-
deps,
|
|
188
|
+
pass.params,
|
|
189
|
+
pass.deps,
|
|
192
190
|
{
|
|
193
|
-
...buildLoaderErrorContext(context),
|
|
191
|
+
...buildLoaderErrorContext(pass.context),
|
|
194
192
|
isPartial: true,
|
|
195
|
-
telemetry
|
|
193
|
+
telemetry,
|
|
196
194
|
},
|
|
197
|
-
context.pathname,
|
|
198
|
-
)
|
|
195
|
+
pass.context.pathname,
|
|
196
|
+
);
|
|
197
|
+
if (background) throw error;
|
|
198
|
+
return component;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
/** The segment id of `intercept`'s slot on `parentEntry`. */
|
|
@@ -206,6 +206,33 @@ export function interceptSlotId(
|
|
|
206
206
|
return `${parentEntry.shortCode}.${intercept.slotName}`;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* The intercept a match selected (findInterceptForRoute), as its cache()
|
|
211
|
+
* record names it (CacheScope): the slot id, then `~` and its position among
|
|
212
|
+
* the intercepts its entry declares for the same slot and target route. Two
|
|
213
|
+
* such intercepts share the slot id, and the position tells them apart; one
|
|
214
|
+
* for another slot or route does not renumber it. `~` is unreserved in a
|
|
215
|
+
* URL, so a store that maps the key onto one unencoded keeps the whole key.
|
|
216
|
+
* Undefined when the match selected none.
|
|
217
|
+
*/
|
|
218
|
+
export function interceptRecordKey(
|
|
219
|
+
selected: { intercept: InterceptEntry; entry: EntryData } | null,
|
|
220
|
+
): string | undefined {
|
|
221
|
+
if (!selected) return undefined;
|
|
222
|
+
const { intercept, entry } = selected;
|
|
223
|
+
let position = 0;
|
|
224
|
+
for (const other of entry.intercept) {
|
|
225
|
+
if (other === intercept) break;
|
|
226
|
+
if (
|
|
227
|
+
other.slotName === intercept.slotName &&
|
|
228
|
+
other.routeName === intercept.routeName
|
|
229
|
+
) {
|
|
230
|
+
position++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return `${interceptSlotId(entry, intercept)}~${position}`;
|
|
234
|
+
}
|
|
235
|
+
|
|
209
236
|
/**
|
|
210
237
|
* Every segment id an intercept's slot owns, in order: the slot, then one
|
|
211
238
|
* loader segment per loader in declaration order, run or not. A request that
|
|
@@ -228,14 +255,13 @@ export function interceptSegmentIds(
|
|
|
228
255
|
* revalidated on its own, kept in a fill, deferred by a prefetch when flagged.
|
|
229
256
|
*/
|
|
230
257
|
function resolveInterceptLoaders<TEnv>(
|
|
258
|
+
pass: ResolutionPass<TEnv>,
|
|
231
259
|
interceptEntry: InterceptEntry,
|
|
232
260
|
parentEntry: EntryData,
|
|
233
|
-
context: HandlerContext<any, TEnv>,
|
|
234
261
|
belongsToRoute: boolean,
|
|
235
|
-
deps: SegmentResolutionDeps<TEnv>,
|
|
236
|
-
rc: RevalidationContext,
|
|
237
262
|
): Promise<{ segments: ResolvedSegment[] }> {
|
|
238
263
|
return resolveOwnerLoaders(
|
|
264
|
+
pass,
|
|
239
265
|
{
|
|
240
266
|
loaders: interceptEntry.loader,
|
|
241
267
|
namespace: `intercept:${interceptEntry.routeName}`,
|
|
@@ -244,17 +270,7 @@ function resolveInterceptLoaders<TEnv>(
|
|
|
244
270
|
bakeLane: false,
|
|
245
271
|
traceSource: "intercept-loader",
|
|
246
272
|
},
|
|
247
|
-
context,
|
|
248
273
|
belongsToRoute,
|
|
249
|
-
rc.clientSegmentIds,
|
|
250
|
-
rc.prevParams,
|
|
251
|
-
rc.request,
|
|
252
|
-
rc.prevUrl,
|
|
253
|
-
rc.nextUrl,
|
|
254
|
-
rc.routeKey,
|
|
255
|
-
deps,
|
|
256
|
-
rc.actionContext,
|
|
257
|
-
rc.stale,
|
|
258
274
|
);
|
|
259
275
|
}
|
|
260
276
|
|
|
@@ -271,45 +287,37 @@ async function settleLoaderSegments(
|
|
|
271
287
|
}
|
|
272
288
|
|
|
273
289
|
/**
|
|
274
|
-
* Resolve an intercept entry: its slot segment, then its loader segments.
|
|
290
|
+
* Resolve an intercept entry: its slot segment, then its loader segments. The
|
|
291
|
+
* background re-render resolves with a pass that holds nothing
|
|
292
|
+
* (heldNothingPassInput, resolution-pass.ts): every segment renders fresh, and
|
|
293
|
+
* its loaders are skipped (skipLoaders), each registered for the handler's
|
|
294
|
+
* read.
|
|
275
295
|
*/
|
|
276
296
|
export async function resolveInterceptEntry<TEnv>(
|
|
297
|
+
pass: ResolutionPass<TEnv>,
|
|
277
298
|
interceptEntry: InterceptEntry,
|
|
278
299
|
parentEntry: EntryData,
|
|
279
|
-
params: Record<string, string>,
|
|
280
|
-
context: HandlerContext<any, TEnv>,
|
|
281
300
|
belongsToRoute: boolean,
|
|
282
|
-
deps: SegmentResolutionDeps<TEnv>,
|
|
283
|
-
// The background re-render passes none: nothing held, rendered fresh.
|
|
284
|
-
revalidationContext: RevalidationContext = {
|
|
285
|
-
clientSegmentIds: NOTHING_HELD,
|
|
286
|
-
prevParams: {},
|
|
287
|
-
request: context.request,
|
|
288
|
-
prevUrl: context.url,
|
|
289
|
-
nextUrl: context.url,
|
|
290
|
-
routeKey: interceptEntry.routeName,
|
|
291
|
-
},
|
|
292
301
|
options?: {
|
|
293
302
|
/**
|
|
294
303
|
* Set ONLY by the post-response background re-render (stale background
|
|
295
304
|
* revalidation), whose sole purpose is to re-render the segment tree to
|
|
296
|
-
* populate the cache: a handler error
|
|
297
|
-
* error boundary, so a failure is never cached. Never
|
|
298
|
-
* foreground path.
|
|
305
|
+
* populate the cache: a handler error is reported, then rejects instead
|
|
306
|
+
* of rendering the error boundary, so a failure is never cached. Never
|
|
307
|
+
* set on the foreground path.
|
|
299
308
|
*/
|
|
300
309
|
background?: boolean;
|
|
301
310
|
},
|
|
302
311
|
): Promise<ResolvedSegment[]> {
|
|
303
312
|
latchPprHeaderScopeForInterceptTarget(interceptEntry);
|
|
304
313
|
|
|
314
|
+
const { context, params } = pass;
|
|
305
315
|
const slotSegmentId = interceptSlotId(parentEntry, interceptEntry);
|
|
306
316
|
const { segments: loaderSegments } = await resolveInterceptLoaders(
|
|
317
|
+
pass,
|
|
307
318
|
interceptEntry,
|
|
308
319
|
parentEntry,
|
|
309
|
-
context,
|
|
310
320
|
belongsToRoute,
|
|
311
|
-
deps,
|
|
312
|
-
revalidationContext,
|
|
313
321
|
);
|
|
314
322
|
// The slot's tag scope (#957, cache-tag.ts runInSegmentTagScope) and the
|
|
315
323
|
// owner of its handler's handle pushes (a handler's ctx.use(Handle) reads
|
|
@@ -337,10 +345,7 @@ export async function resolveInterceptEntry<TEnv>(
|
|
|
337
345
|
// A fill keeps a slot the client holds: neither its handler nor its layout
|
|
338
346
|
// runs, only the loaders the client lacks (match-result.ts leaves the null
|
|
339
347
|
// slot out of the response).
|
|
340
|
-
if (
|
|
341
|
-
fillSends(context, slotSegmentId, revalidationContext.clientSegmentIds) ===
|
|
342
|
-
false
|
|
343
|
-
) {
|
|
348
|
+
if (fillSends(context, slotSegmentId, pass.client) === false) {
|
|
344
349
|
return [slotSegment(null, undefined), ...loaderSegments];
|
|
345
350
|
}
|
|
346
351
|
|
|
@@ -355,11 +360,9 @@ export async function resolveInterceptEntry<TEnv>(
|
|
|
355
360
|
: handler;
|
|
356
361
|
} catch (error) {
|
|
357
362
|
handlerResult = renderInterceptHandlerError(
|
|
363
|
+
pass,
|
|
358
364
|
error,
|
|
359
365
|
parentEntry,
|
|
360
|
-
params,
|
|
361
|
-
context,
|
|
362
|
-
deps,
|
|
363
366
|
options?.background,
|
|
364
367
|
);
|
|
365
368
|
}
|
|
@@ -392,7 +395,7 @@ export async function resolveInterceptEntry<TEnv>(
|
|
|
392
395
|
// recovered into the declared boundary, except on the background
|
|
393
396
|
// re-render, which must reject so a failure is never cached.
|
|
394
397
|
const streamedComponent = (promise: Promise<unknown>): ReactNode =>
|
|
395
|
-
trackStreamedHandler(deps, promise, {
|
|
398
|
+
trackStreamedHandler(pass.deps, promise, {
|
|
396
399
|
boundaryEntry: parentEntry,
|
|
397
400
|
segmentId: slotSegmentId,
|
|
398
401
|
segmentType: "parallel",
|
|
@@ -423,11 +426,9 @@ export async function resolveInterceptEntry<TEnv>(
|
|
|
423
426
|
component = await handlerResult;
|
|
424
427
|
} catch (error) {
|
|
425
428
|
component = renderInterceptHandlerError(
|
|
429
|
+
pass,
|
|
426
430
|
error,
|
|
427
431
|
parentEntry,
|
|
428
|
-
params,
|
|
429
|
-
context,
|
|
430
|
-
deps,
|
|
431
432
|
options?.background,
|
|
432
433
|
);
|
|
433
434
|
}
|
|
@@ -445,23 +446,24 @@ export async function resolveInterceptEntry<TEnv>(
|
|
|
445
446
|
* keeps its cached component and layout, its loaders are never cached.
|
|
446
447
|
*/
|
|
447
448
|
export async function resolveInterceptLoadersOnly<TEnv>(
|
|
449
|
+
pass: ResolutionPass<TEnv>,
|
|
448
450
|
interceptEntry: InterceptEntry,
|
|
449
451
|
parentEntry: EntryData,
|
|
450
|
-
context: HandlerContext<any, TEnv>,
|
|
451
452
|
belongsToRoute: boolean,
|
|
452
|
-
deps: SegmentResolutionDeps<TEnv>,
|
|
453
|
-
revalidationContext: RevalidationContext,
|
|
454
453
|
): Promise<ResolvedSegment[]> {
|
|
455
454
|
latchPprHeaderScopeForInterceptTarget(interceptEntry);
|
|
455
|
+
const handleStore = _getRequestContext()?._handleStore;
|
|
456
456
|
const { segments } = await resolveInterceptLoaders(
|
|
457
|
+
pass,
|
|
457
458
|
interceptEntry,
|
|
458
459
|
parentEntry,
|
|
459
|
-
context,
|
|
460
460
|
belongsToRoute,
|
|
461
|
-
|
|
462
|
-
|
|
461
|
+
);
|
|
462
|
+
// Where resolveInterceptEntry runs the handler.
|
|
463
|
+
handleStore?.releaseRecordedValues(
|
|
464
|
+
interceptSlotId(parentEntry, interceptEntry),
|
|
463
465
|
);
|
|
464
466
|
if (!interceptEntry.loading) await settleLoaderSegments(segments);
|
|
465
|
-
deliverStartedLoaders(context, segments);
|
|
467
|
+
deliverStartedLoaders(pass.context, segments);
|
|
466
468
|
return segments;
|
|
467
469
|
}
|
|
@@ -341,7 +341,8 @@ export function wrapLoaderWithErrorHandling<T>(
|
|
|
341
341
|
// Render fallback on server. The user ErrorBoundaryHandler may throw
|
|
342
342
|
// synchronously; if it does we must NOT let that rejection escape — the
|
|
343
343
|
// wrapped LoaderDataResult promise is contracted to never reject (see
|
|
344
|
-
//
|
|
344
|
+
// resolveOwnerLoaders `await Promise.all(...)` in
|
|
345
|
+
// segment-resolution/revalidation.ts), and a
|
|
345
346
|
// rejection here would collapse the whole entry and discard healthy
|
|
346
347
|
// sibling loader data. On a fallback-render throw, fall back to the
|
|
347
348
|
// no-boundary result (fallback: null) so the client throws the ORIGINAL
|
|
@@ -585,7 +586,7 @@ function createLoaderExecutor<TEnv>(
|
|
|
585
586
|
const variables = internal._variables;
|
|
586
587
|
|
|
587
588
|
// Capture whether this loader is being started from a DSL loader scope
|
|
588
|
-
// (runInsideLoaderScope in
|
|
589
|
+
// (runInsideLoaderScope in resolveOwnerLoaders). Handler-invoked loaders are NOT
|
|
589
590
|
// inside loader scope. This determines whether rendered() is allowed.
|
|
590
591
|
const isDslLoader = isInsideLoaderScope();
|
|
591
592
|
// The body resolves ctx.reverse(".name") in its DSL declaration's module
|
|
@@ -596,7 +597,7 @@ function createLoaderExecutor<TEnv>(
|
|
|
596
597
|
|
|
597
598
|
// Owning segment for ctx.handle() attribution, captured SYNCHRONOUSLY at
|
|
598
599
|
// kickoff: segment resolution sets _currentSegmentId while resolving the
|
|
599
|
-
// segment that declares this loader (
|
|
600
|
+
// segment that declares this loader (resolveOwnerLoaders), and the value moves on as
|
|
600
601
|
// resolution continues — by the time the async body pushes, it would be
|
|
601
602
|
// stale. Attributing to the owning route/layout segment gives handle
|
|
602
603
|
// pushes the same granularity handler pushes have (segmentOrder-correct
|
|
@@ -844,7 +845,7 @@ function createLoaderExecutor<TEnv>(
|
|
|
844
845
|
// Run the loader body inside loader scope so request-scoped reads
|
|
845
846
|
// (cookies()/headers() and non-cacheable ctx.get) are exempt from the
|
|
846
847
|
// cache-purity guards: loaders always run fresh, so their reads never leak
|
|
847
|
-
// into a cached segment. DSL loaders are already wrapped by
|
|
848
|
+
// into a cached segment. DSL loaders are already wrapped by resolveOwnerLoaders; this
|
|
848
849
|
// also covers handler-invoked loaders (ctx.use(Loader) from a handler),
|
|
849
850
|
// which otherwise execute in the caller's cache scope and would wrongly
|
|
850
851
|
// throw. rendered() gating uses the captured isDslLoader (above), so this
|
package/src/router/match-api.ts
CHANGED
|
@@ -184,8 +184,9 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
184
184
|
// A shell capture credits a push under a live-lane loader's body to that
|
|
185
185
|
// loader (shell-capture.ts deriveShellCaptureContext). The lanes are set
|
|
186
186
|
// before any loader runs: a bake-lane loader can start a later one.
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
const captureState = reqCtx?._shellCaptureState;
|
|
188
|
+
if (captureState?.run) {
|
|
189
|
+
captureState.loaderLanes = routeLoaderLanes(snapshot.entries);
|
|
189
190
|
}
|
|
190
191
|
// A document never defers; the plan feeds the ctx.rendered() guards.
|
|
191
192
|
(handlerContext as InternalHandlerContext<any, TEnv>)._prefetchDeferral =
|
|
@@ -208,7 +209,6 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
208
209
|
routeKey: matched.routeKey,
|
|
209
210
|
localRouteName: snapshot.localRouteName,
|
|
210
211
|
handlerContext,
|
|
211
|
-
loaderPromises,
|
|
212
212
|
routeMap: deps.getRouteMap(),
|
|
213
213
|
metricsStore,
|
|
214
214
|
Store,
|
|
@@ -492,7 +492,7 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
492
492
|
prefetch: kind === "prefetch",
|
|
493
493
|
method: request.method,
|
|
494
494
|
isAction,
|
|
495
|
-
isShellCapture: reqCtx?.
|
|
495
|
+
isShellCapture: reqCtx?._shellCaptureState?.run === true,
|
|
496
496
|
}),
|
|
497
497
|
matched,
|
|
498
498
|
cacheScope,
|
|
@@ -523,7 +523,6 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
523
523
|
routeKey: matched.routeKey,
|
|
524
524
|
localRouteName: snapshot.localRouteName,
|
|
525
525
|
handlerContext,
|
|
526
|
-
loaderPromises,
|
|
527
526
|
routeMap: deps.getRouteMap(),
|
|
528
527
|
metricsStore,
|
|
529
528
|
Store,
|
|
@@ -63,7 +63,6 @@
|
|
|
63
63
|
*
|
|
64
64
|
* Handler Context:
|
|
65
65
|
* - handlerContext: Context passed to loaders
|
|
66
|
-
* - loaderPromises: Memoized loader promises
|
|
67
66
|
*
|
|
68
67
|
* Intercepts:
|
|
69
68
|
* - interceptResult: Detected intercept (if soft navigation)
|
|
@@ -118,16 +117,8 @@ import type {
|
|
|
118
117
|
import type { HandlerContext, ResolvedSegment } from "../types.js";
|
|
119
118
|
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
120
119
|
import type { InterceptResult } from "./router-context.js";
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* Action context passed to matchPartial
|
|
124
|
-
*/
|
|
125
|
-
export interface ActionContext {
|
|
126
|
-
actionId?: string;
|
|
127
|
-
actionUrl?: URL;
|
|
128
|
-
actionResult?: any;
|
|
129
|
-
formData?: FormData;
|
|
130
|
-
}
|
|
120
|
+
import type { ResolutionPassInput } from "./segment-resolution/resolution-pass.js";
|
|
121
|
+
import type { ActionContext } from "./types.js";
|
|
131
122
|
|
|
132
123
|
/**
|
|
133
124
|
* Match context containing all state for the match pipeline
|
|
@@ -160,7 +151,6 @@ export interface MatchContext<TEnv = any> {
|
|
|
160
151
|
|
|
161
152
|
// Handler context (for loaders)
|
|
162
153
|
handlerContext: HandlerContext<any, TEnv>;
|
|
163
|
-
loaderPromises: Map<string, Promise<any>>;
|
|
164
154
|
|
|
165
155
|
// Route map for server-side ctx.reverse() resolution
|
|
166
156
|
routeMap: Record<string, string>;
|
|
@@ -201,6 +191,37 @@ export interface MatchContext<TEnv = any> {
|
|
|
201
191
|
isFullMatch: boolean;
|
|
202
192
|
}
|
|
203
193
|
|
|
194
|
+
/**
|
|
195
|
+
* An action, or a stale partial (`_rsc_stale`: Back/Forward onto an entry
|
|
196
|
+
* marked stale, `refresh()`, the cross-tab refresh, the action follow-up, a
|
|
197
|
+
* zero-segment refetch), renders live: no route-cache or prerender-store read
|
|
198
|
+
* a live handler can replace, and no store. An action's render is never
|
|
199
|
+
* stored, so a record can be older than the copy the client holds after it.
|
|
200
|
+
*/
|
|
201
|
+
export function rendersLive(
|
|
202
|
+
ctx: Pick<MatchContext, "isAction" | "stale">,
|
|
203
|
+
): boolean {
|
|
204
|
+
return ctx.isAction || ctx.stale;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** This match as the input of a revalidating resolution pass (resolution-pass.ts). */
|
|
208
|
+
export function resolutionPassInput<TEnv>(
|
|
209
|
+
ctx: MatchContext<TEnv>,
|
|
210
|
+
): ResolutionPassInput<TEnv> {
|
|
211
|
+
return {
|
|
212
|
+
context: ctx.handlerContext,
|
|
213
|
+
client: ctx.clientSegmentSet,
|
|
214
|
+
params: ctx.matched.params,
|
|
215
|
+
prevParams: ctx.prevParams,
|
|
216
|
+
request: ctx.request,
|
|
217
|
+
prevUrl: ctx.prevUrl,
|
|
218
|
+
nextUrl: ctx.url,
|
|
219
|
+
routeKey: ctx.routeKey,
|
|
220
|
+
actionContext: ctx.actionContext,
|
|
221
|
+
stale: ctx.stale,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
204
225
|
/**
|
|
205
226
|
* Mutable state that flows through the pipeline
|
|
206
227
|
*/
|