@rangojs/router 0.0.0-experimental.13 → 0.0.0-experimental.13221847
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 +9 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1531 -212
- package/dist/vite/index.js +3995 -2489
- package/package.json +57 -52
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +85 -23
- 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 +328 -70
- 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 +62 -15
- package/skills/loader/SKILL.md +368 -42
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +14 -10
- package/skills/parallel/SKILL.md +137 -1
- package/skills/prerender/SKILL.md +366 -28
- package/skills/rango/SKILL.md +85 -21
- package/skills/response-routes/SKILL.md +136 -83
- package/skills/route/SKILL.md +195 -21
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +240 -102
- 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 +92 -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 +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +266 -558
- package/src/browser/navigation-client.ts +132 -75
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +303 -309
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +144 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +190 -70
- package/src/browser/react/NavigationProvider.tsx +78 -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 +188 -57
- package/src/browser/scroll-restoration.ts +117 -44
- package/src/browser/segment-reconciler.ts +221 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +488 -606
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +116 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +63 -21
- package/src/build/generate-route-types.ts +36 -1038
- package/src/build/index.ts +2 -5
- package/src/build/route-trie.ts +38 -12
- 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 +479 -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 +342 -0
- package/src/cache/cache-scope.ts +122 -303
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -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 +19 -9
- package/src/errors.ts +77 -7
- package/src/handle.ts +12 -7
- 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 +104 -40
- package/src/index.ts +122 -67
- package/src/internal-debug.ts +9 -3
- package/src/loader.rsc.ts +18 -93
- package/src/loader.ts +26 -9
- 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 +121 -17
- package/src/prerender.ts +325 -20
- package/src/reverse.ts +144 -124
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +959 -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 -1450
- package/src/route-map-builder.ts +87 -133
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +41 -6
- 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 +160 -0
- package/src/router/handler-context.ts +324 -116
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +179 -133
- package/src/router/logging.ts +112 -6
- package/src/router/manifest.ts +58 -19
- package/src/router/match-api.ts +89 -88
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +86 -89
- package/src/router/match-middleware/cache-lookup.ts +295 -49
- package/src/router/match-middleware/cache-store.ts +56 -13
- package/src/router/match-middleware/intercept-resolution.ts +45 -22
- package/src/router/match-middleware/segment-resolution.ts +20 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +44 -21
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +327 -369
- package/src/router/pattern-matching.ts +169 -31
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +105 -14
- package/src/router/router-context.ts +40 -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 +677 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1296 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1354
- package/src/router/segment-wrappers.ts +291 -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 +15 -9
- package/src/router.ts +642 -2366
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +639 -1027
- 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 +66 -54
- package/src/segment-system.tsx +165 -17
- package/src/server/context.ts +237 -54
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +438 -71
- package/src/server.ts +26 -164
- package/src/ssr/index.tsx +101 -31
- package/src/static-handler.ts +22 -4
- 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 +773 -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 +109 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1795
- 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 -1323
- 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 +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -2259
- package/src/vite/plugin-types.ts +48 -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 -47
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +8 -43
- 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 +266 -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 +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +181 -9
- 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/dist/vite/index.named-routes.gen.ts +0 -103
- 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/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { sanitizeError } from "../errors";
|
|
3
|
+
import type { ErrorInfo, ErrorPhase, MatchResult } from "../types";
|
|
4
|
+
import type {
|
|
5
|
+
EntryData,
|
|
6
|
+
InterceptEntry,
|
|
7
|
+
InterceptSelectorContext,
|
|
8
|
+
} from "../server/context";
|
|
9
|
+
import type { MatchApiDeps } from "./types.js";
|
|
10
|
+
import type { RouterContext } from "./router-context.js";
|
|
11
|
+
import { runWithRouterContext } from "./router-context.js";
|
|
12
|
+
import {
|
|
13
|
+
type ActionContext,
|
|
14
|
+
type MatchContext,
|
|
15
|
+
createPipelineState,
|
|
16
|
+
} from "./match-context.js";
|
|
17
|
+
import { createMatchPartialPipeline } from "./match-pipelines.js";
|
|
18
|
+
import { collectMatchResult } from "./match-result.js";
|
|
19
|
+
import {
|
|
20
|
+
createMatchContextForFull as _createMatchContextForFull,
|
|
21
|
+
createMatchContextForPartial as _createMatchContextForPartial,
|
|
22
|
+
matchError as _matchError,
|
|
23
|
+
} from "./match-api.js";
|
|
24
|
+
import { previewMatch as _previewMatch } from "./preview-match.js";
|
|
25
|
+
import {
|
|
26
|
+
runWithRouterLogContext,
|
|
27
|
+
withRouterLogScope,
|
|
28
|
+
isRouterDebugEnabled,
|
|
29
|
+
startRevalidationTrace,
|
|
30
|
+
flushRevalidationTrace,
|
|
31
|
+
} from "./logging.js";
|
|
32
|
+
import type { ErrorBoundaryHandler, NotFoundBoundaryHandler } from "../types";
|
|
33
|
+
import type { MiddlewareFn } from "./middleware.js";
|
|
34
|
+
import {
|
|
35
|
+
type TelemetrySink,
|
|
36
|
+
safeEmit,
|
|
37
|
+
resolveSink,
|
|
38
|
+
getRequestId,
|
|
39
|
+
} from "./telemetry.js";
|
|
40
|
+
|
|
41
|
+
export interface MatchHandlerDeps<TEnv = any> {
|
|
42
|
+
buildRouterContext: () => RouterContext<TEnv>;
|
|
43
|
+
callOnError: (error: unknown, phase: ErrorPhase, context: any) => void;
|
|
44
|
+
matchApiDeps: MatchApiDeps<TEnv>;
|
|
45
|
+
defaultErrorBoundary: ReactNode | ErrorBoundaryHandler | undefined;
|
|
46
|
+
findMatch: (pathname: string, ms?: any) => any;
|
|
47
|
+
findInterceptForRoute: (
|
|
48
|
+
routeKey: string,
|
|
49
|
+
parentEntry: EntryData | null,
|
|
50
|
+
selectorContext: InterceptSelectorContext | null,
|
|
51
|
+
isAction: boolean,
|
|
52
|
+
) => { intercept: InterceptEntry; entry: EntryData } | null;
|
|
53
|
+
telemetry?: TelemetrySink;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface MatchHandlers<TEnv = any> {
|
|
57
|
+
match: (request: Request, env: TEnv) => Promise<MatchResult>;
|
|
58
|
+
matchPartial: (
|
|
59
|
+
request: Request,
|
|
60
|
+
context: TEnv,
|
|
61
|
+
actionContext?: ActionContext,
|
|
62
|
+
) => Promise<MatchResult | null>;
|
|
63
|
+
matchError: (
|
|
64
|
+
request: Request,
|
|
65
|
+
_context: TEnv,
|
|
66
|
+
error: unknown,
|
|
67
|
+
segmentType?: ErrorInfo["segmentType"],
|
|
68
|
+
) => Promise<MatchResult | null>;
|
|
69
|
+
previewMatch: (
|
|
70
|
+
request: Request,
|
|
71
|
+
_context: TEnv,
|
|
72
|
+
) => Promise<{
|
|
73
|
+
routeMiddleware?: Array<{
|
|
74
|
+
handler: MiddlewareFn;
|
|
75
|
+
params: Record<string, string>;
|
|
76
|
+
}>;
|
|
77
|
+
responseType?: string;
|
|
78
|
+
handler?: Function;
|
|
79
|
+
params?: Record<string, string>;
|
|
80
|
+
negotiated?: boolean;
|
|
81
|
+
manifestEntry?: EntryData;
|
|
82
|
+
} | null>;
|
|
83
|
+
createMatchContextForFull: (
|
|
84
|
+
request: Request,
|
|
85
|
+
env: TEnv,
|
|
86
|
+
) => Promise<MatchContext<TEnv> | { type: "redirect"; redirectUrl: string }>;
|
|
87
|
+
createMatchContextForPartial: (
|
|
88
|
+
request: Request,
|
|
89
|
+
env: TEnv,
|
|
90
|
+
actionContext?: {
|
|
91
|
+
actionId?: string;
|
|
92
|
+
actionUrl?: URL;
|
|
93
|
+
actionResult?: any;
|
|
94
|
+
formData?: FormData;
|
|
95
|
+
},
|
|
96
|
+
) => Promise<MatchContext<TEnv> | null>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create match handler functions bound to router closure state.
|
|
101
|
+
* These are the main request-handling entry points for SSR, navigation,
|
|
102
|
+
* error recovery, and preview matching.
|
|
103
|
+
*/
|
|
104
|
+
export function createMatchHandlers<TEnv = any>(
|
|
105
|
+
deps: MatchHandlerDeps<TEnv>,
|
|
106
|
+
): MatchHandlers<TEnv> {
|
|
107
|
+
const {
|
|
108
|
+
buildRouterContext,
|
|
109
|
+
callOnError,
|
|
110
|
+
matchApiDeps,
|
|
111
|
+
defaultErrorBoundary,
|
|
112
|
+
findInterceptForRoute,
|
|
113
|
+
} = deps;
|
|
114
|
+
const hasTelemetry = !!deps.telemetry;
|
|
115
|
+
const telemetry = resolveSink(deps.telemetry);
|
|
116
|
+
|
|
117
|
+
async function createMatchContextForFull(
|
|
118
|
+
request: Request,
|
|
119
|
+
env: TEnv,
|
|
120
|
+
): Promise<MatchContext<TEnv> | { type: "redirect"; redirectUrl: string }> {
|
|
121
|
+
return _createMatchContextForFull(
|
|
122
|
+
request,
|
|
123
|
+
env,
|
|
124
|
+
matchApiDeps,
|
|
125
|
+
findInterceptForRoute,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function createMatchContextForPartial(
|
|
130
|
+
request: Request,
|
|
131
|
+
env: TEnv,
|
|
132
|
+
actionContext?: {
|
|
133
|
+
actionId?: string;
|
|
134
|
+
actionUrl?: URL;
|
|
135
|
+
actionResult?: any;
|
|
136
|
+
formData?: FormData;
|
|
137
|
+
},
|
|
138
|
+
): Promise<MatchContext<TEnv> | null> {
|
|
139
|
+
return _createMatchContextForPartial(
|
|
140
|
+
request,
|
|
141
|
+
env,
|
|
142
|
+
matchApiDeps,
|
|
143
|
+
findInterceptForRoute,
|
|
144
|
+
actionContext,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Match request and return segments (document/SSR requests)
|
|
150
|
+
*
|
|
151
|
+
* Uses generator middleware pipeline for clean separation of concerns:
|
|
152
|
+
* - cache-lookup: Check cache first
|
|
153
|
+
* - segment-resolution: Resolve segments on cache miss
|
|
154
|
+
* - cache-store: Store results in cache
|
|
155
|
+
* - background-revalidation: SWR revalidation
|
|
156
|
+
*/
|
|
157
|
+
async function match(request: Request, env: TEnv): Promise<MatchResult> {
|
|
158
|
+
const requestId = hasTelemetry ? getRequestId(request) : undefined;
|
|
159
|
+
return runWithRouterLogContext({ request, transaction: "match" }, () => {
|
|
160
|
+
const routerCtx = buildRouterContext();
|
|
161
|
+
routerCtx.requestId = requestId;
|
|
162
|
+
return runWithRouterContext(routerCtx, async () =>
|
|
163
|
+
withRouterLogScope("match", async () => {
|
|
164
|
+
const matchStart = performance.now();
|
|
165
|
+
const pathname = new URL(request.url).pathname;
|
|
166
|
+
if (hasTelemetry) {
|
|
167
|
+
safeEmit(telemetry, {
|
|
168
|
+
type: "request.start",
|
|
169
|
+
timestamp: matchStart,
|
|
170
|
+
requestId,
|
|
171
|
+
method: request.method,
|
|
172
|
+
pathname,
|
|
173
|
+
transaction: "match",
|
|
174
|
+
isPartial: false,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const result = await createMatchContextForFull(request, env);
|
|
179
|
+
|
|
180
|
+
// Handle redirect case
|
|
181
|
+
if ("type" in result && result.type === "redirect") {
|
|
182
|
+
if (hasTelemetry) {
|
|
183
|
+
safeEmit(telemetry, {
|
|
184
|
+
type: "request.end",
|
|
185
|
+
timestamp: performance.now(),
|
|
186
|
+
requestId,
|
|
187
|
+
method: request.method,
|
|
188
|
+
pathname,
|
|
189
|
+
transaction: "match",
|
|
190
|
+
durationMs: performance.now() - matchStart,
|
|
191
|
+
segmentCount: 0,
|
|
192
|
+
cacheHit: false,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
segments: [],
|
|
197
|
+
matched: [],
|
|
198
|
+
diff: [],
|
|
199
|
+
params: {},
|
|
200
|
+
redirect: result.redirectUrl,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const ctx = result as MatchContext<TEnv>;
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
const state = createPipelineState();
|
|
208
|
+
const pipeline = createMatchPartialPipeline(ctx, state);
|
|
209
|
+
const matchResult = await collectMatchResult(pipeline, ctx, state);
|
|
210
|
+
if (hasTelemetry) {
|
|
211
|
+
safeEmit(telemetry, {
|
|
212
|
+
type: "cache.decision",
|
|
213
|
+
timestamp: performance.now(),
|
|
214
|
+
requestId,
|
|
215
|
+
pathname,
|
|
216
|
+
routeKey: ctx.routeKey,
|
|
217
|
+
hit: state.cacheHit,
|
|
218
|
+
shouldRevalidate: !!state.shouldRevalidate,
|
|
219
|
+
source: state.cacheSource,
|
|
220
|
+
});
|
|
221
|
+
safeEmit(telemetry, {
|
|
222
|
+
type: "request.end",
|
|
223
|
+
timestamp: performance.now(),
|
|
224
|
+
requestId,
|
|
225
|
+
method: request.method,
|
|
226
|
+
pathname,
|
|
227
|
+
transaction: "match",
|
|
228
|
+
durationMs: performance.now() - matchStart,
|
|
229
|
+
segmentCount: matchResult.segments.length,
|
|
230
|
+
cacheHit: state.cacheHit,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return matchResult;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (hasTelemetry) {
|
|
236
|
+
const errorObj =
|
|
237
|
+
error instanceof Error ? error : new Error(String(error));
|
|
238
|
+
safeEmit(telemetry, {
|
|
239
|
+
type: "request.error",
|
|
240
|
+
timestamp: performance.now(),
|
|
241
|
+
requestId,
|
|
242
|
+
method: request.method,
|
|
243
|
+
pathname,
|
|
244
|
+
transaction: "match",
|
|
245
|
+
error: errorObj,
|
|
246
|
+
phase: error instanceof Response ? "redirect" : "routing",
|
|
247
|
+
durationMs: performance.now() - matchStart,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (error instanceof Response) throw error;
|
|
251
|
+
// Report unhandled errors during full match pipeline
|
|
252
|
+
callOnError(error, "routing", {
|
|
253
|
+
request,
|
|
254
|
+
url: ctx.url,
|
|
255
|
+
env,
|
|
256
|
+
isPartial: false,
|
|
257
|
+
handledByBoundary: false,
|
|
258
|
+
});
|
|
259
|
+
throw sanitizeError(error);
|
|
260
|
+
}
|
|
261
|
+
}),
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function matchError(
|
|
267
|
+
request: Request,
|
|
268
|
+
_context: TEnv,
|
|
269
|
+
error: unknown,
|
|
270
|
+
segmentType: ErrorInfo["segmentType"] = "route",
|
|
271
|
+
): Promise<MatchResult | null> {
|
|
272
|
+
return runWithRouterLogContext({ request, transaction: "matchError" }, () =>
|
|
273
|
+
withRouterLogScope("matchError", () =>
|
|
274
|
+
_matchError(
|
|
275
|
+
request,
|
|
276
|
+
_context,
|
|
277
|
+
error,
|
|
278
|
+
matchApiDeps,
|
|
279
|
+
defaultErrorBoundary,
|
|
280
|
+
segmentType,
|
|
281
|
+
),
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Match partial request with revalidation
|
|
288
|
+
*
|
|
289
|
+
* Uses generator middleware pipeline for clean separation of concerns:
|
|
290
|
+
* - cache-lookup: Check cache first
|
|
291
|
+
* - segment-resolution: Resolve segments on cache miss
|
|
292
|
+
* - intercept-resolution: Handle intercept routes
|
|
293
|
+
* - cache-store: Store results in cache
|
|
294
|
+
* - background-revalidation: SWR revalidation
|
|
295
|
+
*/
|
|
296
|
+
async function matchPartial(
|
|
297
|
+
request: Request,
|
|
298
|
+
context: TEnv,
|
|
299
|
+
actionContext?: ActionContext,
|
|
300
|
+
): Promise<MatchResult | null> {
|
|
301
|
+
const partialRequestId = hasTelemetry ? getRequestId(request) : undefined;
|
|
302
|
+
return runWithRouterLogContext(
|
|
303
|
+
{ request, transaction: "matchPartial" },
|
|
304
|
+
() => {
|
|
305
|
+
const routerCtx = buildRouterContext();
|
|
306
|
+
routerCtx.requestId = partialRequestId;
|
|
307
|
+
return runWithRouterContext(routerCtx, async () =>
|
|
308
|
+
withRouterLogScope("matchPartial", async () => {
|
|
309
|
+
const matchStart = performance.now();
|
|
310
|
+
const pathname = new URL(request.url).pathname;
|
|
311
|
+
if (hasTelemetry) {
|
|
312
|
+
safeEmit(telemetry, {
|
|
313
|
+
type: "request.start",
|
|
314
|
+
timestamp: matchStart,
|
|
315
|
+
requestId: partialRequestId,
|
|
316
|
+
method: request.method,
|
|
317
|
+
pathname,
|
|
318
|
+
transaction: "matchPartial",
|
|
319
|
+
isPartial: true,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const ctx = await createMatchContextForPartial(
|
|
324
|
+
request,
|
|
325
|
+
context,
|
|
326
|
+
actionContext,
|
|
327
|
+
);
|
|
328
|
+
if (!ctx) {
|
|
329
|
+
if (hasTelemetry) {
|
|
330
|
+
safeEmit(telemetry, {
|
|
331
|
+
type: "request.end",
|
|
332
|
+
timestamp: performance.now(),
|
|
333
|
+
requestId: partialRequestId,
|
|
334
|
+
method: request.method,
|
|
335
|
+
pathname,
|
|
336
|
+
transaction: "matchPartial",
|
|
337
|
+
durationMs: performance.now() - matchStart,
|
|
338
|
+
segmentCount: 0,
|
|
339
|
+
cacheHit: false,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (isRouterDebugEnabled()) {
|
|
346
|
+
startRevalidationTrace({
|
|
347
|
+
method: request.method,
|
|
348
|
+
prevUrl: ctx.prevUrl.href,
|
|
349
|
+
nextUrl: ctx.url.href,
|
|
350
|
+
routeKey: ctx.routeKey,
|
|
351
|
+
isAction: !!actionContext,
|
|
352
|
+
stale: ctx.stale || undefined,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
const state = createPipelineState();
|
|
358
|
+
const pipeline = createMatchPartialPipeline(ctx, state);
|
|
359
|
+
const matchResult = await collectMatchResult(
|
|
360
|
+
pipeline,
|
|
361
|
+
ctx,
|
|
362
|
+
state,
|
|
363
|
+
);
|
|
364
|
+
flushRevalidationTrace();
|
|
365
|
+
if (hasTelemetry) {
|
|
366
|
+
safeEmit(telemetry, {
|
|
367
|
+
type: "cache.decision",
|
|
368
|
+
timestamp: performance.now(),
|
|
369
|
+
requestId: partialRequestId,
|
|
370
|
+
pathname,
|
|
371
|
+
routeKey: ctx.routeKey,
|
|
372
|
+
hit: state.cacheHit,
|
|
373
|
+
shouldRevalidate: !!state.shouldRevalidate,
|
|
374
|
+
source: state.cacheSource,
|
|
375
|
+
});
|
|
376
|
+
safeEmit(telemetry, {
|
|
377
|
+
type: "request.end",
|
|
378
|
+
timestamp: performance.now(),
|
|
379
|
+
requestId: partialRequestId,
|
|
380
|
+
method: request.method,
|
|
381
|
+
pathname,
|
|
382
|
+
transaction: "matchPartial",
|
|
383
|
+
durationMs: performance.now() - matchStart,
|
|
384
|
+
segmentCount: matchResult.segments.length,
|
|
385
|
+
cacheHit: state.cacheHit,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
return matchResult;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
flushRevalidationTrace();
|
|
391
|
+
if (hasTelemetry) {
|
|
392
|
+
const errorObj =
|
|
393
|
+
error instanceof Error ? error : new Error(String(error));
|
|
394
|
+
const phase = actionContext ? "action" : "revalidation";
|
|
395
|
+
safeEmit(telemetry, {
|
|
396
|
+
type: "request.error",
|
|
397
|
+
timestamp: performance.now(),
|
|
398
|
+
requestId: partialRequestId,
|
|
399
|
+
method: request.method,
|
|
400
|
+
pathname,
|
|
401
|
+
transaction: "matchPartial",
|
|
402
|
+
error: errorObj,
|
|
403
|
+
phase: error instanceof Response ? "redirect" : phase,
|
|
404
|
+
durationMs: performance.now() - matchStart,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (error instanceof Response) throw error;
|
|
408
|
+
// Report unhandled errors during partial match pipeline
|
|
409
|
+
callOnError(error, actionContext ? "action" : "revalidation", {
|
|
410
|
+
request,
|
|
411
|
+
url: ctx.url,
|
|
412
|
+
env: context,
|
|
413
|
+
actionId: actionContext?.actionId,
|
|
414
|
+
isPartial: true,
|
|
415
|
+
handledByBoundary: false,
|
|
416
|
+
});
|
|
417
|
+
throw sanitizeError(error);
|
|
418
|
+
}
|
|
419
|
+
}),
|
|
420
|
+
);
|
|
421
|
+
},
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async function previewMatch(
|
|
426
|
+
request: Request,
|
|
427
|
+
_context: TEnv,
|
|
428
|
+
): ReturnType<typeof _previewMatch> {
|
|
429
|
+
return _previewMatch(request, _context, { findMatch: deps.findMatch });
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return {
|
|
433
|
+
match: match,
|
|
434
|
+
matchPartial: matchPartial,
|
|
435
|
+
matchError: matchError,
|
|
436
|
+
previewMatch: previewMatch,
|
|
437
|
+
createMatchContextForFull: createMatchContextForFull,
|
|
438
|
+
createMatchContextForPartial: createMatchContextForPartial,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
@@ -30,23 +30,15 @@
|
|
|
30
30
|
* |
|
|
31
31
|
* v (async, doesn't block response)
|
|
32
32
|
* +---------------------------+
|
|
33
|
-
* | Create fresh
|
|
33
|
+
* | Create fresh context | Fresh handleStore, handlerContext,
|
|
34
|
+
* | (full isolation) | and loaderPromises map
|
|
34
35
|
* +---------------------------+
|
|
35
36
|
* |
|
|
36
37
|
* v
|
|
37
|
-
*
|
|
38
|
-
* |
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* +-----+-----+
|
|
42
|
-
* | |
|
|
43
|
-
* yes no
|
|
44
|
-
* | |
|
|
45
|
-
* v v
|
|
46
|
-
* resolveAll resolveWithRevalidation
|
|
47
|
-
* Segments + resolveIntercepts
|
|
48
|
-
* | |
|
|
49
|
-
* +-----------+
|
|
38
|
+
* +---------------------------+
|
|
39
|
+
* | resolveAllSegments() | Fresh resolution (no revalidation)
|
|
40
|
+
* | + resolveIntercepts() | Ensures complete components
|
|
41
|
+
* +---------------------------+
|
|
50
42
|
* |
|
|
51
43
|
* v
|
|
52
44
|
* +---------------------------+
|
|
@@ -90,33 +82,29 @@
|
|
|
90
82
|
* ISOLATION FROM RESPONSE
|
|
91
83
|
* =======================
|
|
92
84
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* - Polluting the current response stream
|
|
99
|
-
* - Causing duplicate data in the client
|
|
100
|
-
* - Creating race conditions
|
|
85
|
+
* Background revalidation creates fully isolated context:
|
|
86
|
+
* - Fresh handleStore (prevents polluting the response stream)
|
|
87
|
+
* - Fresh handlerContext + loaderPromises (prevents reusing memoized
|
|
88
|
+
* loader results from the foreground pass)
|
|
89
|
+
* - handleStore is saved/restored in try/finally
|
|
101
90
|
*
|
|
91
|
+
* This matches the proactive caching pattern in cache-store.ts.
|
|
102
92
|
*
|
|
103
|
-
* FULL VS PARTIAL REVALIDATION
|
|
104
|
-
* ============================
|
|
105
93
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* - No need to compare with previous state
|
|
94
|
+
* FRESH RESOLUTION (NO REVALIDATION)
|
|
95
|
+
* ===================================
|
|
109
96
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
97
|
+
* Both full and partial requests use resolveAllSegments() (without
|
|
98
|
+
* revalidation logic) to ensure all segments have complete components.
|
|
99
|
+
* Using revalidation-aware resolution would produce null components
|
|
100
|
+
* for skipped segments, which would corrupt the cache entry.
|
|
114
101
|
*/
|
|
115
102
|
import type { ResolvedSegment } from "../../types.js";
|
|
116
103
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
117
104
|
import { getRouterContext } from "../router-context.js";
|
|
118
105
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
119
|
-
import { debugLog, debugWarn } from "../logging.js";
|
|
106
|
+
import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
|
|
107
|
+
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
120
108
|
|
|
121
109
|
/**
|
|
122
110
|
* Creates background revalidation middleware
|
|
@@ -128,10 +116,10 @@ import { debugLog, debugWarn } from "../logging.js";
|
|
|
128
116
|
*/
|
|
129
117
|
export function withBackgroundRevalidation<TEnv>(
|
|
130
118
|
ctx: MatchContext<TEnv>,
|
|
131
|
-
state: MatchPipelineState
|
|
119
|
+
state: MatchPipelineState,
|
|
132
120
|
): GeneratorMiddleware<ResolvedSegment> {
|
|
133
121
|
return async function* (
|
|
134
|
-
source: AsyncGenerator<ResolvedSegment
|
|
122
|
+
source: AsyncGenerator<ResolvedSegment>,
|
|
135
123
|
): AsyncGenerator<ResolvedSegment> {
|
|
136
124
|
// Pass through all segments unchanged
|
|
137
125
|
for await (const segment of source) {
|
|
@@ -148,95 +136,104 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
148
136
|
const {
|
|
149
137
|
getRequestContext,
|
|
150
138
|
createHandleStore,
|
|
151
|
-
|
|
139
|
+
createHandlerContext,
|
|
140
|
+
setupLoaderAccess,
|
|
152
141
|
resolveAllSegments,
|
|
153
142
|
resolveInterceptEntry,
|
|
154
143
|
} = getRouterContext<TEnv>();
|
|
155
144
|
|
|
156
145
|
const requestCtx = getRequestContext();
|
|
157
146
|
const cacheScope = ctx.cacheScope;
|
|
147
|
+
const reqId = INTERNAL_RANGO_DEBUG
|
|
148
|
+
? getOrCreateRequestId(ctx.request)
|
|
149
|
+
: undefined;
|
|
158
150
|
|
|
159
151
|
requestCtx?.waitUntil(async () => {
|
|
152
|
+
const start = performance.now();
|
|
160
153
|
debugLog("backgroundRevalidation", "revalidating stale route", {
|
|
161
154
|
pathname: ctx.pathname,
|
|
162
155
|
fullMatch: ctx.isFullMatch,
|
|
163
156
|
});
|
|
164
|
-
try {
|
|
165
|
-
// Create a fresh handleStore for background revalidation
|
|
166
|
-
// to avoid polluting the current response's handle stream
|
|
167
|
-
if (requestCtx) {
|
|
168
|
-
requestCtx._handleStore = createHandleStore();
|
|
169
|
-
}
|
|
170
157
|
|
|
171
|
-
|
|
158
|
+
// Save and replace handleStore to avoid polluting the response stream.
|
|
159
|
+
// Restore in finally (same pattern as proactive caching in cache-store).
|
|
160
|
+
const originalHandleStore = requestCtx._handleStore;
|
|
161
|
+
requestCtx._handleStore = createHandleStore();
|
|
172
162
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
163
|
+
try {
|
|
164
|
+
// Create fresh handler context and loader promises to avoid
|
|
165
|
+
// reusing memoized results from the foreground pass
|
|
166
|
+
const freshHandlerContext = createHandlerContext(
|
|
167
|
+
ctx.matched.params,
|
|
168
|
+
ctx.request,
|
|
169
|
+
ctx.url.searchParams,
|
|
170
|
+
ctx.pathname,
|
|
171
|
+
ctx.url,
|
|
172
|
+
ctx.env,
|
|
173
|
+
ctx.routeMap,
|
|
174
|
+
ctx.matched.routeKey,
|
|
175
|
+
ctx.matched.responseType,
|
|
176
|
+
ctx.matched.pt === true,
|
|
177
|
+
);
|
|
178
|
+
const freshLoaderPromises = new Map<string, Promise<any>>();
|
|
179
|
+
setupLoaderAccess(freshHandlerContext, freshLoaderPromises);
|
|
180
|
+
|
|
181
|
+
// Resolve all segments fresh (without revalidation logic)
|
|
182
|
+
// to ensure complete components for caching
|
|
183
|
+
const freshSegments = await ctx.Store.run(() =>
|
|
184
|
+
resolveAllSegments(
|
|
185
185
|
ctx.entries,
|
|
186
186
|
ctx.routeKey,
|
|
187
187
|
ctx.matched.params,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
ctx.prevUrl,
|
|
193
|
-
ctx.url,
|
|
194
|
-
ctx.loaderPromises,
|
|
195
|
-
ctx.actionContext,
|
|
196
|
-
ctx.interceptResult,
|
|
197
|
-
ctx.localRouteName,
|
|
198
|
-
ctx.pathname
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
freshSegments = freshResult.segments;
|
|
188
|
+
freshHandlerContext,
|
|
189
|
+
freshLoaderPromises,
|
|
190
|
+
),
|
|
191
|
+
);
|
|
202
192
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
193
|
+
// Also resolve intercept segments fresh if applicable
|
|
194
|
+
let freshInterceptSegments: ResolvedSegment[] = [];
|
|
195
|
+
if (ctx.interceptResult) {
|
|
196
|
+
freshInterceptSegments = await ctx.Store.run(() =>
|
|
197
|
+
resolveInterceptEntry(
|
|
198
|
+
ctx.interceptResult!.intercept,
|
|
199
|
+
ctx.interceptResult!.entry,
|
|
208
200
|
ctx.matched.params,
|
|
209
|
-
|
|
201
|
+
freshHandlerContext,
|
|
210
202
|
true,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
prevParams: ctx.prevParams,
|
|
214
|
-
request: ctx.request,
|
|
215
|
-
prevUrl: ctx.prevUrl,
|
|
216
|
-
nextUrl: ctx.url,
|
|
217
|
-
routeKey: ctx.routeKey,
|
|
218
|
-
actionContext: ctx.actionContext,
|
|
219
|
-
stale: false,
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
freshSegments = [...freshSegments, ...freshInterceptSegments];
|
|
223
|
-
}
|
|
203
|
+
),
|
|
204
|
+
);
|
|
224
205
|
}
|
|
225
206
|
|
|
207
|
+
const completeSegments = [...freshSegments, ...freshInterceptSegments];
|
|
208
|
+
requestCtx._handleStore.seal();
|
|
226
209
|
await cacheScope.cacheRoute(
|
|
227
210
|
ctx.pathname,
|
|
228
211
|
ctx.matched.params,
|
|
229
|
-
|
|
230
|
-
ctx.isIntercept
|
|
212
|
+
completeSegments,
|
|
213
|
+
ctx.isIntercept,
|
|
231
214
|
);
|
|
215
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
216
|
+
const dur = performance.now() - start;
|
|
217
|
+
console.log(
|
|
218
|
+
`[RSC Background][req:${reqId}] SWR revalidation ${ctx.pathname} (${dur.toFixed(2)}ms) segments=${completeSegments.length}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
232
221
|
debugLog("backgroundRevalidation", "revalidation complete", {
|
|
233
222
|
pathname: ctx.pathname,
|
|
234
223
|
});
|
|
235
224
|
} catch (error) {
|
|
225
|
+
if (INTERNAL_RANGO_DEBUG) {
|
|
226
|
+
const dur = performance.now() - start;
|
|
227
|
+
console.log(
|
|
228
|
+
`[RSC Background][req:${reqId}] SWR revalidation ${ctx.pathname} FAILED (${dur.toFixed(2)}ms) error=${String(error)}`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
236
231
|
debugWarn("backgroundRevalidation", "revalidation failed", {
|
|
237
232
|
pathname: ctx.pathname,
|
|
238
233
|
error: String(error),
|
|
239
234
|
});
|
|
235
|
+
} finally {
|
|
236
|
+
requestCtx._handleStore = originalHandleStore;
|
|
240
237
|
}
|
|
241
238
|
});
|
|
242
239
|
};
|