@rangojs/router 0.0.0-experimental.124 → 0.0.0-experimental.126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/bin/rango.js +3 -4
- package/dist/vite/index.js +315 -68
- package/package.json +19 -18
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/hooks/SKILL.md +2 -2
- package/skills/route/SKILL.md +6 -0
- package/skills/server-actions/SKILL.md +25 -1
- package/skills/testing/SKILL.md +17 -17
- package/skills/testing/cache-prerender.md +29 -3
- package/skills/testing/flight.md +13 -10
- package/skills/testing/render-handler.md +3 -0
- package/skills/testing/server-tree.md +1 -1
- package/skills/testing/setup.md +1 -1
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +10 -0
- package/src/browser/event-controller.ts +1 -83
- package/src/browser/navigation-store-handle.ts +3 -4
- package/src/browser/navigation-store.ts +0 -39
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/partial-update.ts +23 -84
- package/src/browser/prefetch/cache.ts +6 -45
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +2 -23
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +2 -1
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -45
- package/src/browser/react/location-state-shared.ts +0 -13
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-router.ts +2 -1
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/rsc-router.tsx +10 -3
- package/src/browser/server-action-bridge.ts +51 -3
- package/src/browser/types.ts +23 -5
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/index.ts +8 -9
- package/src/build/route-trie.ts +46 -11
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/router-processing.ts +0 -8
- package/src/cache/cache-policy.ts +0 -54
- package/src/cache/cache-runtime.ts +48 -24
- package/src/cache/cache-scope.ts +0 -27
- package/src/cache/cache-tag.ts +0 -37
- package/src/cache/cf/cf-cache-store.ts +72 -45
- package/src/cache/cf/index.ts +0 -24
- package/src/cache/document-cache.ts +10 -36
- package/src/cache/handle-snapshot.ts +0 -40
- package/src/cache/index.ts +0 -27
- package/src/cache/memory-segment-store.ts +0 -52
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/types.ts +0 -98
- package/src/client.rsc.tsx +4 -22
- package/src/client.tsx +19 -32
- package/src/context-var.ts +12 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/handle.ts +2 -12
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +6 -0
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +0 -16
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +0 -4
- package/src/index.rsc.ts +27 -2
- package/src/index.ts +7 -0
- package/src/internal-debug.ts +2 -4
- package/src/loader.rsc.ts +4 -15
- package/src/loader.ts +3 -9
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +23 -30
- package/src/prerender.ts +34 -0
- package/src/redirect-origin.ts +100 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +1 -44
- package/src/route-definition/dsl-helpers.ts +7 -19
- package/src/route-definition/helpers-types.ts +3 -3
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-map-builder.ts +0 -16
- package/src/router/content-negotiation.ts +0 -13
- package/src/router/error-handling.ts +12 -16
- package/src/router/find-match.ts +4 -31
- package/src/router/intercept-resolution.ts +10 -1
- package/src/router/lazy-includes.ts +1 -57
- package/src/router/loader-resolution.ts +25 -23
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +1 -25
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +0 -43
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +96 -179
- package/src/router/match-middleware/cache-store.ts +0 -31
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +1 -52
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +77 -60
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +5 -56
- package/src/router/prerender-match.ts +56 -51
- package/src/router/request-classification.ts +1 -38
- package/src/router/revalidation.ts +14 -62
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +10 -0
- package/src/router/segment-resolution/fresh.ts +25 -57
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +35 -23
- package/src/router/segment-resolution/revalidation.ts +188 -283
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +0 -22
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +66 -45
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +8 -11
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +20 -4
- package/src/rsc/helpers.ts +71 -3
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/origin-guard.ts +9 -15
- package/src/rsc/progressive-enhancement.ts +10 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-route-handler.ts +23 -18
- package/src/rsc/rsc-rendering.ts +2 -7
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +34 -29
- package/src/rsc/types.ts +6 -3
- package/src/search-params.ts +0 -16
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +79 -88
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +29 -92
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +2 -27
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +1 -24
- package/src/testing/dispatch.ts +43 -6
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/flight-matchers.ts +0 -13
- package/src/testing/flight-normalize.ts +3 -30
- package/src/testing/flight.ts +46 -48
- package/src/testing/generated-routes.ts +1 -41
- package/src/testing/index.ts +1 -21
- package/src/testing/internal/context.ts +3 -45
- package/src/testing/internal/seed-vars.ts +0 -26
- package/src/testing/render-handler.ts +31 -61
- package/src/testing/render-route.tsx +75 -103
- package/src/testing/run-loader.ts +0 -96
- package/src/testing/run-middleware.ts +0 -26
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/error-types.ts +25 -89
- package/src/types/global-namespace.ts +4 -14
- package/src/types/handler-context.ts +28 -9
- package/src/types/index.ts +0 -10
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +0 -13
- package/src/urls/include-helper.ts +0 -4
- package/src/urls/index.ts +0 -6
- package/src/urls/path-helper-types.ts +2 -2
- package/src/urls/path-helper.ts +0 -54
- package/src/urls/urls-function.ts +0 -13
- package/src/use-loader.tsx +0 -186
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/discover-routers.ts +28 -18
- package/src/vite/discovery/prerender-collection.ts +2 -4
- package/src/vite/discovery/state.ts +5 -0
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/plugin-types.ts +35 -9
- package/src/vite/plugins/cjs-to-esm.ts +0 -11
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +0 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +0 -38
- package/src/vite/plugins/expose-ids/handler-transform.ts +0 -15
- package/src/vite/plugins/expose-ids/loader-transform.ts +0 -15
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +10 -0
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/version-injector.ts +0 -20
- package/src/vite/plugins/version-plugin.ts +1 -49
- package/src/vite/plugins/virtual-entries.ts +0 -15
- package/src/vite/rango.ts +2 -108
- package/src/vite/router-discovery.ts +9 -1
- package/src/vite/utils/ast-handler-extract.ts +0 -16
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +0 -4
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -35
- package/src/vite/utils/shared-utils.ts +3 -35
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -242,25 +242,3 @@ export function createPipelineState(): MatchPipelineState {
|
|
|
242
242
|
slots: {},
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Input parameters for createMatchContext
|
|
248
|
-
*/
|
|
249
|
-
export interface CreateMatchContextInput<TEnv = any> {
|
|
250
|
-
request: Request;
|
|
251
|
-
env: TEnv;
|
|
252
|
-
actionContext?: ActionContext;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Result from createMatchContext - either a context or null (fall back to full match)
|
|
257
|
-
*/
|
|
258
|
-
export type CreateMatchContextResult<TEnv = any> =
|
|
259
|
-
| { type: "context"; ctx: MatchContext<TEnv> }
|
|
260
|
-
| { type: "fallback"; reason: string }
|
|
261
|
-
| { type: "error"; error: Error };
|
|
262
|
-
|
|
263
|
-
// Note: createMatchContext() will be implemented in Step J10 when we wire everything together.
|
|
264
|
-
// It requires access to RouterContext (findMatch, loadManifest, etc.) which are closure
|
|
265
|
-
// functions from createRouter(). The implementation will live in router.ts initially
|
|
266
|
-
// and call getRouterContext() to access these dependencies.
|
|
@@ -89,20 +89,6 @@ export interface MatchHandlers<TEnv = any> {
|
|
|
89
89
|
negotiated?: boolean;
|
|
90
90
|
manifestEntry?: EntryData;
|
|
91
91
|
} | null>;
|
|
92
|
-
createMatchContextForFull: (
|
|
93
|
-
request: Request,
|
|
94
|
-
env: TEnv,
|
|
95
|
-
) => Promise<MatchContext<TEnv> | { type: "redirect"; redirectUrl: string }>;
|
|
96
|
-
createMatchContextForPartial: (
|
|
97
|
-
request: Request,
|
|
98
|
-
env: TEnv,
|
|
99
|
-
actionContext?: {
|
|
100
|
-
actionId?: string;
|
|
101
|
-
actionUrl?: URL;
|
|
102
|
-
actionResult?: any;
|
|
103
|
-
formData?: FormData;
|
|
104
|
-
},
|
|
105
|
-
) => Promise<MatchContext<TEnv> | null>;
|
|
106
92
|
}
|
|
107
93
|
|
|
108
94
|
/**
|
|
@@ -123,9 +109,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
123
109
|
const hasTelemetry = !!deps.telemetry;
|
|
124
110
|
const telemetry = resolveSink(deps.telemetry);
|
|
125
111
|
const cacheSignalEnabled = !!deps.cacheSignalEnabled;
|
|
126
|
-
// Compute the coarse cache signal when EITHER telemetry needs it (for the
|
|
127
|
-
// cache.decision event) OR the debug header gate is on. When neither is set,
|
|
128
|
-
// this is never called — zero extra work on the hot path.
|
|
129
112
|
const buildSignal = (
|
|
130
113
|
routeKey: string,
|
|
131
114
|
state: {
|
|
@@ -134,8 +117,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
134
117
|
shouldRevalidate?: boolean;
|
|
135
118
|
},
|
|
136
119
|
): CacheSegmentSignal[] => buildCacheSignalSegments(routeKey, state);
|
|
137
|
-
// Stash the signal on the request context for the response path to emit as
|
|
138
|
-
// the X-Rango-Cache header. Only when the debug gate is on.
|
|
139
120
|
const recordSignalIfEnabled = (segments: CacheSegmentSignal[]): void => {
|
|
140
121
|
if (!cacheSignalEnabled) return;
|
|
141
122
|
const reqCtx = _getRequestContext();
|
|
@@ -173,15 +154,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
173
154
|
);
|
|
174
155
|
}
|
|
175
156
|
|
|
176
|
-
/**
|
|
177
|
-
* Match request and return segments (document/SSR requests)
|
|
178
|
-
*
|
|
179
|
-
* Uses generator middleware pipeline for clean separation of concerns:
|
|
180
|
-
* - cache-lookup: Check cache first
|
|
181
|
-
* - segment-resolution: Resolve segments on cache miss
|
|
182
|
-
* - cache-store: Store results in cache
|
|
183
|
-
* - background-revalidation: SWR revalidation
|
|
184
|
-
*/
|
|
185
157
|
async function match(request: Request, env: TEnv): Promise<MatchResult> {
|
|
186
158
|
const requestId = hasTelemetry ? getRequestId(request) : undefined;
|
|
187
159
|
return runWithRouterLogContext({ request, transaction: "match" }, () => {
|
|
@@ -205,7 +177,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
205
177
|
|
|
206
178
|
const result = await createMatchContextForFull(request, env);
|
|
207
179
|
|
|
208
|
-
// Handle redirect case
|
|
209
180
|
if ("type" in result && result.type === "redirect") {
|
|
210
181
|
if (hasTelemetry) {
|
|
211
182
|
safeEmit(telemetry, {
|
|
@@ -284,7 +255,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
284
255
|
});
|
|
285
256
|
}
|
|
286
257
|
if (error instanceof Response) throw error;
|
|
287
|
-
// Report unhandled errors during full match pipeline
|
|
288
258
|
callOnError(error, "routing", {
|
|
289
259
|
request,
|
|
290
260
|
url: ctx.url,
|
|
@@ -319,16 +289,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
319
289
|
);
|
|
320
290
|
}
|
|
321
291
|
|
|
322
|
-
/**
|
|
323
|
-
* Match partial request with revalidation
|
|
324
|
-
*
|
|
325
|
-
* Uses generator middleware pipeline for clean separation of concerns:
|
|
326
|
-
* - cache-lookup: Check cache first
|
|
327
|
-
* - segment-resolution: Resolve segments on cache miss
|
|
328
|
-
* - intercept-resolution: Handle intercept routes
|
|
329
|
-
* - cache-store: Store results in cache
|
|
330
|
-
* - background-revalidation: SWR revalidation
|
|
331
|
-
*/
|
|
332
292
|
async function matchPartial(
|
|
333
293
|
request: Request,
|
|
334
294
|
context: TEnv,
|
|
@@ -448,7 +408,6 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
448
408
|
});
|
|
449
409
|
}
|
|
450
410
|
if (error instanceof Response) throw error;
|
|
451
|
-
// Report unhandled errors during partial match pipeline
|
|
452
411
|
callOnError(error, actionContext ? "action" : "revalidation", {
|
|
453
412
|
request,
|
|
454
413
|
url: ctx.url,
|
|
@@ -477,7 +436,5 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
477
436
|
matchPartial: matchPartial,
|
|
478
437
|
matchError: matchError,
|
|
479
438
|
previewMatch: previewMatch,
|
|
480
|
-
createMatchContextForFull: createMatchContextForFull,
|
|
481
|
-
createMatchContextForPartial: createMatchContextForPartial,
|
|
482
439
|
};
|
|
483
440
|
}
|
|
@@ -168,8 +168,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
168
168
|
requestCtx._handleStore = createHandleStore();
|
|
169
169
|
|
|
170
170
|
try {
|
|
171
|
-
// Create fresh handler context and loader promises to avoid
|
|
172
|
-
// reusing memoized results from the foreground pass
|
|
173
171
|
const freshHandlerContext = createHandlerContext(
|
|
174
172
|
ctx.matched.params,
|
|
175
173
|
ctx.request,
|
|
@@ -185,10 +183,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
185
183
|
const freshLoaderPromises = new Map<string, Promise<any>>();
|
|
186
184
|
setupLoaderAccess(freshHandlerContext, freshLoaderPromises);
|
|
187
185
|
|
|
188
|
-
// Resolve all segments fresh (without revalidation logic)
|
|
189
|
-
// to ensure complete components for caching.
|
|
190
|
-
// Skip DSL loaders — they are never cached (cacheRoute filters them)
|
|
191
|
-
// and are always resolved fresh on each request.
|
|
192
186
|
const freshSegments = await ctx.Store.run(() =>
|
|
193
187
|
resolveAllSegments(
|
|
194
188
|
ctx.entries,
|
|
@@ -200,7 +194,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
200
194
|
),
|
|
201
195
|
);
|
|
202
196
|
|
|
203
|
-
// Also resolve intercept segments fresh if applicable
|
|
204
197
|
let freshInterceptSegments: ResolvedSegment[] = [];
|
|
205
198
|
if (ctx.interceptResult) {
|
|
206
199
|
freshInterceptSegments = await ctx.Store.run(() =>
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
*/
|
|
94
94
|
import type { ResolvedSegment } from "../../types.js";
|
|
95
95
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
96
|
-
import { getRouterContext } from "../router-context.js";
|
|
96
|
+
import { getRouterContext, type RouterContext } from "../router-context.js";
|
|
97
97
|
import { resolveSink, safeEmit } from "../telemetry.js";
|
|
98
98
|
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
99
99
|
import { treeHasStreaming } from "./segment-resolution.js";
|
|
@@ -103,6 +103,7 @@ import {
|
|
|
103
103
|
getRequestContext,
|
|
104
104
|
_getRequestContext,
|
|
105
105
|
} from "../../server/request-context.js";
|
|
106
|
+
import { paramsEqual } from "../params-util.js";
|
|
106
107
|
|
|
107
108
|
// Lazily initialized prerender store singleton and dynamically imported deps.
|
|
108
109
|
// Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
|
|
@@ -124,22 +125,6 @@ let _lazyGetRequestContext:
|
|
|
124
125
|
| typeof import("../../server/request-context.js").getRequestContext
|
|
125
126
|
| undefined;
|
|
126
127
|
|
|
127
|
-
function paramsEqual(
|
|
128
|
-
a: Record<string, string>,
|
|
129
|
-
b: Record<string, string>,
|
|
130
|
-
): boolean {
|
|
131
|
-
if (a === b) return true;
|
|
132
|
-
|
|
133
|
-
const keysA = Object.keys(a);
|
|
134
|
-
if (keysA.length !== Object.keys(b).length) return false;
|
|
135
|
-
|
|
136
|
-
for (const key of keysA) {
|
|
137
|
-
if (a[key] !== b[key]) return false;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
128
|
async function ensurePrerenderDeps() {
|
|
144
129
|
if (!_deserializeSegments) {
|
|
145
130
|
const [codec, snapshot, paramHash, reqCtx, store] = await Promise.all([
|
|
@@ -165,6 +150,81 @@ async function ensurePrerenderDeps() {
|
|
|
165
150
|
* Deserializes segments, replays handle data, yields segments with partial
|
|
166
151
|
* navigation nullification, and resolves fresh loaders.
|
|
167
152
|
*/
|
|
153
|
+
// Resolve loaders fresh on a cache hit (loaders are NEVER cached) and yield
|
|
154
|
+
// the loader segments, updating state.matchedIds and pushing the loader-resolve
|
|
155
|
+
// + cache-hit metrics. Shared verbatim by the prerender-store path
|
|
156
|
+
// (yieldFromStore) and the runtime cache-hit path (withCacheLookup). The router
|
|
157
|
+
// resolve fns are passed in (captured early by the callers) rather than re-read
|
|
158
|
+
// from getRouterContext() here, because that is ALS-backed and the callers run
|
|
159
|
+
// awaits before reaching this point (workerd can disrupt ALS mid-pipeline).
|
|
160
|
+
async function* resolveFreshLoadersAndYield<TEnv>(
|
|
161
|
+
ctx: MatchContext<TEnv>,
|
|
162
|
+
state: MatchPipelineState,
|
|
163
|
+
pipelineStart: number,
|
|
164
|
+
ms: MatchContext<TEnv>["metricsStore"],
|
|
165
|
+
resolveLoadersOnly: RouterContext<TEnv>["resolveLoadersOnly"],
|
|
166
|
+
resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
|
|
167
|
+
): AsyncGenerator<ResolvedSegment> {
|
|
168
|
+
const loaderStart = performance.now();
|
|
169
|
+
|
|
170
|
+
if (ctx.isFullMatch) {
|
|
171
|
+
if (resolveLoadersOnly) {
|
|
172
|
+
const loaderSegments = await ctx.Store.run(() =>
|
|
173
|
+
resolveLoadersOnly(ctx.entries, ctx.handlerContext),
|
|
174
|
+
);
|
|
175
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
176
|
+
for (const segment of loaderSegments) {
|
|
177
|
+
yield segment;
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
if (resolveLoadersOnlyWithRevalidation) {
|
|
184
|
+
const loaderResult = await ctx.Store.run(() =>
|
|
185
|
+
resolveLoadersOnlyWithRevalidation(
|
|
186
|
+
ctx.entries,
|
|
187
|
+
ctx.handlerContext,
|
|
188
|
+
ctx.clientSegmentSet,
|
|
189
|
+
ctx.prevParams,
|
|
190
|
+
ctx.request,
|
|
191
|
+
ctx.prevUrl,
|
|
192
|
+
ctx.url,
|
|
193
|
+
ctx.routeKey,
|
|
194
|
+
ctx.actionContext,
|
|
195
|
+
// Loaders are never cached in the segment cache, so segment staleness
|
|
196
|
+
// must not propagate; browser-sent staleness (ctx.stale) still must.
|
|
197
|
+
ctx.stale || undefined,
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
state.matchedIds = [
|
|
201
|
+
...state.cachedMatchedIds!,
|
|
202
|
+
...loaderResult.matchedIds,
|
|
203
|
+
];
|
|
204
|
+
for (const segment of loaderResult.segments) {
|
|
205
|
+
yield segment;
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (ms) {
|
|
213
|
+
const loaderEnd = performance.now();
|
|
214
|
+
ms.metrics.push({
|
|
215
|
+
label: "pipeline:loader-resolve",
|
|
216
|
+
duration: loaderEnd - loaderStart,
|
|
217
|
+
startTime: loaderStart - ms.requestStart,
|
|
218
|
+
depth: 1,
|
|
219
|
+
});
|
|
220
|
+
ms.metrics.push({
|
|
221
|
+
label: "pipeline:cache-hit",
|
|
222
|
+
duration: loaderEnd - pipelineStart,
|
|
223
|
+
startTime: pipelineStart - ms.requestStart,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
168
228
|
async function* yieldFromStore<TEnv>(
|
|
169
229
|
entry: PrerenderEntry,
|
|
170
230
|
ctx: MatchContext<TEnv>,
|
|
@@ -231,64 +291,15 @@ async function* yieldFromStore<TEnv>(
|
|
|
231
291
|
yield segment;
|
|
232
292
|
}
|
|
233
293
|
|
|
234
|
-
// Resolve loaders fresh (loaders are never pre-rendered/cached)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
244
|
-
for (const segment of loaderSegments) {
|
|
245
|
-
yield segment;
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
249
|
-
}
|
|
250
|
-
} else {
|
|
251
|
-
if (resolveLoadersOnlyWithRevalidation) {
|
|
252
|
-
const loaderResult = await ctx.Store.run(() =>
|
|
253
|
-
resolveLoadersOnlyWithRevalidation(
|
|
254
|
-
ctx.entries,
|
|
255
|
-
ctx.handlerContext,
|
|
256
|
-
ctx.clientSegmentSet,
|
|
257
|
-
ctx.prevParams,
|
|
258
|
-
ctx.request,
|
|
259
|
-
ctx.prevUrl,
|
|
260
|
-
ctx.url,
|
|
261
|
-
ctx.routeKey,
|
|
262
|
-
ctx.actionContext,
|
|
263
|
-
ctx.stale || undefined,
|
|
264
|
-
),
|
|
265
|
-
);
|
|
266
|
-
state.matchedIds = [
|
|
267
|
-
...state.cachedMatchedIds!,
|
|
268
|
-
...loaderResult.matchedIds,
|
|
269
|
-
];
|
|
270
|
-
for (const segment of loaderResult.segments) {
|
|
271
|
-
yield segment;
|
|
272
|
-
}
|
|
273
|
-
} else {
|
|
274
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (ms) {
|
|
279
|
-
const loaderEnd = performance.now();
|
|
280
|
-
ms.metrics.push({
|
|
281
|
-
label: "pipeline:loader-resolve",
|
|
282
|
-
duration: loaderEnd - loaderStart,
|
|
283
|
-
startTime: loaderStart - ms.requestStart,
|
|
284
|
-
depth: 1,
|
|
285
|
-
});
|
|
286
|
-
ms.metrics.push({
|
|
287
|
-
label: "pipeline:cache-hit",
|
|
288
|
-
duration: loaderEnd - pipelineStart,
|
|
289
|
-
startTime: pipelineStart - ms.requestStart,
|
|
290
|
-
});
|
|
291
|
-
}
|
|
294
|
+
// Resolve loaders fresh (loaders are never pre-rendered/cached).
|
|
295
|
+
yield* resolveFreshLoadersAndYield(
|
|
296
|
+
ctx,
|
|
297
|
+
state,
|
|
298
|
+
pipelineStart,
|
|
299
|
+
ctx.metricsStore,
|
|
300
|
+
resolveLoadersOnly,
|
|
301
|
+
resolveLoadersOnlyWithRevalidation,
|
|
302
|
+
);
|
|
292
303
|
}
|
|
293
304
|
|
|
294
305
|
/**
|
|
@@ -367,10 +378,6 @@ export function withCacheLookup<TEnv>(
|
|
|
367
378
|
resolveLoadersOnly,
|
|
368
379
|
} = getRouterContext<TEnv>();
|
|
369
380
|
|
|
370
|
-
// Prerender lookup: check build-time cached data before runtime cache.
|
|
371
|
-
// Prerender data is available regardless of runtime cache configuration.
|
|
372
|
-
// Skip for HMR requests — the dev prerender endpoint reads from a stale
|
|
373
|
-
// RouterRegistry snapshot; rendering fresh ensures edits are visible.
|
|
374
381
|
const isHmr = !!ctx.request.headers.get("X-RSC-HMR");
|
|
375
382
|
if (!ctx.isAction && !isHmr && ctx.matched.pr) {
|
|
376
383
|
await ensurePrerenderDeps();
|
|
@@ -385,14 +392,6 @@ export function withCacheLookup<TEnv>(
|
|
|
385
392
|
}
|
|
386
393
|
}
|
|
387
394
|
|
|
388
|
-
// Dev-mode static handler interception for non-Node.js runtimes.
|
|
389
|
-
// __PRERENDER_DEV_URL is set by the Vite plugin when the RSC environment
|
|
390
|
-
// lacks a Node.js module runner (e.g. workerd, Deno workers). In those
|
|
391
|
-
// runtimes, handlers that depend on Node APIs like node:fs can't run
|
|
392
|
-
// in-process. We redirect them to the /__rsc_prerender endpoint which
|
|
393
|
-
// resolves segments in a Node.js temp server, same as prerender routes.
|
|
394
|
-
// In Node.js dev mode this variable is undefined -- handlers run
|
|
395
|
-
// in-process where Node APIs work, so no interception is needed.
|
|
396
395
|
if (!ctx.isAction && !ctx.matched.pr && globalThis.__PRERENDER_DEV_URL) {
|
|
397
396
|
const hasStatic = ctx.entries.some(
|
|
398
397
|
(e) =>
|
|
@@ -415,9 +414,7 @@ export function withCacheLookup<TEnv>(
|
|
|
415
414
|
}
|
|
416
415
|
}
|
|
417
416
|
|
|
418
|
-
// Skip cache during actions
|
|
419
417
|
if (ctx.isAction || !ctx.cacheScope?.enabled) {
|
|
420
|
-
// Cache miss - pass through to segment resolution
|
|
421
418
|
yield* source;
|
|
422
419
|
if (ms) {
|
|
423
420
|
ms.metrics.push({
|
|
@@ -429,7 +426,6 @@ export function withCacheLookup<TEnv>(
|
|
|
429
426
|
return;
|
|
430
427
|
}
|
|
431
428
|
|
|
432
|
-
// Lookup cache
|
|
433
429
|
const cacheResult = await ctx.cacheScope.lookupRoute(
|
|
434
430
|
ctx.pathname,
|
|
435
431
|
ctx.matched.params,
|
|
@@ -437,7 +433,6 @@ export function withCacheLookup<TEnv>(
|
|
|
437
433
|
);
|
|
438
434
|
|
|
439
435
|
if (!cacheResult) {
|
|
440
|
-
// Cache miss - pass through to segment resolution
|
|
441
436
|
yield* source;
|
|
442
437
|
if (ms) {
|
|
443
438
|
ms.metrics.push({
|
|
@@ -449,16 +444,12 @@ export function withCacheLookup<TEnv>(
|
|
|
449
444
|
return;
|
|
450
445
|
}
|
|
451
446
|
|
|
452
|
-
// Cache HIT
|
|
453
447
|
state.cacheHit = true;
|
|
454
448
|
state.cacheSource = "runtime";
|
|
455
449
|
state.shouldRevalidate = cacheResult.shouldRevalidate;
|
|
456
450
|
state.cachedSegments = cacheResult.segments;
|
|
457
451
|
state.cachedMatchedIds = cacheResult.segments.map((s) => s.id);
|
|
458
452
|
|
|
459
|
-
// Apply revalidation to cached segments.
|
|
460
|
-
// For full matches or empty client segment sets, this map is unnecessary:
|
|
461
|
-
// we never run segment-level revalidation and can stream segments directly.
|
|
462
453
|
const canCheckSegmentRevalidation =
|
|
463
454
|
!ctx.isFullMatch &&
|
|
464
455
|
ctx.clientSegmentSet.size > 0 &&
|
|
@@ -468,7 +459,6 @@ export function withCacheLookup<TEnv>(
|
|
|
468
459
|
: undefined;
|
|
469
460
|
|
|
470
461
|
for (const segment of cacheResult.segments) {
|
|
471
|
-
// Skip segments client doesn't have - they need their component
|
|
472
462
|
if (!ctx.clientSegmentSet.has(segment.id)) {
|
|
473
463
|
if (isTraceActive()) {
|
|
474
464
|
pushRevalidationTraceEntry({
|
|
@@ -485,19 +475,13 @@ export function withCacheLookup<TEnv>(
|
|
|
485
475
|
continue;
|
|
486
476
|
}
|
|
487
477
|
|
|
488
|
-
// Skip intercept segments - they're handled separately
|
|
489
478
|
if (segment.namespace?.startsWith("intercept:")) {
|
|
490
479
|
yield segment;
|
|
491
480
|
continue;
|
|
492
481
|
}
|
|
493
482
|
|
|
494
|
-
// Look up revalidation rules for this segment
|
|
495
483
|
const entryInfo = entryRevalidateMap?.get(segment.id);
|
|
496
484
|
|
|
497
|
-
// Even without explicit revalidation rules, route segments and their
|
|
498
|
-
// children must re-render when params or search params change — the
|
|
499
|
-
// handler reads ctx.params/ctx.searchParams so different values produce
|
|
500
|
-
// different content. Matches evaluateRevalidation's default logic.
|
|
501
485
|
const searchChanged = ctx.prevUrl.search !== ctx.url.search;
|
|
502
486
|
const routeParamsChanged = !paramsEqual(
|
|
503
487
|
ctx.matched.params,
|
|
@@ -511,7 +495,6 @@ export function withCacheLookup<TEnv>(
|
|
|
511
495
|
|
|
512
496
|
if (!entryInfo || entryInfo.revalidate.length === 0) {
|
|
513
497
|
if (shouldDefaultRevalidate) {
|
|
514
|
-
// Params or search params changed — must re-render even without custom rules
|
|
515
498
|
if (isTraceActive()) {
|
|
516
499
|
pushRevalidationTraceEntry({
|
|
517
500
|
segmentId: segment.id,
|
|
@@ -528,7 +511,6 @@ export function withCacheLookup<TEnv>(
|
|
|
528
511
|
yield segment;
|
|
529
512
|
continue;
|
|
530
513
|
}
|
|
531
|
-
// No revalidation rules, use default behavior (skip if client has)
|
|
532
514
|
if (isTraceActive()) {
|
|
533
515
|
pushRevalidationTraceEntry({
|
|
534
516
|
segmentId: segment.id,
|
|
@@ -546,7 +528,6 @@ export function withCacheLookup<TEnv>(
|
|
|
546
528
|
continue;
|
|
547
529
|
}
|
|
548
530
|
|
|
549
|
-
// Evaluate revalidation rules
|
|
550
531
|
const shouldRevalidate = await evaluateRevalidation({
|
|
551
532
|
segment,
|
|
552
533
|
prevParams: ctx.prevParams,
|
|
@@ -580,7 +561,6 @@ export function withCacheLookup<TEnv>(
|
|
|
580
561
|
}
|
|
581
562
|
|
|
582
563
|
if (!shouldRevalidate) {
|
|
583
|
-
// Client has it, no revalidation needed
|
|
584
564
|
segment.component = null;
|
|
585
565
|
segment.loading = undefined;
|
|
586
566
|
}
|
|
@@ -588,7 +568,6 @@ export function withCacheLookup<TEnv>(
|
|
|
588
568
|
yield segment;
|
|
589
569
|
}
|
|
590
570
|
|
|
591
|
-
// Set streaming flag (once) and resolve render barrier.
|
|
592
571
|
const barrierReqCtx = _getRequestContext();
|
|
593
572
|
if (barrierReqCtx) {
|
|
594
573
|
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
@@ -597,77 +576,15 @@ export function withCacheLookup<TEnv>(
|
|
|
597
576
|
barrierReqCtx._resolveRenderBarrier(cacheResult.segments);
|
|
598
577
|
}
|
|
599
578
|
|
|
600
|
-
// Resolve loaders fresh (loaders are
|
|
601
|
-
//
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
);
|
|
611
|
-
|
|
612
|
-
// Update state - full match doesn't track matchedIds separately
|
|
613
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
614
|
-
|
|
615
|
-
// Yield fresh loader segments
|
|
616
|
-
for (const segment of loaderSegments) {
|
|
617
|
-
yield segment;
|
|
618
|
-
}
|
|
619
|
-
} else {
|
|
620
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
621
|
-
}
|
|
622
|
-
} else {
|
|
623
|
-
// Partial match (navigation) - loader resolution with revalidation
|
|
624
|
-
if (resolveLoadersOnlyWithRevalidation) {
|
|
625
|
-
const loaderResult = await Store.run(() =>
|
|
626
|
-
resolveLoadersOnlyWithRevalidation(
|
|
627
|
-
ctx.entries,
|
|
628
|
-
ctx.handlerContext,
|
|
629
|
-
ctx.clientSegmentSet,
|
|
630
|
-
ctx.prevParams,
|
|
631
|
-
ctx.request,
|
|
632
|
-
ctx.prevUrl,
|
|
633
|
-
ctx.url,
|
|
634
|
-
ctx.routeKey,
|
|
635
|
-
ctx.actionContext,
|
|
636
|
-
// Loaders are never cached in the segment cache, so segment
|
|
637
|
-
// staleness (cacheResult.shouldRevalidate) must not propagate.
|
|
638
|
-
// But browser-sent staleness (ctx.stale) — indicating an action
|
|
639
|
-
// happened in this or another tab — must still reach loaders.
|
|
640
|
-
ctx.stale || undefined,
|
|
641
|
-
),
|
|
642
|
-
);
|
|
643
|
-
|
|
644
|
-
// Update state with fresh loader matchedIds
|
|
645
|
-
state.matchedIds = [
|
|
646
|
-
...state.cachedMatchedIds!,
|
|
647
|
-
...loaderResult.matchedIds,
|
|
648
|
-
];
|
|
649
|
-
|
|
650
|
-
// Yield fresh loader segments
|
|
651
|
-
for (const segment of loaderResult.segments) {
|
|
652
|
-
yield segment;
|
|
653
|
-
}
|
|
654
|
-
} else {
|
|
655
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
if (ms) {
|
|
659
|
-
const loaderEnd = performance.now();
|
|
660
|
-
ms.metrics.push({
|
|
661
|
-
label: "pipeline:loader-resolve",
|
|
662
|
-
duration: loaderEnd - loaderStart,
|
|
663
|
-
startTime: loaderStart - ms.requestStart,
|
|
664
|
-
depth: 1,
|
|
665
|
-
});
|
|
666
|
-
ms.metrics.push({
|
|
667
|
-
label: "pipeline:cache-hit",
|
|
668
|
-
duration: loaderEnd - pipelineStart,
|
|
669
|
-
startTime: pipelineStart - ms.requestStart,
|
|
670
|
-
});
|
|
671
|
-
}
|
|
579
|
+
// Resolve loaders fresh (loaders are never cached). Shared with the
|
|
580
|
+
// prerender-store path via resolveFreshLoadersAndYield.
|
|
581
|
+
yield* resolveFreshLoadersAndYield(
|
|
582
|
+
ctx,
|
|
583
|
+
state,
|
|
584
|
+
pipelineStart,
|
|
585
|
+
ms,
|
|
586
|
+
resolveLoadersOnly,
|
|
587
|
+
resolveLoadersOnlyWithRevalidation,
|
|
588
|
+
);
|
|
672
589
|
};
|
|
673
590
|
}
|
|
@@ -123,21 +123,14 @@ export function withCacheStore<TEnv>(
|
|
|
123
123
|
): AsyncGenerator<ResolvedSegment> {
|
|
124
124
|
const ms = ctx.metricsStore;
|
|
125
125
|
|
|
126
|
-
// Collect all segments while passing them through
|
|
127
126
|
const allSegments: ResolvedSegment[] = [];
|
|
128
127
|
for await (const segment of source) {
|
|
129
128
|
allSegments.push(segment);
|
|
130
129
|
yield segment;
|
|
131
130
|
}
|
|
132
131
|
|
|
133
|
-
// Measure own work only (after source iteration completes)
|
|
134
132
|
const ownStart = performance.now();
|
|
135
133
|
|
|
136
|
-
// Skip caching if:
|
|
137
|
-
// 1. Cache miss but cache scope is disabled
|
|
138
|
-
// 2. This is an action (actions don't cache)
|
|
139
|
-
// 3. Cache was already hit (no need to re-cache)
|
|
140
|
-
// 4. Non-GET request (only cache GET requests)
|
|
141
134
|
if (
|
|
142
135
|
!ctx.cacheScope?.enabled ||
|
|
143
136
|
ctx.isAction ||
|
|
@@ -162,13 +155,8 @@ export function withCacheStore<TEnv>(
|
|
|
162
155
|
createHandleStore,
|
|
163
156
|
} = getRouterContext<TEnv>();
|
|
164
157
|
|
|
165
|
-
// Combine main segments with intercept segments
|
|
166
158
|
const allSegmentsToCache = [...allSegments, ...state.interceptSegments];
|
|
167
159
|
|
|
168
|
-
// Check if any non-loader segments have null components from revalidation
|
|
169
|
-
// skip (client already had them). Segments where the handler intentionally
|
|
170
|
-
// returned null are not revalidation skips — re-rendering them will still
|
|
171
|
-
// produce null, so proactive caching would be wasted work.
|
|
172
160
|
const hasNullComponents = allSegmentsToCache.some(
|
|
173
161
|
(s) =>
|
|
174
162
|
s.component === null &&
|
|
@@ -184,10 +172,7 @@ export function withCacheStore<TEnv>(
|
|
|
184
172
|
? getOrCreateRequestId(ctx.request)
|
|
185
173
|
: undefined;
|
|
186
174
|
|
|
187
|
-
// Register onResponse callback to skip caching for non-200 responses
|
|
188
|
-
// Note: error/notFound status codes are set elsewhere (not caching-specific)
|
|
189
175
|
requestCtx.onResponse((response) => {
|
|
190
|
-
// Only cache successful responses
|
|
191
176
|
if (response.status !== 200) {
|
|
192
177
|
debugLog("cacheStore", "skipping cache for non-200 response", {
|
|
193
178
|
status: response.status,
|
|
@@ -197,10 +182,7 @@ export function withCacheStore<TEnv>(
|
|
|
197
182
|
}
|
|
198
183
|
|
|
199
184
|
if (hasNullComponents) {
|
|
200
|
-
// Proactive caching: render all segments fresh in background
|
|
201
|
-
// This ensures cache has complete components for future requests
|
|
202
185
|
requestCtx.waitUntil(async () => {
|
|
203
|
-
// Prevent background metrics from polluting foreground timeline.
|
|
204
186
|
const savedMetrics = ctx.Store.metrics;
|
|
205
187
|
ctx.Store.metrics = undefined;
|
|
206
188
|
|
|
@@ -208,15 +190,9 @@ export function withCacheStore<TEnv>(
|
|
|
208
190
|
debugLog("cacheStore", "proactive caching started", {
|
|
209
191
|
pathname: ctx.pathname,
|
|
210
192
|
});
|
|
211
|
-
// Swap to a fresh HandleStore so handle.push() calls from
|
|
212
|
-
// proactive resolution are captured (not silenced). The original
|
|
213
|
-
// store's stream is already sent by waitUntil time.
|
|
214
|
-
// cacheRoute reads from requestCtx._handleStore, so this ensures
|
|
215
|
-
// complete handle data (e.g. breadcrumbs) is cached.
|
|
216
193
|
const originalHandleStore = requestCtx._handleStore;
|
|
217
194
|
requestCtx._handleStore = createHandleStore();
|
|
218
195
|
try {
|
|
219
|
-
// Create fresh context for proactive caching
|
|
220
196
|
const proactiveHandlerContext = createHandlerContext(
|
|
221
197
|
ctx.matched.params,
|
|
222
198
|
ctx.request,
|
|
@@ -231,12 +207,8 @@ export function withCacheStore<TEnv>(
|
|
|
231
207
|
);
|
|
232
208
|
const proactiveLoaderPromises = new Map<string, Promise<any>>();
|
|
233
209
|
|
|
234
|
-
// Use normal loader access so handle data is captured
|
|
235
210
|
setupLoaderAccess(proactiveHandlerContext, proactiveLoaderPromises);
|
|
236
211
|
|
|
237
|
-
// Re-resolve ALL segments without revalidation.
|
|
238
|
-
// Skip DSL loaders — they are never cached (cacheRoute filters them)
|
|
239
|
-
// and are always resolved fresh on each request.
|
|
240
212
|
const Store = ctx.Store;
|
|
241
213
|
const freshSegments = await Store.run(() =>
|
|
242
214
|
resolveAllSegments(
|
|
@@ -249,7 +221,6 @@ export function withCacheStore<TEnv>(
|
|
|
249
221
|
),
|
|
250
222
|
);
|
|
251
223
|
|
|
252
|
-
// Also resolve intercept segments fresh if applicable
|
|
253
224
|
let freshInterceptSegments: ResolvedSegment[] = [];
|
|
254
225
|
if (ctx.interceptResult) {
|
|
255
226
|
freshInterceptSegments = await Store.run(() =>
|
|
@@ -301,8 +272,6 @@ export function withCacheStore<TEnv>(
|
|
|
301
272
|
}
|
|
302
273
|
});
|
|
303
274
|
} else {
|
|
304
|
-
// All segments have components - cache directly
|
|
305
|
-
// Schedule caching in waitUntil since cacheRoute is now async (key resolution)
|
|
306
275
|
if (INTERNAL_RANGO_DEBUG) {
|
|
307
276
|
console.log(
|
|
308
277
|
`[RSC CacheStore][req:${reqId}] Direct cache path: scheduling cacheRoute for ${ctx.pathname} (${allSegmentsToCache.length} segments, hasNullComponents=${hasNullComponents})`,
|