@rangojs/router 0.0.0-experimental.9 → 0.0.0-experimental.a5f27bd5
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/AGENTS.md +5 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1531 -155
- package/dist/vite/index.js +4440 -2170
- package/package.json +60 -54
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +50 -21
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +6 -4
- package/skills/hooks/SKILL.md +333 -71
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +74 -15
- package/skills/loader/SKILL.md +388 -38
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +15 -11
- package/skills/parallel/SKILL.md +78 -1
- package/skills/prerender/SKILL.md +405 -45
- package/skills/rango/SKILL.md +85 -21
- package/skills/response-routes/SKILL.md +144 -91
- package/skills/route/SKILL.md +226 -14
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +316 -87
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +87 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +285 -553
- package/src/browser/navigation-client.ts +123 -73
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +261 -309
- package/src/browser/prefetch/cache.ts +154 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +182 -70
- package/src/browser/react/NavigationProvider.tsx +51 -11
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +29 -70
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +106 -27
- package/src/browser/scroll-restoration.ts +92 -16
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +504 -599
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +107 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +82 -21
- package/src/build/generate-route-types.ts +36 -752
- package/src/build/index.ts +6 -5
- package/src/build/route-trie.ts +39 -13
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +469 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +120 -301
- package/src/cache/cf/cf-cache-store.ts +119 -7
- package/src/cache/cf/index.ts +8 -2
- package/src/cache/document-cache.ts +101 -72
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +0 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +84 -126
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +17 -7
- package/src/errors.ts +77 -7
- package/src/handle.ts +15 -10
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +65 -45
- package/src/index.rsc.ts +133 -21
- package/src/index.ts +164 -52
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +25 -143
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +158 -13
- package/src/prerender.ts +333 -26
- package/src/reverse.ts +184 -121
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -1431
- package/src/route-map-builder.ts +156 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +48 -9
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +158 -0
- package/src/router/handler-context.ts +374 -81
- package/src/router/intercept-resolution.ts +24 -16
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +215 -122
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +83 -32
- package/src/router/match-api.ts +118 -119
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +80 -93
- package/src/router/match-middleware/cache-lookup.ts +336 -84
- package/src/router/match-middleware/cache-store.ts +43 -24
- package/src/router/match-middleware/intercept-resolution.ts +45 -20
- package/src/router/match-middleware/segment-resolution.ts +16 -8
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +34 -28
- package/src/router/metrics.ts +235 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +324 -367
- package/src/router/pattern-matching.ts +197 -41
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/router-context.ts +36 -21
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1239 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1315
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +96 -29
- package/src/router/types.ts +16 -9
- package/src/router.ts +590 -1983
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +661 -1015
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +38 -11
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +25 -13
- package/src/server/context.ts +173 -48
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +430 -70
- package/src/server.ts +35 -155
- package/src/ssr/index.tsx +100 -31
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +102 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -1757
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -1282
- package/src/use-loader.tsx +85 -77
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -1963
- package/src/vite/plugin-types.ts +131 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +254 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +510 -0
- package/src/vite/router-discovery.ts +785 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/router.gen.ts +0 -6
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- package/src/vite/expose-prerender-handler-id.ts +0 -429
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -92,38 +92,178 @@
|
|
|
92
92
|
import type { ResolvedSegment } from "../../types.js";
|
|
93
93
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
94
94
|
import { getRouterContext } from "../router-context.js";
|
|
95
|
-
import
|
|
95
|
+
import { resolveSink, safeEmit } from "../telemetry.js";
|
|
96
|
+
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
97
|
+
import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
|
|
98
|
+
import type { HandleStore } from "../../server/handle-store.js";
|
|
99
|
+
import {
|
|
100
|
+
getRequestContext,
|
|
101
|
+
_getRequestContext,
|
|
102
|
+
} from "../../server/request-context.js";
|
|
96
103
|
|
|
97
104
|
// Lazily initialized prerender store singleton and dynamically imported deps.
|
|
98
105
|
// Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
|
|
99
106
|
// top-level, which breaks vitest (only URLs with file:, data:, node: schemes).
|
|
100
107
|
let prerenderStoreInstance: PrerenderStore | null | undefined;
|
|
101
|
-
let _deserializeSegments:
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
let _deserializeSegments:
|
|
109
|
+
| typeof import("../../cache/segment-codec.js").deserializeSegments
|
|
110
|
+
| undefined;
|
|
111
|
+
let _restoreHandles:
|
|
112
|
+
| typeof import("../../cache/handle-snapshot.js").restoreHandles
|
|
113
|
+
| undefined;
|
|
114
|
+
let _hashParams:
|
|
115
|
+
| typeof import("../../prerender/param-hash.js").hashParams
|
|
116
|
+
| undefined;
|
|
117
|
+
let _lazyGetRequestContext:
|
|
118
|
+
| typeof import("../../server/request-context.js").getRequestContext
|
|
119
|
+
| undefined;
|
|
120
|
+
|
|
121
|
+
function paramsEqual(
|
|
122
|
+
a: Record<string, string>,
|
|
123
|
+
b: Record<string, string>,
|
|
124
|
+
): boolean {
|
|
125
|
+
if (a === b) return true;
|
|
126
|
+
|
|
127
|
+
const keysA = Object.keys(a);
|
|
128
|
+
if (keysA.length !== Object.keys(b).length) return false;
|
|
129
|
+
|
|
130
|
+
for (const key of keysA) {
|
|
131
|
+
if (a[key] !== b[key]) return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
104
136
|
|
|
105
137
|
async function ensurePrerenderDeps() {
|
|
106
138
|
if (!_deserializeSegments) {
|
|
107
|
-
const [
|
|
108
|
-
import("../../cache/
|
|
139
|
+
const [codec, snapshot, paramHash, reqCtx, store] = await Promise.all([
|
|
140
|
+
import("../../cache/segment-codec.js"),
|
|
141
|
+
import("../../cache/handle-snapshot.js"),
|
|
109
142
|
import("../../prerender/param-hash.js"),
|
|
110
143
|
import("../../server/request-context.js"),
|
|
111
144
|
import("../../prerender/store.js"),
|
|
112
145
|
]);
|
|
113
|
-
_deserializeSegments =
|
|
146
|
+
_deserializeSegments = codec.deserializeSegments;
|
|
147
|
+
_restoreHandles = snapshot.restoreHandles;
|
|
114
148
|
_hashParams = paramHash.hashParams;
|
|
115
|
-
|
|
149
|
+
_lazyGetRequestContext = reqCtx.getRequestContext;
|
|
116
150
|
if (prerenderStoreInstance === undefined) {
|
|
117
151
|
prerenderStoreInstance = store.createPrerenderStore();
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
154
|
}
|
|
121
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Shared yield logic for prerender and static handler store entries.
|
|
158
|
+
* Deserializes segments, replays handle data, yields segments with partial
|
|
159
|
+
* navigation nullification, and resolves fresh loaders.
|
|
160
|
+
*/
|
|
161
|
+
async function* yieldFromStore<TEnv>(
|
|
162
|
+
entry: PrerenderEntry,
|
|
163
|
+
ctx: MatchContext<TEnv>,
|
|
164
|
+
state: MatchPipelineState,
|
|
165
|
+
pipelineStart: number,
|
|
166
|
+
handleStoreRef?: HandleStore,
|
|
167
|
+
): AsyncGenerator<ResolvedSegment> {
|
|
168
|
+
const { resolveLoadersOnlyWithRevalidation, resolveLoadersOnly } =
|
|
169
|
+
getRouterContext<TEnv>();
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
!_deserializeSegments ||
|
|
173
|
+
!_restoreHandles ||
|
|
174
|
+
!_hashParams ||
|
|
175
|
+
!_lazyGetRequestContext
|
|
176
|
+
) {
|
|
177
|
+
throw new Error("yieldFromStore called before ensurePrerenderDeps");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const segments = await _deserializeSegments(entry.segments);
|
|
181
|
+
|
|
182
|
+
// Replay handle data (same as runtime cache hit path).
|
|
183
|
+
// Prefer the eagerly-captured handleStoreRef to avoid ALS disruption in workerd.
|
|
184
|
+
const handleStore = handleStoreRef ?? _lazyGetRequestContext()?._handleStore;
|
|
185
|
+
if (handleStore) {
|
|
186
|
+
_restoreHandles(entry.handles, handleStore);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
state.cacheHit = true;
|
|
190
|
+
state.cacheSource = "prerender";
|
|
191
|
+
state.cachedSegments = segments;
|
|
192
|
+
state.cachedMatchedIds = segments.map((s) => s.id);
|
|
193
|
+
|
|
194
|
+
// For partial navigation, nullify components the client already has
|
|
195
|
+
// so parent layouts stay live (client keeps its existing versions).
|
|
196
|
+
// When params changed (e.g., different guide slug), the segments have
|
|
197
|
+
// different content, so we must NOT nullify.
|
|
198
|
+
const paramsChanged =
|
|
199
|
+
!ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
200
|
+
for (const segment of segments) {
|
|
201
|
+
if (
|
|
202
|
+
!ctx.isFullMatch &&
|
|
203
|
+
!paramsChanged &&
|
|
204
|
+
ctx.clientSegmentSet.has(segment.id)
|
|
205
|
+
) {
|
|
206
|
+
segment.component = null;
|
|
207
|
+
segment.loading = undefined;
|
|
208
|
+
}
|
|
209
|
+
yield segment;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Resolve loaders fresh (loaders are never pre-rendered/cached)
|
|
213
|
+
if (ctx.isFullMatch) {
|
|
214
|
+
if (resolveLoadersOnly) {
|
|
215
|
+
const loaderSegments = await ctx.Store.run(() =>
|
|
216
|
+
resolveLoadersOnly(ctx.entries, ctx.handlerContext),
|
|
217
|
+
);
|
|
218
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
219
|
+
for (const segment of loaderSegments) {
|
|
220
|
+
yield segment;
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
if (resolveLoadersOnlyWithRevalidation) {
|
|
227
|
+
const loaderResult = await ctx.Store.run(() =>
|
|
228
|
+
resolveLoadersOnlyWithRevalidation(
|
|
229
|
+
ctx.entries,
|
|
230
|
+
ctx.handlerContext,
|
|
231
|
+
ctx.clientSegmentSet,
|
|
232
|
+
ctx.prevParams,
|
|
233
|
+
ctx.request,
|
|
234
|
+
ctx.prevUrl,
|
|
235
|
+
ctx.url,
|
|
236
|
+
ctx.routeKey,
|
|
237
|
+
ctx.actionContext,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
state.matchedIds = [
|
|
241
|
+
...state.cachedMatchedIds!,
|
|
242
|
+
...loaderResult.matchedIds,
|
|
243
|
+
];
|
|
244
|
+
for (const segment of loaderResult.segments) {
|
|
245
|
+
yield segment;
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
state.matchedIds = state.cachedMatchedIds!;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const ms = ctx.metricsStore;
|
|
253
|
+
if (ms) {
|
|
254
|
+
ms.metrics.push({
|
|
255
|
+
label: "pipeline:cache-lookup",
|
|
256
|
+
duration: performance.now() - pipelineStart,
|
|
257
|
+
startTime: pipelineStart - ms.requestStart,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
122
262
|
/**
|
|
123
263
|
* Async generator middleware type
|
|
124
264
|
*/
|
|
125
265
|
export type GeneratorMiddleware<T> = (
|
|
126
|
-
source: AsyncGenerator<T
|
|
266
|
+
source: AsyncGenerator<T>,
|
|
127
267
|
) => AsyncGenerator<T>;
|
|
128
268
|
|
|
129
269
|
/**
|
|
@@ -141,14 +281,21 @@ export type GeneratorMiddleware<T> = (
|
|
|
141
281
|
*/
|
|
142
282
|
export function withCacheLookup<TEnv>(
|
|
143
283
|
ctx: MatchContext<TEnv>,
|
|
144
|
-
state: MatchPipelineState
|
|
284
|
+
state: MatchPipelineState,
|
|
145
285
|
): GeneratorMiddleware<ResolvedSegment> {
|
|
146
286
|
return async function* (
|
|
147
|
-
source: AsyncGenerator<ResolvedSegment
|
|
287
|
+
source: AsyncGenerator<ResolvedSegment>,
|
|
148
288
|
): AsyncGenerator<ResolvedSegment> {
|
|
149
289
|
const pipelineStart = performance.now();
|
|
150
290
|
const ms = ctx.metricsStore;
|
|
151
291
|
|
|
292
|
+
// Eagerly capture the HandleStore before any async operations.
|
|
293
|
+
// In workerd/Cloudflare, dynamic imports and fetch() inside the pipeline
|
|
294
|
+
// can disrupt AsyncLocalStorage, causing getRequestContext() to return
|
|
295
|
+
// undefined afterward. Capturing the reference early ensures handle replay
|
|
296
|
+
// and handler handle-push work regardless of ALS state.
|
|
297
|
+
const handleStoreRef = _getRequestContext()?._handleStore;
|
|
298
|
+
|
|
152
299
|
const {
|
|
153
300
|
evaluateRevalidation,
|
|
154
301
|
buildEntryRevalidateMap,
|
|
@@ -162,79 +309,124 @@ export function withCacheLookup<TEnv>(
|
|
|
162
309
|
await ensurePrerenderDeps();
|
|
163
310
|
if (prerenderStoreInstance) {
|
|
164
311
|
const paramHash = _hashParams!(ctx.matched.params);
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const handleStore = _getRequestContext!()?._handleStore;
|
|
171
|
-
if (handleStore) {
|
|
172
|
-
for (const [segId, segHandles] of Object.entries(entry.handles)) {
|
|
173
|
-
if (Object.keys(segHandles).length > 0) {
|
|
174
|
-
handleStore.replaySegmentData(segId, segHandles);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
312
|
+
const isPassthroughPrerenderRoute = ctx.entries.some(
|
|
313
|
+
(entry) =>
|
|
314
|
+
entry.type === "route" &&
|
|
315
|
+
entry.prerenderDef?.options?.passthrough === true,
|
|
316
|
+
);
|
|
178
317
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
318
|
+
if (ctx.isIntercept) {
|
|
319
|
+
// Intercept navigation: try intercept-specific prerender entry
|
|
320
|
+
const entry = await prerenderStoreInstance.get(
|
|
321
|
+
ctx.matched.routeKey,
|
|
322
|
+
paramHash + "/i",
|
|
323
|
+
{
|
|
324
|
+
pathname: ctx.pathname,
|
|
325
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
326
|
+
},
|
|
327
|
+
);
|
|
328
|
+
if (entry) {
|
|
329
|
+
yield* yieldFromStore(
|
|
330
|
+
entry,
|
|
331
|
+
ctx,
|
|
332
|
+
state,
|
|
333
|
+
pipelineStart,
|
|
334
|
+
handleStoreRef,
|
|
335
|
+
);
|
|
336
|
+
return;
|
|
192
337
|
}
|
|
338
|
+
// No intercept prerender -- fall through to normal pipeline
|
|
339
|
+
// (skip non-intercept prerender to let intercept-resolution run)
|
|
340
|
+
} else {
|
|
341
|
+
// Normal navigation: existing behavior
|
|
342
|
+
const entry = await prerenderStoreInstance.get(
|
|
343
|
+
ctx.matched.routeKey,
|
|
344
|
+
paramHash,
|
|
345
|
+
{
|
|
346
|
+
pathname: ctx.pathname,
|
|
347
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
348
|
+
},
|
|
349
|
+
);
|
|
350
|
+
if (entry) {
|
|
351
|
+
yield* yieldFromStore(
|
|
352
|
+
entry,
|
|
353
|
+
ctx,
|
|
354
|
+
state,
|
|
355
|
+
pipelineStart,
|
|
356
|
+
handleStoreRef,
|
|
357
|
+
);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Dev-mode static handler interception for non-Node.js runtimes.
|
|
365
|
+
// __PRERENDER_DEV_URL is set by the Vite plugin when the RSC environment
|
|
366
|
+
// lacks a Node.js module runner (e.g. workerd, Deno workers). In those
|
|
367
|
+
// runtimes, handlers that depend on Node APIs like node:fs can't run
|
|
368
|
+
// in-process. We redirect them to the /__rsc_prerender endpoint which
|
|
369
|
+
// resolves segments in a Node.js temp server, same as prerender routes.
|
|
370
|
+
// In Node.js dev mode this variable is undefined -- handlers run
|
|
371
|
+
// in-process where Node APIs work, so no interception is needed.
|
|
372
|
+
if (!ctx.isAction && !ctx.matched.pr && globalThis.__PRERENDER_DEV_URL) {
|
|
373
|
+
const hasStatic = ctx.entries.some(
|
|
374
|
+
(e) =>
|
|
375
|
+
(e.type === "layout" ||
|
|
376
|
+
e.type === "route" ||
|
|
377
|
+
e.type === "parallel") &&
|
|
378
|
+
e.isStaticPrerender,
|
|
379
|
+
);
|
|
380
|
+
if (hasStatic) {
|
|
381
|
+
await ensurePrerenderDeps();
|
|
382
|
+
if (prerenderStoreInstance) {
|
|
383
|
+
const paramHash = _hashParams!(ctx.matched.params);
|
|
384
|
+
const isPassthroughPrerenderRoute = ctx.entries.some(
|
|
385
|
+
(entry) =>
|
|
386
|
+
entry.type === "route" &&
|
|
387
|
+
entry.prerenderDef?.options?.passthrough === true,
|
|
388
|
+
);
|
|
193
389
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
390
|
+
if (ctx.isIntercept) {
|
|
391
|
+
const entry = await prerenderStoreInstance.get(
|
|
392
|
+
ctx.matched.routeKey,
|
|
393
|
+
paramHash + "/i",
|
|
394
|
+
{
|
|
395
|
+
pathname: ctx.pathname,
|
|
396
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
397
|
+
},
|
|
398
|
+
);
|
|
399
|
+
if (entry) {
|
|
400
|
+
yield* yieldFromStore(
|
|
401
|
+
entry,
|
|
402
|
+
ctx,
|
|
403
|
+
state,
|
|
404
|
+
pipelineStart,
|
|
405
|
+
handleStoreRef,
|
|
199
406
|
);
|
|
200
|
-
|
|
201
|
-
for (const segment of loaderSegments) {
|
|
202
|
-
yield segment;
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
407
|
+
return;
|
|
206
408
|
}
|
|
409
|
+
// No intercept prerender -- fall through to normal pipeline
|
|
207
410
|
} else {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
411
|
+
const entry = await prerenderStoreInstance.get(
|
|
412
|
+
ctx.matched.routeKey,
|
|
413
|
+
paramHash,
|
|
414
|
+
{
|
|
415
|
+
pathname: ctx.pathname,
|
|
416
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
417
|
+
},
|
|
418
|
+
);
|
|
419
|
+
if (entry) {
|
|
420
|
+
yield* yieldFromStore(
|
|
421
|
+
entry,
|
|
422
|
+
ctx,
|
|
423
|
+
state,
|
|
424
|
+
pipelineStart,
|
|
425
|
+
handleStoreRef,
|
|
221
426
|
);
|
|
222
|
-
|
|
223
|
-
...state.cachedMatchedIds!,
|
|
224
|
-
...loaderResult.matchedIds,
|
|
225
|
-
];
|
|
226
|
-
for (const segment of loaderResult.segments) {
|
|
227
|
-
yield segment;
|
|
228
|
-
}
|
|
229
|
-
} else {
|
|
230
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
427
|
+
return;
|
|
231
428
|
}
|
|
232
429
|
}
|
|
233
|
-
|
|
234
|
-
if (ms) {
|
|
235
|
-
ms.metrics.push({ label: "pipeline:cache-lookup", duration: performance.now() - pipelineStart, startTime: pipelineStart - ms.requestStart });
|
|
236
|
-
}
|
|
237
|
-
return;
|
|
238
430
|
}
|
|
239
431
|
}
|
|
240
432
|
}
|
|
@@ -244,7 +436,11 @@ export function withCacheLookup<TEnv>(
|
|
|
244
436
|
// Cache miss - pass through to segment resolution
|
|
245
437
|
yield* source;
|
|
246
438
|
if (ms) {
|
|
247
|
-
ms.metrics.push({
|
|
439
|
+
ms.metrics.push({
|
|
440
|
+
label: "pipeline:cache-lookup",
|
|
441
|
+
duration: performance.now() - pipelineStart,
|
|
442
|
+
startTime: pipelineStart - ms.requestStart,
|
|
443
|
+
});
|
|
248
444
|
}
|
|
249
445
|
return;
|
|
250
446
|
}
|
|
@@ -253,30 +449,54 @@ export function withCacheLookup<TEnv>(
|
|
|
253
449
|
const cacheResult = await ctx.cacheScope.lookupRoute(
|
|
254
450
|
ctx.pathname,
|
|
255
451
|
ctx.matched.params,
|
|
256
|
-
ctx.isIntercept
|
|
452
|
+
ctx.isIntercept,
|
|
257
453
|
);
|
|
258
454
|
|
|
259
455
|
if (!cacheResult) {
|
|
260
456
|
// Cache miss - pass through to segment resolution
|
|
261
457
|
yield* source;
|
|
262
458
|
if (ms) {
|
|
263
|
-
ms.metrics.push({
|
|
459
|
+
ms.metrics.push({
|
|
460
|
+
label: "pipeline:cache-lookup",
|
|
461
|
+
duration: performance.now() - pipelineStart,
|
|
462
|
+
startTime: pipelineStart - ms.requestStart,
|
|
463
|
+
});
|
|
264
464
|
}
|
|
265
465
|
return;
|
|
266
466
|
}
|
|
267
467
|
|
|
268
468
|
// Cache HIT
|
|
269
469
|
state.cacheHit = true;
|
|
470
|
+
state.cacheSource = "runtime";
|
|
270
471
|
state.shouldRevalidate = cacheResult.shouldRevalidate;
|
|
271
472
|
state.cachedSegments = cacheResult.segments;
|
|
272
473
|
state.cachedMatchedIds = cacheResult.segments.map((s) => s.id);
|
|
273
474
|
|
|
274
|
-
// Apply revalidation to cached segments
|
|
275
|
-
|
|
475
|
+
// Apply revalidation to cached segments.
|
|
476
|
+
// For full matches or empty client segment sets, this map is unnecessary:
|
|
477
|
+
// we never run segment-level revalidation and can stream segments directly.
|
|
478
|
+
const canCheckSegmentRevalidation =
|
|
479
|
+
!ctx.isFullMatch &&
|
|
480
|
+
ctx.clientSegmentSet.size > 0 &&
|
|
481
|
+
!!buildEntryRevalidateMap;
|
|
482
|
+
const entryRevalidateMap = canCheckSegmentRevalidation
|
|
483
|
+
? buildEntryRevalidateMap(ctx.entries)
|
|
484
|
+
: undefined;
|
|
276
485
|
|
|
277
486
|
for (const segment of cacheResult.segments) {
|
|
278
487
|
// Skip segments client doesn't have - they need their component
|
|
279
488
|
if (!ctx.clientSegmentSet.has(segment.id)) {
|
|
489
|
+
if (isTraceActive()) {
|
|
490
|
+
pushRevalidationTraceEntry({
|
|
491
|
+
segmentId: segment.id,
|
|
492
|
+
segmentType: segment.type,
|
|
493
|
+
belongsToRoute: segment.belongsToRoute ?? false,
|
|
494
|
+
source: "cache-hit",
|
|
495
|
+
defaultShouldRevalidate: true,
|
|
496
|
+
finalShouldRevalidate: true,
|
|
497
|
+
reason: "new-segment",
|
|
498
|
+
});
|
|
499
|
+
}
|
|
280
500
|
yield segment;
|
|
281
501
|
continue;
|
|
282
502
|
}
|
|
@@ -291,6 +511,17 @@ export function withCacheLookup<TEnv>(
|
|
|
291
511
|
const entryInfo = entryRevalidateMap?.get(segment.id);
|
|
292
512
|
if (!entryInfo || entryInfo.revalidate.length === 0) {
|
|
293
513
|
// No revalidation rules, use default behavior (skip if client has)
|
|
514
|
+
if (isTraceActive()) {
|
|
515
|
+
pushRevalidationTraceEntry({
|
|
516
|
+
segmentId: segment.id,
|
|
517
|
+
segmentType: segment.type,
|
|
518
|
+
belongsToRoute: segment.belongsToRoute ?? false,
|
|
519
|
+
source: "cache-hit",
|
|
520
|
+
defaultShouldRevalidate: false,
|
|
521
|
+
finalShouldRevalidate: false,
|
|
522
|
+
reason: "cached-no-rules",
|
|
523
|
+
});
|
|
524
|
+
}
|
|
294
525
|
segment.component = null;
|
|
295
526
|
segment.loading = undefined;
|
|
296
527
|
yield segment;
|
|
@@ -312,8 +543,24 @@ export function withCacheLookup<TEnv>(
|
|
|
312
543
|
routeKey: ctx.routeKey,
|
|
313
544
|
context: ctx.handlerContext,
|
|
314
545
|
actionContext: ctx.actionContext,
|
|
546
|
+
stale: cacheResult.shouldRevalidate || undefined,
|
|
547
|
+
traceSource: "cache-hit",
|
|
315
548
|
});
|
|
316
549
|
|
|
550
|
+
const routerCtx = getRouterContext<TEnv>();
|
|
551
|
+
if (routerCtx.telemetry) {
|
|
552
|
+
const tSink = resolveSink(routerCtx.telemetry);
|
|
553
|
+
safeEmit(tSink, {
|
|
554
|
+
type: "revalidation.decision",
|
|
555
|
+
timestamp: performance.now(),
|
|
556
|
+
requestId: routerCtx.requestId,
|
|
557
|
+
segmentId: segment.id,
|
|
558
|
+
pathname: ctx.pathname,
|
|
559
|
+
routeKey: ctx.routeKey,
|
|
560
|
+
shouldRevalidate,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
317
564
|
if (!shouldRevalidate) {
|
|
318
565
|
// Client has it, no revalidation needed
|
|
319
566
|
segment.component = null;
|
|
@@ -331,7 +578,7 @@ export function withCacheLookup<TEnv>(
|
|
|
331
578
|
// Full match (document request) - simple loader resolution without revalidation
|
|
332
579
|
if (resolveLoadersOnly) {
|
|
333
580
|
const loaderSegments = await Store.run(() =>
|
|
334
|
-
resolveLoadersOnly(ctx.entries, ctx.handlerContext)
|
|
581
|
+
resolveLoadersOnly(ctx.entries, ctx.handlerContext),
|
|
335
582
|
);
|
|
336
583
|
|
|
337
584
|
// Update state - full match doesn't track matchedIds separately
|
|
@@ -357,8 +604,9 @@ export function withCacheLookup<TEnv>(
|
|
|
357
604
|
ctx.prevUrl,
|
|
358
605
|
ctx.url,
|
|
359
606
|
ctx.routeKey,
|
|
360
|
-
ctx.actionContext
|
|
361
|
-
|
|
607
|
+
ctx.actionContext,
|
|
608
|
+
cacheResult.shouldRevalidate || undefined,
|
|
609
|
+
),
|
|
362
610
|
);
|
|
363
611
|
|
|
364
612
|
// Update state with fresh loader matchedIds
|
|
@@ -376,7 +624,11 @@ export function withCacheLookup<TEnv>(
|
|
|
376
624
|
}
|
|
377
625
|
}
|
|
378
626
|
if (ms) {
|
|
379
|
-
ms.metrics.push({
|
|
627
|
+
ms.metrics.push({
|
|
628
|
+
label: "pipeline:cache-lookup",
|
|
629
|
+
duration: performance.now() - pipelineStart,
|
|
630
|
+
startTime: pipelineStart - ms.requestStart,
|
|
631
|
+
});
|
|
380
632
|
}
|
|
381
633
|
};
|
|
382
634
|
}
|
|
@@ -104,6 +104,7 @@ import type { ResolvedSegment } from "../../types.js";
|
|
|
104
104
|
import { getRequestContext } from "../../server/request-context.js";
|
|
105
105
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
106
106
|
import { getRouterContext } from "../router-context.js";
|
|
107
|
+
import { debugLog, debugWarn } from "../logging.js";
|
|
107
108
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
108
109
|
|
|
109
110
|
/**
|
|
@@ -141,16 +142,21 @@ export function withCacheStore<TEnv>(
|
|
|
141
142
|
ctx.request.method !== "GET"
|
|
142
143
|
) {
|
|
143
144
|
if (ms) {
|
|
144
|
-
ms.metrics.push({
|
|
145
|
+
ms.metrics.push({
|
|
146
|
+
label: "pipeline:cache-store",
|
|
147
|
+
duration: performance.now() - pipelineStart,
|
|
148
|
+
startTime: pipelineStart - ms.requestStart,
|
|
149
|
+
});
|
|
145
150
|
}
|
|
146
151
|
return;
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
const {
|
|
150
155
|
createHandlerContext,
|
|
151
|
-
|
|
156
|
+
setupLoaderAccess,
|
|
152
157
|
resolveAllSegments,
|
|
153
158
|
resolveInterceptEntry,
|
|
159
|
+
createHandleStore,
|
|
154
160
|
} = getRouterContext<TEnv>();
|
|
155
161
|
|
|
156
162
|
// Combine main segments with intercept segments
|
|
@@ -172,9 +178,10 @@ export function withCacheStore<TEnv>(
|
|
|
172
178
|
requestCtx.onResponse((response) => {
|
|
173
179
|
// Only cache successful responses
|
|
174
180
|
if (response.status !== 200) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
debugLog("cacheStore", "skipping cache for non-200 response", {
|
|
182
|
+
status: response.status,
|
|
183
|
+
pathname: ctx.pathname,
|
|
184
|
+
});
|
|
178
185
|
return response;
|
|
179
186
|
}
|
|
180
187
|
|
|
@@ -182,29 +189,34 @@ export function withCacheStore<TEnv>(
|
|
|
182
189
|
// Proactive caching: render all segments fresh in background
|
|
183
190
|
// This ensures cache has complete components for future requests
|
|
184
191
|
requestCtx.waitUntil(async () => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
192
|
+
debugLog("cacheStore", "proactive caching started", {
|
|
193
|
+
pathname: ctx.pathname,
|
|
194
|
+
});
|
|
195
|
+
// Swap to a fresh HandleStore so handle.push() calls from
|
|
196
|
+
// proactive resolution are captured (not silenced). The original
|
|
197
|
+
// store's stream is already sent by waitUntil time.
|
|
198
|
+
// cacheRoute reads from requestCtx._handleStore, so this ensures
|
|
199
|
+
// complete handle data (e.g. breadcrumbs) is cached.
|
|
200
|
+
const originalHandleStore = requestCtx._handleStore;
|
|
201
|
+
requestCtx._handleStore = createHandleStore();
|
|
188
202
|
try {
|
|
189
203
|
// Create fresh context for proactive caching
|
|
190
|
-
// This prevents handle data from polluting the response stream
|
|
191
204
|
const proactiveHandlerContext = createHandlerContext(
|
|
192
205
|
ctx.matched.params,
|
|
193
206
|
ctx.request,
|
|
194
207
|
ctx.url.searchParams,
|
|
195
208
|
ctx.pathname,
|
|
196
209
|
ctx.url,
|
|
197
|
-
ctx.
|
|
210
|
+
ctx.env,
|
|
198
211
|
ctx.routeMap,
|
|
199
|
-
ctx.matched.routeKey
|
|
212
|
+
ctx.matched.routeKey,
|
|
213
|
+
ctx.matched.responseType,
|
|
214
|
+
ctx.matched.pt === true,
|
|
200
215
|
);
|
|
201
216
|
const proactiveLoaderPromises = new Map<string, Promise<any>>();
|
|
202
217
|
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
proactiveHandlerContext,
|
|
206
|
-
proactiveLoaderPromises,
|
|
207
|
-
);
|
|
218
|
+
// Use normal loader access so handle data is captured
|
|
219
|
+
setupLoaderAccess(proactiveHandlerContext, proactiveLoaderPromises);
|
|
208
220
|
|
|
209
221
|
// Re-resolve ALL segments without revalidation
|
|
210
222
|
const Store = ctx.Store;
|
|
@@ -237,20 +249,23 @@ export function withCacheStore<TEnv>(
|
|
|
237
249
|
...freshSegments,
|
|
238
250
|
...freshInterceptSegments,
|
|
239
251
|
];
|
|
252
|
+
requestCtx._handleStore.seal();
|
|
240
253
|
await cacheScope.cacheRoute(
|
|
241
254
|
ctx.pathname,
|
|
242
255
|
ctx.matched.params,
|
|
243
256
|
completeSegments,
|
|
244
257
|
ctx.isIntercept,
|
|
245
258
|
);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
);
|
|
259
|
+
debugLog("cacheStore", "proactive caching complete", {
|
|
260
|
+
pathname: ctx.pathname,
|
|
261
|
+
});
|
|
249
262
|
} catch (error) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
error,
|
|
253
|
-
);
|
|
263
|
+
debugWarn("cacheStore", "proactive caching failed", {
|
|
264
|
+
pathname: ctx.pathname,
|
|
265
|
+
error: String(error),
|
|
266
|
+
});
|
|
267
|
+
} finally {
|
|
268
|
+
requestCtx._handleStore = originalHandleStore;
|
|
254
269
|
}
|
|
255
270
|
});
|
|
256
271
|
} else {
|
|
@@ -270,7 +285,11 @@ export function withCacheStore<TEnv>(
|
|
|
270
285
|
});
|
|
271
286
|
|
|
272
287
|
if (ms) {
|
|
273
|
-
ms.metrics.push({
|
|
288
|
+
ms.metrics.push({
|
|
289
|
+
label: "pipeline:cache-store",
|
|
290
|
+
duration: performance.now() - pipelineStart,
|
|
291
|
+
startTime: pipelineStart - ms.requestStart,
|
|
292
|
+
});
|
|
274
293
|
}
|
|
275
294
|
};
|
|
276
295
|
}
|