@rangojs/router 0.0.0-experimental.b9cb8739 → 0.0.0-experimental.bd6e11bc
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 +196 -43
- package/dist/bin/rango.js +277 -99
- package/dist/testing/vitest.js +48 -0
- package/dist/vite/index.js +2779 -1064
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +57 -11
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +243 -21
- package/skills/caching/SKILL.md +155 -6
- package/skills/composability/SKILL.md +27 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +229 -20
- package/skills/host-router/SKILL.md +45 -20
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +46 -4
- package/skills/layout/SKILL.md +28 -7
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +273 -53
- package/skills/middleware/SKILL.md +49 -12
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +197 -6
- package/skills/prerender/SKILL.md +123 -100
- package/skills/rango/SKILL.md +242 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +66 -9
- package/skills/route/SKILL.md +88 -4
- package/skills/router-setup/SKILL.md +90 -5
- package/skills/server-actions/SKILL.md +751 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/testing/SKILL.md +716 -0
- package/skills/typesafety/SKILL.md +329 -27
- package/skills/use-cache/SKILL.md +34 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +117 -0
- package/src/__internal.ts +1 -1
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +91 -70
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/navigation-bridge.ts +102 -16
- package/src/browser/navigation-client.ts +164 -59
- package/src/browser/navigation-store.ts +75 -17
- package/src/browser/navigation-transaction.ts +21 -37
- package/src/browser/partial-update.ts +139 -38
- package/src/browser/prefetch/cache.ts +175 -15
- package/src/browser/prefetch/fetch.ts +180 -33
- package/src/browser/prefetch/queue.ts +123 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +81 -9
- package/src/browser/react/NavigationProvider.tsx +110 -33
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +51 -7
- package/src/browser/react/index.ts +3 -0
- package/src/browser/react/location-state-shared.ts +175 -4
- package/src/browser/react/location-state.ts +39 -13
- package/src/browser/react/use-handle.ts +23 -64
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +20 -8
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +43 -10
- package/src/browser/react/use-segments.ts +11 -8
- package/src/browser/response-adapter.ts +25 -0
- package/src/browser/rsc-router.tsx +191 -74
- package/src/browser/scroll-restoration.ts +41 -14
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +31 -36
- package/src/browser/types.ts +57 -5
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/index.ts +2 -0
- package/src/build/route-trie.ts +52 -25
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +9 -2
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +278 -88
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +76 -49
- package/src/cache/cf/cf-cache-store.ts +501 -18
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.rsc.tsx +3 -0
- package/src/client.tsx +94 -238
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +36 -0
- package/src/errors.ts +30 -1
- package/src/handle.ts +65 -12
- package/src/host/index.ts +2 -2
- package/src/host/router.ts +129 -57
- package/src/host/types.ts +31 -2
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +140 -20
- package/src/index.rsc.ts +12 -5
- package/src/index.ts +61 -11
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +2 -5
- package/src/loader.ts +3 -10
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +141 -80
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -15
- package/src/route-content-wrapper.tsx +6 -28
- package/src/route-definition/dsl-helpers.ts +435 -260
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +110 -34
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +113 -1
- package/src/router/error-handling.ts +1 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +77 -38
- package/src/router/intercept-resolution.ts +15 -22
- package/src/router/lazy-includes.ts +12 -9
- package/src/router/loader-resolution.ts +174 -22
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +31 -16
- package/src/router/match-api.ts +128 -192
- package/src/router/match-handlers.ts +63 -20
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +136 -106
- package/src/router/match-middleware/cache-store.ts +54 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +125 -10
- package/src/router/metrics.ts +7 -2
- package/src/router/middleware-types.ts +21 -34
- package/src/router/middleware.ts +103 -90
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +101 -17
- package/src/router/prerender-match.ts +110 -10
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +286 -0
- package/src/router/revalidation.ts +58 -2
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +77 -28
- package/src/router/router-options.ts +76 -11
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +223 -24
- package/src/router/segment-resolution/helpers.ts +29 -24
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +466 -285
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry.ts +99 -0
- package/src/router/trie-matching.ts +18 -13
- package/src/router/types.ts +9 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +91 -23
- package/src/rsc/handler-context.ts +2 -2
- package/src/rsc/handler.ts +440 -381
- package/src/rsc/helpers.ts +91 -43
- package/src/rsc/index.ts +1 -1
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/origin-guard.ts +28 -10
- package/src/rsc/progressive-enhancement.ts +18 -2
- package/src/rsc/response-route-handler.ts +46 -53
- package/src/rsc/rsc-rendering.ts +41 -48
- package/src/rsc/runtime-warnings.ts +9 -10
- package/src/rsc/server-action.ts +25 -37
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/types.ts +17 -3
- package/src/search-params.ts +4 -4
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +219 -67
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +277 -61
- package/src/server/cookie-store.ts +28 -4
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +204 -60
- package/src/ssr/index.tsx +9 -1
- package/src/static-handler.ts +19 -7
- package/src/testing/cache-status.ts +166 -0
- package/src/testing/collect-handle.ts +63 -0
- package/src/testing/dispatch.ts +440 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +154 -0
- package/src/testing/e2e/index.ts +149 -0
- package/src/testing/e2e/matchers.ts +51 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +306 -0
- package/src/testing/e2e/server.ts +183 -0
- package/src/testing/flight-matchers.ts +104 -0
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +22 -0
- package/src/testing/flight.ts +182 -0
- package/src/testing/generated-routes.ts +223 -0
- package/src/testing/index.ts +106 -0
- package/src/testing/internal/context.ts +255 -0
- package/src/testing/render-route.tsx +565 -0
- package/src/testing/run-loader.ts +296 -0
- package/src/testing/run-middleware.ts +179 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +183 -0
- package/src/types/cache-types.ts +4 -4
- package/src/types/global-namespace.ts +39 -26
- package/src/types/handler-context.ts +194 -72
- package/src/types/index.ts +1 -0
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +19 -1
- package/src/types/segments.ts +37 -1
- package/src/urls/include-helper.ts +34 -67
- package/src/urls/index.ts +0 -3
- package/src/urls/path-helper-types.ts +50 -9
- package/src/urls/path-helper.ts +63 -63
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +26 -116
- package/src/urls/urls-function.ts +1 -5
- package/src/use-loader.tsx +487 -44
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +34 -37
- package/src/vite/discovery/discover-routers.ts +105 -51
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +188 -93
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +46 -6
- package/src/vite/discovery/virtual-module-codegen.ts +13 -23
- package/src/vite/index.ts +6 -0
- package/src/vite/plugin-types.ts +111 -72
- package/src/vite/plugins/cjs-to-esm.ts +8 -7
- package/src/vite/plugins/client-ref-dedup.ts +16 -0
- package/src/vite/plugins/client-ref-hashing.ts +28 -5
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/plugins/expose-action-id.ts +55 -33
- package/src/vite/plugins/expose-id-utils.ts +24 -8
- package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
- package/src/vite/plugins/expose-ids/handler-transform.ts +12 -35
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
- package/src/vite/plugins/expose-internal-ids.ts +544 -317
- package/src/vite/plugins/performance-tracks.ts +92 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/use-cache-transform.ts +65 -50
- package/src/vite/plugins/version-injector.ts +39 -23
- package/src/vite/plugins/version-plugin.ts +72 -3
- package/src/vite/plugins/virtual-entries.ts +2 -2
- package/src/vite/rango.ts +265 -226
- package/src/vite/router-discovery.ts +920 -137
- package/src/vite/utils/ast-handler-extract.ts +15 -15
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +4 -2
- package/src/vite/utils/client-chunks.ts +190 -0
- package/src/vite/utils/forward-user-plugins.ts +193 -0
- package/src/vite/utils/manifest-utils.ts +21 -5
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +38 -5
- package/src/vite/utils/shared-utils.ts +109 -27
- package/src/browser/action-response-classifier.ts +0 -99
|
@@ -103,7 +103,8 @@ import type { ResolvedSegment } from "../../types.js";
|
|
|
103
103
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
104
104
|
import { getRouterContext } from "../router-context.js";
|
|
105
105
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
106
|
-
import { debugLog, debugWarn } from "../logging.js";
|
|
106
|
+
import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
|
|
107
|
+
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
107
108
|
|
|
108
109
|
/**
|
|
109
110
|
* Creates background revalidation middleware
|
|
@@ -143,8 +144,19 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
143
144
|
|
|
144
145
|
const requestCtx = getRequestContext();
|
|
145
146
|
const cacheScope = ctx.cacheScope;
|
|
147
|
+
const reqId = INTERNAL_RANGO_DEBUG
|
|
148
|
+
? getOrCreateRequestId(ctx.request)
|
|
149
|
+
: undefined;
|
|
146
150
|
|
|
147
151
|
requestCtx?.waitUntil(async () => {
|
|
152
|
+
// Prevent background metrics from polluting foreground timeline.
|
|
153
|
+
// The foreground uses its own metricsStore reference directly (via
|
|
154
|
+
// appendMetric), so nulling Store.metrics only affects track() calls
|
|
155
|
+
// inside this background Store.run() scope.
|
|
156
|
+
const savedMetrics = ctx.Store.metrics;
|
|
157
|
+
ctx.Store.metrics = undefined;
|
|
158
|
+
|
|
159
|
+
const start = performance.now();
|
|
148
160
|
debugLog("backgroundRevalidation", "revalidating stale route", {
|
|
149
161
|
pathname: ctx.pathname,
|
|
150
162
|
fullMatch: ctx.isFullMatch,
|
|
@@ -174,7 +186,9 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
174
186
|
setupLoaderAccess(freshHandlerContext, freshLoaderPromises);
|
|
175
187
|
|
|
176
188
|
// Resolve all segments fresh (without revalidation logic)
|
|
177
|
-
// to ensure complete components for caching
|
|
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.
|
|
178
192
|
const freshSegments = await ctx.Store.run(() =>
|
|
179
193
|
resolveAllSegments(
|
|
180
194
|
ctx.entries,
|
|
@@ -182,6 +196,7 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
182
196
|
ctx.matched.params,
|
|
183
197
|
freshHandlerContext,
|
|
184
198
|
freshLoaderPromises,
|
|
199
|
+
{ skipLoaders: true },
|
|
185
200
|
),
|
|
186
201
|
);
|
|
187
202
|
|
|
@@ -207,16 +222,29 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
207
222
|
completeSegments,
|
|
208
223
|
ctx.isIntercept,
|
|
209
224
|
);
|
|
225
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
226
|
+
const dur = performance.now() - start;
|
|
227
|
+
console.log(
|
|
228
|
+
`[RSC Background][req:${reqId}] SWR revalidation ${ctx.pathname} (${dur.toFixed(2)}ms) segments=${completeSegments.length}`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
210
231
|
debugLog("backgroundRevalidation", "revalidation complete", {
|
|
211
232
|
pathname: ctx.pathname,
|
|
212
233
|
});
|
|
213
234
|
} catch (error) {
|
|
235
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
236
|
+
const dur = performance.now() - start;
|
|
237
|
+
console.log(
|
|
238
|
+
`[RSC Background][req:${reqId}] SWR revalidation ${ctx.pathname} FAILED (${dur.toFixed(2)}ms) error=${String(error)}`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
214
241
|
debugWarn("backgroundRevalidation", "revalidation failed", {
|
|
215
242
|
pathname: ctx.pathname,
|
|
216
243
|
error: String(error),
|
|
217
244
|
});
|
|
218
245
|
} finally {
|
|
219
246
|
requestCtx._handleStore = originalHandleStore;
|
|
247
|
+
ctx.Store.metrics = savedMetrics;
|
|
220
248
|
}
|
|
221
249
|
});
|
|
222
250
|
};
|
|
@@ -70,9 +70,11 @@
|
|
|
70
70
|
* - No segments yielded from this middleware
|
|
71
71
|
*
|
|
72
72
|
* Loaders:
|
|
73
|
-
* - NEVER cached
|
|
73
|
+
* - NEVER cached in the segment cache
|
|
74
74
|
* - Always resolved fresh on every request
|
|
75
75
|
* - Ensures data freshness even with cached UI components
|
|
76
|
+
* - Segment cache staleness does NOT propagate to loader revalidation;
|
|
77
|
+
* loaders use their own revalidation rules (actionId, user-defined)
|
|
76
78
|
*
|
|
77
79
|
*
|
|
78
80
|
* REVALIDATION RULES
|
|
@@ -94,6 +96,7 @@ import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
|
94
96
|
import { getRouterContext } from "../router-context.js";
|
|
95
97
|
import { resolveSink, safeEmit } from "../telemetry.js";
|
|
96
98
|
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
99
|
+
import { treeHasStreaming } from "./segment-resolution.js";
|
|
97
100
|
import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
|
|
98
101
|
import type { HandleStore } from "../../server/handle-store.js";
|
|
99
102
|
import {
|
|
@@ -191,6 +194,16 @@ async function* yieldFromStore<TEnv>(
|
|
|
191
194
|
state.cachedSegments = segments;
|
|
192
195
|
state.cachedMatchedIds = segments.map((s) => s.id);
|
|
193
196
|
|
|
197
|
+
// Set streaming flag (once) and resolve render barrier.
|
|
198
|
+
const reqCtx = handleStoreRef ? undefined : _lazyGetRequestContext?.();
|
|
199
|
+
const barrierReqCtx = reqCtx ?? _getRequestContext();
|
|
200
|
+
if (barrierReqCtx) {
|
|
201
|
+
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
202
|
+
barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
|
|
203
|
+
}
|
|
204
|
+
barrierReqCtx._resolveRenderBarrier(segments);
|
|
205
|
+
}
|
|
206
|
+
|
|
194
207
|
// For partial navigation, nullify components the client already has
|
|
195
208
|
// so parent layouts stay live (client keeps its existing versions).
|
|
196
209
|
// When params changed (e.g., different guide slug), the segments have
|
|
@@ -210,6 +223,9 @@ async function* yieldFromStore<TEnv>(
|
|
|
210
223
|
}
|
|
211
224
|
|
|
212
225
|
// Resolve loaders fresh (loaders are never pre-rendered/cached)
|
|
226
|
+
const ms = ctx.metricsStore;
|
|
227
|
+
const loaderStart = performance.now();
|
|
228
|
+
|
|
213
229
|
if (ctx.isFullMatch) {
|
|
214
230
|
if (resolveLoadersOnly) {
|
|
215
231
|
const loaderSegments = await ctx.Store.run(() =>
|
|
@@ -235,6 +251,7 @@ async function* yieldFromStore<TEnv>(
|
|
|
235
251
|
ctx.url,
|
|
236
252
|
ctx.routeKey,
|
|
237
253
|
ctx.actionContext,
|
|
254
|
+
ctx.stale || undefined,
|
|
238
255
|
),
|
|
239
256
|
);
|
|
240
257
|
state.matchedIds = [
|
|
@@ -249,16 +266,54 @@ async function* yieldFromStore<TEnv>(
|
|
|
249
266
|
}
|
|
250
267
|
}
|
|
251
268
|
|
|
252
|
-
const ms = ctx.metricsStore;
|
|
253
269
|
if (ms) {
|
|
270
|
+
const loaderEnd = performance.now();
|
|
271
|
+
ms.metrics.push({
|
|
272
|
+
label: "pipeline:loader-resolve",
|
|
273
|
+
duration: loaderEnd - loaderStart,
|
|
274
|
+
startTime: loaderStart - ms.requestStart,
|
|
275
|
+
depth: 1,
|
|
276
|
+
});
|
|
254
277
|
ms.metrics.push({
|
|
255
|
-
label: "pipeline:cache-
|
|
256
|
-
duration:
|
|
278
|
+
label: "pipeline:cache-hit",
|
|
279
|
+
duration: loaderEnd - pipelineStart,
|
|
257
280
|
startTime: pipelineStart - ms.requestStart,
|
|
258
281
|
});
|
|
259
282
|
}
|
|
260
283
|
}
|
|
261
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Look up a prerendered (build-time cached) entry for the current route and, on
|
|
287
|
+
* a hit, yield its segments. Returns true when an entry was served (the caller
|
|
288
|
+
* should stop the pipeline) and false on a miss. Intercept navigations consult
|
|
289
|
+
* only the intercept-specific entry (`paramHash + "/i"`); a miss there falls
|
|
290
|
+
* through to the normal pipeline so intercept-resolution can run. Callers must
|
|
291
|
+
* guard on `prerenderStoreInstance` after `ensurePrerenderDeps()`.
|
|
292
|
+
*/
|
|
293
|
+
async function* tryPrerenderLookup<TEnv>(
|
|
294
|
+
ctx: MatchContext<TEnv>,
|
|
295
|
+
state: MatchPipelineState,
|
|
296
|
+
pipelineStart: number,
|
|
297
|
+
handleStoreRef?: HandleStore,
|
|
298
|
+
): AsyncGenerator<ResolvedSegment, boolean> {
|
|
299
|
+
const paramHash = _hashParams!(ctx.matched.params);
|
|
300
|
+
const isPassthroughPrerenderRoute = ctx.entries.some(
|
|
301
|
+
(entry) => entry.type === "route" && entry.isPassthrough === true,
|
|
302
|
+
);
|
|
303
|
+
const lookupHash = ctx.isIntercept ? paramHash + "/i" : paramHash;
|
|
304
|
+
const entry = await prerenderStoreInstance!.get(
|
|
305
|
+
ctx.matched.routeKey,
|
|
306
|
+
lookupHash,
|
|
307
|
+
{
|
|
308
|
+
pathname: ctx.pathname,
|
|
309
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
310
|
+
},
|
|
311
|
+
);
|
|
312
|
+
if (!entry) return false;
|
|
313
|
+
yield* yieldFromStore(entry, ctx, state, pipelineStart, handleStoreRef);
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
262
317
|
/**
|
|
263
318
|
* Async generator middleware type
|
|
264
319
|
*/
|
|
@@ -305,59 +360,19 @@ export function withCacheLookup<TEnv>(
|
|
|
305
360
|
|
|
306
361
|
// Prerender lookup: check build-time cached data before runtime cache.
|
|
307
362
|
// Prerender data is available regardless of runtime cache configuration.
|
|
308
|
-
|
|
363
|
+
// Skip for HMR requests — the dev prerender endpoint reads from a stale
|
|
364
|
+
// RouterRegistry snapshot; rendering fresh ensures edits are visible.
|
|
365
|
+
const isHmr = !!ctx.request.headers.get("X-RSC-HMR");
|
|
366
|
+
if (!ctx.isAction && !isHmr && ctx.matched.pr) {
|
|
309
367
|
await ensurePrerenderDeps();
|
|
310
368
|
if (prerenderStoreInstance) {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
369
|
+
const served = yield* tryPrerenderLookup(
|
|
370
|
+
ctx,
|
|
371
|
+
state,
|
|
372
|
+
pipelineStart,
|
|
373
|
+
handleStoreRef,
|
|
316
374
|
);
|
|
317
|
-
|
|
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;
|
|
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
|
-
}
|
|
375
|
+
if (served) return;
|
|
361
376
|
}
|
|
362
377
|
}
|
|
363
378
|
|
|
@@ -380,53 +395,13 @@ export function withCacheLookup<TEnv>(
|
|
|
380
395
|
if (hasStatic) {
|
|
381
396
|
await ensurePrerenderDeps();
|
|
382
397
|
if (prerenderStoreInstance) {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
398
|
+
const served = yield* tryPrerenderLookup(
|
|
399
|
+
ctx,
|
|
400
|
+
state,
|
|
401
|
+
pipelineStart,
|
|
402
|
+
handleStoreRef,
|
|
388
403
|
);
|
|
389
|
-
|
|
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,
|
|
406
|
-
);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
// No intercept prerender -- fall through to normal pipeline
|
|
410
|
-
} else {
|
|
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,
|
|
426
|
-
);
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
404
|
+
if (served) return;
|
|
430
405
|
}
|
|
431
406
|
}
|
|
432
407
|
}
|
|
@@ -437,7 +412,7 @@ export function withCacheLookup<TEnv>(
|
|
|
437
412
|
yield* source;
|
|
438
413
|
if (ms) {
|
|
439
414
|
ms.metrics.push({
|
|
440
|
-
label: "pipeline:cache-
|
|
415
|
+
label: "pipeline:cache-miss",
|
|
441
416
|
duration: performance.now() - pipelineStart,
|
|
442
417
|
startTime: pipelineStart - ms.requestStart,
|
|
443
418
|
});
|
|
@@ -457,7 +432,7 @@ export function withCacheLookup<TEnv>(
|
|
|
457
432
|
yield* source;
|
|
458
433
|
if (ms) {
|
|
459
434
|
ms.metrics.push({
|
|
460
|
-
label: "pipeline:cache-
|
|
435
|
+
label: "pipeline:cache-miss",
|
|
461
436
|
duration: performance.now() - pipelineStart,
|
|
462
437
|
startTime: pipelineStart - ms.requestStart,
|
|
463
438
|
});
|
|
@@ -509,7 +484,41 @@ export function withCacheLookup<TEnv>(
|
|
|
509
484
|
|
|
510
485
|
// Look up revalidation rules for this segment
|
|
511
486
|
const entryInfo = entryRevalidateMap?.get(segment.id);
|
|
487
|
+
|
|
488
|
+
// Even without explicit revalidation rules, route segments and their
|
|
489
|
+
// children must re-render when params or search params change — the
|
|
490
|
+
// handler reads ctx.params/ctx.searchParams so different values produce
|
|
491
|
+
// different content. Matches evaluateRevalidation's default logic.
|
|
492
|
+
const searchChanged = ctx.prevUrl.search !== ctx.url.search;
|
|
493
|
+
const routeParamsChanged = !paramsEqual(
|
|
494
|
+
ctx.matched.params,
|
|
495
|
+
ctx.prevParams,
|
|
496
|
+
);
|
|
497
|
+
const shouldDefaultRevalidate =
|
|
498
|
+
(searchChanged || routeParamsChanged) &&
|
|
499
|
+
(segment.type === "route" ||
|
|
500
|
+
(segment.belongsToRoute &&
|
|
501
|
+
(segment.type === "layout" || segment.type === "parallel")));
|
|
502
|
+
|
|
512
503
|
if (!entryInfo || entryInfo.revalidate.length === 0) {
|
|
504
|
+
if (shouldDefaultRevalidate) {
|
|
505
|
+
// Params or search params changed — must re-render even without custom rules
|
|
506
|
+
if (isTraceActive()) {
|
|
507
|
+
pushRevalidationTraceEntry({
|
|
508
|
+
segmentId: segment.id,
|
|
509
|
+
segmentType: segment.type,
|
|
510
|
+
belongsToRoute: segment.belongsToRoute ?? false,
|
|
511
|
+
source: "cache-hit",
|
|
512
|
+
defaultShouldRevalidate: true,
|
|
513
|
+
finalShouldRevalidate: true,
|
|
514
|
+
reason: routeParamsChanged
|
|
515
|
+
? "cached-params-changed"
|
|
516
|
+
: "cached-search-changed",
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
yield segment;
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
513
522
|
// No revalidation rules, use default behavior (skip if client has)
|
|
514
523
|
if (isTraceActive()) {
|
|
515
524
|
pushRevalidationTraceEntry({
|
|
@@ -543,7 +552,7 @@ export function withCacheLookup<TEnv>(
|
|
|
543
552
|
routeKey: ctx.routeKey,
|
|
544
553
|
context: ctx.handlerContext,
|
|
545
554
|
actionContext: ctx.actionContext,
|
|
546
|
-
stale: cacheResult.shouldRevalidate || undefined,
|
|
555
|
+
stale: cacheResult.shouldRevalidate || ctx.stale || undefined,
|
|
547
556
|
traceSource: "cache-hit",
|
|
548
557
|
});
|
|
549
558
|
|
|
@@ -570,9 +579,19 @@ export function withCacheLookup<TEnv>(
|
|
|
570
579
|
yield segment;
|
|
571
580
|
}
|
|
572
581
|
|
|
582
|
+
// Set streaming flag (once) and resolve render barrier.
|
|
583
|
+
const barrierReqCtx = _getRequestContext();
|
|
584
|
+
if (barrierReqCtx) {
|
|
585
|
+
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
586
|
+
barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
|
|
587
|
+
}
|
|
588
|
+
barrierReqCtx._resolveRenderBarrier(cacheResult.segments);
|
|
589
|
+
}
|
|
590
|
+
|
|
573
591
|
// Resolve loaders fresh (loaders are NOT cached by default)
|
|
574
592
|
// This ensures fresh data even on cache hit
|
|
575
593
|
const Store = ctx.Store;
|
|
594
|
+
const loaderStart = performance.now();
|
|
576
595
|
|
|
577
596
|
if (ctx.isFullMatch) {
|
|
578
597
|
// Full match (document request) - simple loader resolution without revalidation
|
|
@@ -605,7 +624,11 @@ export function withCacheLookup<TEnv>(
|
|
|
605
624
|
ctx.url,
|
|
606
625
|
ctx.routeKey,
|
|
607
626
|
ctx.actionContext,
|
|
608
|
-
|
|
627
|
+
// Loaders are never cached in the segment cache, so segment
|
|
628
|
+
// staleness (cacheResult.shouldRevalidate) must not propagate.
|
|
629
|
+
// But browser-sent staleness (ctx.stale) — indicating an action
|
|
630
|
+
// happened in this or another tab — must still reach loaders.
|
|
631
|
+
ctx.stale || undefined,
|
|
609
632
|
),
|
|
610
633
|
);
|
|
611
634
|
|
|
@@ -624,9 +647,16 @@ export function withCacheLookup<TEnv>(
|
|
|
624
647
|
}
|
|
625
648
|
}
|
|
626
649
|
if (ms) {
|
|
650
|
+
const loaderEnd = performance.now();
|
|
651
|
+
ms.metrics.push({
|
|
652
|
+
label: "pipeline:loader-resolve",
|
|
653
|
+
duration: loaderEnd - loaderStart,
|
|
654
|
+
startTime: loaderStart - ms.requestStart,
|
|
655
|
+
depth: 1,
|
|
656
|
+
});
|
|
627
657
|
ms.metrics.push({
|
|
628
|
-
label: "pipeline:cache-
|
|
629
|
-
duration:
|
|
658
|
+
label: "pipeline:cache-hit",
|
|
659
|
+
duration: loaderEnd - pipelineStart,
|
|
630
660
|
startTime: pipelineStart - ms.requestStart,
|
|
631
661
|
});
|
|
632
662
|
}
|
|
@@ -104,7 +104,8 @@ 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
|
+
import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
|
|
108
|
+
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
108
109
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
109
110
|
|
|
110
111
|
/**
|
|
@@ -120,7 +121,6 @@ export function withCacheStore<TEnv>(
|
|
|
120
121
|
return async function* (
|
|
121
122
|
source: AsyncGenerator<ResolvedSegment>,
|
|
122
123
|
): AsyncGenerator<ResolvedSegment> {
|
|
123
|
-
const pipelineStart = performance.now();
|
|
124
124
|
const ms = ctx.metricsStore;
|
|
125
125
|
|
|
126
126
|
// Collect all segments while passing them through
|
|
@@ -130,6 +130,9 @@ export function withCacheStore<TEnv>(
|
|
|
130
130
|
yield segment;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
// Measure own work only (after source iteration completes)
|
|
134
|
+
const ownStart = performance.now();
|
|
135
|
+
|
|
133
136
|
// Skip caching if:
|
|
134
137
|
// 1. Cache miss but cache scope is disabled
|
|
135
138
|
// 2. This is an action (actions don't cache)
|
|
@@ -144,8 +147,8 @@ export function withCacheStore<TEnv>(
|
|
|
144
147
|
if (ms) {
|
|
145
148
|
ms.metrics.push({
|
|
146
149
|
label: "pipeline:cache-store",
|
|
147
|
-
duration: performance.now() -
|
|
148
|
-
startTime:
|
|
150
|
+
duration: performance.now() - ownStart,
|
|
151
|
+
startTime: ownStart - ms.requestStart,
|
|
149
152
|
});
|
|
150
153
|
}
|
|
151
154
|
return;
|
|
@@ -162,16 +165,24 @@ export function withCacheStore<TEnv>(
|
|
|
162
165
|
// Combine main segments with intercept segments
|
|
163
166
|
const allSegmentsToCache = [...allSegments, ...state.interceptSegments];
|
|
164
167
|
|
|
165
|
-
// Check if any non-loader segments have null components
|
|
166
|
-
//
|
|
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.
|
|
167
172
|
const hasNullComponents = allSegmentsToCache.some(
|
|
168
|
-
(s) =>
|
|
173
|
+
(s) =>
|
|
174
|
+
s.component === null &&
|
|
175
|
+
s.type !== "loader" &&
|
|
176
|
+
ctx.clientSegmentSet.has(s.id),
|
|
169
177
|
);
|
|
170
178
|
|
|
171
179
|
const requestCtx = getRequestContext();
|
|
172
180
|
if (!requestCtx) return;
|
|
173
181
|
|
|
174
182
|
const cacheScope = ctx.cacheScope;
|
|
183
|
+
const reqId = INTERNAL_RANGO_DEBUG
|
|
184
|
+
? getOrCreateRequestId(ctx.request)
|
|
185
|
+
: undefined;
|
|
175
186
|
|
|
176
187
|
// Register onResponse callback to skip caching for non-200 responses
|
|
177
188
|
// Note: error/notFound status codes are set elsewhere (not caching-specific)
|
|
@@ -189,6 +200,11 @@ export function withCacheStore<TEnv>(
|
|
|
189
200
|
// Proactive caching: render all segments fresh in background
|
|
190
201
|
// This ensures cache has complete components for future requests
|
|
191
202
|
requestCtx.waitUntil(async () => {
|
|
203
|
+
// Prevent background metrics from polluting foreground timeline.
|
|
204
|
+
const savedMetrics = ctx.Store.metrics;
|
|
205
|
+
ctx.Store.metrics = undefined;
|
|
206
|
+
|
|
207
|
+
const start = performance.now();
|
|
192
208
|
debugLog("cacheStore", "proactive caching started", {
|
|
193
209
|
pathname: ctx.pathname,
|
|
194
210
|
});
|
|
@@ -218,7 +234,9 @@ export function withCacheStore<TEnv>(
|
|
|
218
234
|
// Use normal loader access so handle data is captured
|
|
219
235
|
setupLoaderAccess(proactiveHandlerContext, proactiveLoaderPromises);
|
|
220
236
|
|
|
221
|
-
// Re-resolve ALL segments without revalidation
|
|
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.
|
|
222
240
|
const Store = ctx.Store;
|
|
223
241
|
const freshSegments = await Store.run(() =>
|
|
224
242
|
resolveAllSegments(
|
|
@@ -227,6 +245,7 @@ export function withCacheStore<TEnv>(
|
|
|
227
245
|
ctx.matched.params,
|
|
228
246
|
proactiveHandlerContext,
|
|
229
247
|
proactiveLoaderPromises,
|
|
248
|
+
{ skipLoaders: true },
|
|
230
249
|
),
|
|
231
250
|
);
|
|
232
251
|
|
|
@@ -256,28 +275,53 @@ export function withCacheStore<TEnv>(
|
|
|
256
275
|
completeSegments,
|
|
257
276
|
ctx.isIntercept,
|
|
258
277
|
);
|
|
278
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
279
|
+
const dur = performance.now() - start;
|
|
280
|
+
console.log(
|
|
281
|
+
`[RSC Background][req:${reqId}] Proactive cache ${ctx.pathname} (${dur.toFixed(2)}ms) segments=${completeSegments.length}`,
|
|
282
|
+
);
|
|
283
|
+
}
|
|
259
284
|
debugLog("cacheStore", "proactive caching complete", {
|
|
260
285
|
pathname: ctx.pathname,
|
|
261
286
|
});
|
|
262
287
|
} catch (error) {
|
|
288
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
289
|
+
const dur = performance.now() - start;
|
|
290
|
+
console.log(
|
|
291
|
+
`[RSC Background][req:${reqId}] Proactive cache ${ctx.pathname} FAILED (${dur.toFixed(2)}ms) error=${String(error)}`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
263
294
|
debugWarn("cacheStore", "proactive caching failed", {
|
|
264
295
|
pathname: ctx.pathname,
|
|
265
296
|
error: String(error),
|
|
266
297
|
});
|
|
267
298
|
} finally {
|
|
268
299
|
requestCtx._handleStore = originalHandleStore;
|
|
300
|
+
ctx.Store.metrics = savedMetrics;
|
|
269
301
|
}
|
|
270
302
|
});
|
|
271
303
|
} else {
|
|
272
304
|
// All segments have components - cache directly
|
|
273
305
|
// Schedule caching in waitUntil since cacheRoute is now async (key resolution)
|
|
306
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
307
|
+
console.log(
|
|
308
|
+
`[RSC CacheStore][req:${reqId}] Direct cache path: scheduling cacheRoute for ${ctx.pathname} (${allSegmentsToCache.length} segments, hasNullComponents=${hasNullComponents})`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
274
311
|
requestCtx.waitUntil(async () => {
|
|
312
|
+
const start = performance.now();
|
|
275
313
|
await cacheScope.cacheRoute(
|
|
276
314
|
ctx.pathname,
|
|
277
315
|
ctx.matched.params,
|
|
278
316
|
allSegmentsToCache,
|
|
279
317
|
ctx.isIntercept,
|
|
280
318
|
);
|
|
319
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
320
|
+
const dur = performance.now() - start;
|
|
321
|
+
console.log(
|
|
322
|
+
`[RSC Background][req:${reqId}] Cache store ${ctx.pathname} (${dur.toFixed(2)}ms) segments=${allSegmentsToCache.length}`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
281
325
|
});
|
|
282
326
|
}
|
|
283
327
|
|
|
@@ -287,8 +331,8 @@ export function withCacheStore<TEnv>(
|
|
|
287
331
|
if (ms) {
|
|
288
332
|
ms.metrics.push({
|
|
289
333
|
label: "pipeline:cache-store",
|
|
290
|
-
duration: performance.now() -
|
|
291
|
-
startTime:
|
|
334
|
+
duration: performance.now() - ownStart,
|
|
335
|
+
startTime: ownStart - ms.requestStart,
|
|
292
336
|
});
|
|
293
337
|
}
|
|
294
338
|
};
|
|
@@ -123,7 +123,6 @@ export function withInterceptResolution<TEnv>(
|
|
|
123
123
|
return async function* (
|
|
124
124
|
source: AsyncGenerator<ResolvedSegment>,
|
|
125
125
|
): AsyncGenerator<ResolvedSegment> {
|
|
126
|
-
const pipelineStart = performance.now();
|
|
127
126
|
const ms = ctx.metricsStore;
|
|
128
127
|
|
|
129
128
|
// First, yield all segments from the source (main segment resolution or cache)
|
|
@@ -133,13 +132,16 @@ export function withInterceptResolution<TEnv>(
|
|
|
133
132
|
yield segment;
|
|
134
133
|
}
|
|
135
134
|
|
|
135
|
+
// Measure own work only (after source iteration completes)
|
|
136
|
+
const ownStart = performance.now();
|
|
137
|
+
|
|
136
138
|
// Skip intercept resolution for full match (document requests don't have intercepts)
|
|
137
139
|
if (ctx.isFullMatch) {
|
|
138
140
|
if (ms) {
|
|
139
141
|
ms.metrics.push({
|
|
140
142
|
label: "pipeline:intercept",
|
|
141
|
-
duration: performance.now() -
|
|
142
|
-
startTime:
|
|
143
|
+
duration: performance.now() - ownStart,
|
|
144
|
+
startTime: ownStart - ms.requestStart,
|
|
143
145
|
});
|
|
144
146
|
}
|
|
145
147
|
return;
|
|
@@ -163,8 +165,8 @@ export function withInterceptResolution<TEnv>(
|
|
|
163
165
|
if (ms) {
|
|
164
166
|
ms.metrics.push({
|
|
165
167
|
label: "pipeline:intercept",
|
|
166
|
-
duration: performance.now() -
|
|
167
|
-
startTime:
|
|
168
|
+
duration: performance.now() - ownStart,
|
|
169
|
+
startTime: ownStart - ms.requestStart,
|
|
168
170
|
});
|
|
169
171
|
}
|
|
170
172
|
return;
|
|
@@ -216,8 +218,8 @@ export function withInterceptResolution<TEnv>(
|
|
|
216
218
|
if (ms) {
|
|
217
219
|
ms.metrics.push({
|
|
218
220
|
label: "pipeline:intercept",
|
|
219
|
-
duration: performance.now() -
|
|
220
|
-
startTime:
|
|
221
|
+
duration: performance.now() - ownStart,
|
|
222
|
+
startTime: ownStart - ms.requestStart,
|
|
221
223
|
});
|
|
222
224
|
}
|
|
223
225
|
};
|