@rangojs/router 0.0.0-experimental.0f44aca1
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 +899 -0
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +5214 -0
- package/package.json +176 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +220 -0
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +182 -0
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +704 -0
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +313 -0
- package/skills/layout/SKILL.md +310 -0
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +596 -0
- package/skills/middleware/SKILL.md +339 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +305 -0
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +118 -0
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +385 -0
- package/skills/router-setup/SKILL.md +439 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +79 -0
- package/skills/typesafety/SKILL.md +623 -0
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +273 -0
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +899 -0
- package/src/browser/history-state.ts +80 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +141 -0
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +134 -0
- package/src/browser/navigation-bridge.ts +645 -0
- package/src/browser/navigation-client.ts +215 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +550 -0
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +360 -0
- package/src/browser/react/NavigationProvider.tsx +386 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +59 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +162 -0
- package/src/browser/react/location-state.ts +107 -0
- package/src/browser/react/mount-context.ts +37 -0
- 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 +218 -0
- package/src/browser/react/use-client-cache.ts +58 -0
- package/src/browser/react/use-handle.ts +162 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +135 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +99 -0
- 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 +171 -0
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +431 -0
- package/src/browser/scroll-restoration.ts +400 -0
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +667 -0
- package/src/browser/shallow.ts +40 -0
- package/src/browser/types.ts +538 -0
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -0
- package/src/build/route-trie.ts +265 -0
- 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 +382 -0
- package/src/cache/cf/cf-cache-store.ts +540 -0
- package/src/cache/cf/index.ts +25 -0
- package/src/cache/document-cache.ts +369 -0
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +43 -0
- package/src/cache/memory-segment-store.ts +328 -0
- 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 +342 -0
- package/src/client.rsc.tsx +85 -0
- package/src/client.tsx +601 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +27 -0
- package/src/context-var.ts +86 -0
- package/src/debug.ts +243 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +365 -0
- package/src/handle.ts +135 -0
- package/src/handles/MetaTags.tsx +246 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +7 -0
- package/src/handles/meta.ts +264 -0
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +222 -0
- package/src/index.rsc.ts +233 -0
- package/src/index.ts +277 -0
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +89 -0
- package/src/loader.ts +64 -0
- package/src/network-error-thrower.tsx +23 -0
- package/src/outlet-context.ts +15 -0
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +289 -0
- package/src/route-content-wrapper.tsx +196 -0
- 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 -0
- package/src/route-map-builder.ts +275 -0
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +259 -0
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/find-match.ts +158 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +267 -0
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +266 -0
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +223 -0
- package/src/router/match-middleware/cache-lookup.ts +634 -0
- package/src/router/match-middleware/cache-store.ts +295 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +306 -0
- package/src/router/match-middleware/segment-resolution.ts +192 -0
- package/src/router/match-pipelines.ts +179 -0
- package/src/router/match-result.ts +219 -0
- package/src/router/metrics.ts +282 -0
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +748 -0
- package/src/router/pattern-matching.ts +563 -0
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +289 -0
- package/src/router/router-context.ts +316 -0
- 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 -0
- 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 +239 -0
- package/src/router/types.ts +170 -0
- package/src/router.ts +1002 -0
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +1089 -0
- package/src/rsc/helpers.ts +198 -0
- package/src/rsc/index.ts +36 -0
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +32 -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 +235 -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 +263 -0
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +454 -0
- package/src/server/context.ts +591 -0
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +308 -0
- package/src/server/loader-registry.ts +133 -0
- package/src/server/request-context.ts +914 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +51 -0
- package/src/ssr/index.tsx +365 -0
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +297 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +62 -0
- package/src/theme/index.ts +48 -0
- package/src/theme/theme-context.ts +44 -0
- package/src/theme/theme-script.ts +155 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- 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 -0
- 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 -0
- package/src/use-loader.tsx +354 -0
- 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 +16 -0
- 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/plugins/expose-action-id.ts +365 -0
- 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/plugins/version.d.ts +12 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- 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/utils/package-resolution.ts +121 -0
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match Context for Router Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates all state needed by the match pipeline middleware.
|
|
5
|
+
* Created once at the start of match()/matchPartial() and passed through the pipeline.
|
|
6
|
+
*
|
|
7
|
+
* DATA FLOW ARCHITECTURE
|
|
8
|
+
* ======================
|
|
9
|
+
*
|
|
10
|
+
* The router uses two complementary data structures:
|
|
11
|
+
*
|
|
12
|
+
* MatchContext (ctx) - Immutable request state
|
|
13
|
+
* MatchPipelineState (state) - Mutable pipeline state
|
|
14
|
+
*
|
|
15
|
+
*
|
|
16
|
+
* Request
|
|
17
|
+
* |
|
|
18
|
+
* v
|
|
19
|
+
* +-------------------+
|
|
20
|
+
* | Create Context | ctx = immutable snapshot of request
|
|
21
|
+
* +-------------------+
|
|
22
|
+
* |
|
|
23
|
+
* v
|
|
24
|
+
* +-------------------+
|
|
25
|
+
* | Create State | state = mutable accumulator
|
|
26
|
+
* +-------------------+
|
|
27
|
+
* |
|
|
28
|
+
* +---> [Pipeline Middleware]
|
|
29
|
+
* | |
|
|
30
|
+
* | ctx: read-only
|
|
31
|
+
* | state: read/write
|
|
32
|
+
* | |
|
|
33
|
+
* +<----------+
|
|
34
|
+
* |
|
|
35
|
+
* v
|
|
36
|
+
* +-------------------+
|
|
37
|
+
* | Build Result | Merge ctx + state into MatchResult
|
|
38
|
+
* +-------------------+
|
|
39
|
+
*
|
|
40
|
+
*
|
|
41
|
+
* MATCHCONTEXT FIELDS
|
|
42
|
+
* ===================
|
|
43
|
+
*
|
|
44
|
+
* Request Info:
|
|
45
|
+
* - request, url, pathname: The incoming HTTP request
|
|
46
|
+
*
|
|
47
|
+
* Environment:
|
|
48
|
+
* - env: Server environment (Cloudflare bindings, etc.)
|
|
49
|
+
*
|
|
50
|
+
* Client State (from RSC request headers):
|
|
51
|
+
* - clientSegmentIds: Segments the client currently has
|
|
52
|
+
* - clientSegmentSet: Set version for O(1) lookup
|
|
53
|
+
* - stale: Whether client considers its cache stale
|
|
54
|
+
*
|
|
55
|
+
* Navigation State:
|
|
56
|
+
* - prevUrl, prevParams, prevMatch: Previous navigation for comparison
|
|
57
|
+
*
|
|
58
|
+
* Current Match:
|
|
59
|
+
* - matched: Route match result (params, route key)
|
|
60
|
+
* - manifestEntry: Resolved manifest data
|
|
61
|
+
* - entries: All route entries (layouts, loaders, etc.)
|
|
62
|
+
* - routeKey, localRouteName: Route identifiers
|
|
63
|
+
*
|
|
64
|
+
* Handler Context:
|
|
65
|
+
* - handlerContext: Context passed to loaders
|
|
66
|
+
* - loaderPromises: Memoized loader promises
|
|
67
|
+
*
|
|
68
|
+
* Intercepts:
|
|
69
|
+
* - interceptResult: Detected intercept (if soft navigation)
|
|
70
|
+
* - interceptSelectorContext: Context for intercept matching
|
|
71
|
+
*
|
|
72
|
+
* Cache:
|
|
73
|
+
* - cacheScope: Cache configuration and methods
|
|
74
|
+
* - isIntercept: Whether this is an intercept request
|
|
75
|
+
*
|
|
76
|
+
* Flags:
|
|
77
|
+
* - isAction: POST/mutation request
|
|
78
|
+
* - isFullMatch: Document request vs navigation
|
|
79
|
+
*
|
|
80
|
+
*
|
|
81
|
+
* MATCHPIPELINESTATE FIELDS
|
|
82
|
+
* =========================
|
|
83
|
+
*
|
|
84
|
+
* State flags (set by middleware, read by others):
|
|
85
|
+
* - cacheHit: Cache lookup succeeded
|
|
86
|
+
* - shouldRevalidate: SWR revalidation needed
|
|
87
|
+
*
|
|
88
|
+
* Segment accumulation:
|
|
89
|
+
* - segments: Resolved segments from pipeline
|
|
90
|
+
* - matchedIds: All segment IDs in match order
|
|
91
|
+
* - cachedSegments: Segments from cache (if hit)
|
|
92
|
+
*
|
|
93
|
+
* Intercept data:
|
|
94
|
+
* - interceptSegments: Segments for modal slots
|
|
95
|
+
* - slots: Named slot data for client
|
|
96
|
+
*
|
|
97
|
+
*
|
|
98
|
+
* IMMUTABILITY CONTRACT
|
|
99
|
+
* =====================
|
|
100
|
+
*
|
|
101
|
+
* MatchContext is treated as immutable after creation.
|
|
102
|
+
* Middleware should NEVER modify ctx properties.
|
|
103
|
+
*
|
|
104
|
+
* MatchPipelineState is explicitly mutable.
|
|
105
|
+
* Middleware communicate by setting state flags.
|
|
106
|
+
*
|
|
107
|
+
* This separation ensures:
|
|
108
|
+
* - Request data is consistent across all middleware
|
|
109
|
+
* - Pipeline state changes are explicit and trackable
|
|
110
|
+
* - No hidden side effects in request handling
|
|
111
|
+
*/
|
|
112
|
+
import type { CacheScope } from "../cache/cache-scope.js";
|
|
113
|
+
import type {
|
|
114
|
+
EntryData,
|
|
115
|
+
InterceptSelectorContext,
|
|
116
|
+
MetricsStore,
|
|
117
|
+
} from "../server/context.js";
|
|
118
|
+
import type { HandlerContext, ResolvedSegment } from "../types.js";
|
|
119
|
+
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
120
|
+
import type { InterceptResult } from "./router-context.js";
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Action context passed to matchPartial
|
|
124
|
+
*/
|
|
125
|
+
export interface ActionContext {
|
|
126
|
+
actionId?: string;
|
|
127
|
+
actionUrl?: URL;
|
|
128
|
+
actionResult?: any;
|
|
129
|
+
formData?: FormData;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Match context containing all state for the match pipeline
|
|
134
|
+
*/
|
|
135
|
+
export interface MatchContext<TEnv = any> {
|
|
136
|
+
// Request info
|
|
137
|
+
request: Request;
|
|
138
|
+
url: URL;
|
|
139
|
+
pathname: string;
|
|
140
|
+
|
|
141
|
+
// Environment
|
|
142
|
+
env: TEnv;
|
|
143
|
+
|
|
144
|
+
// Client state
|
|
145
|
+
clientSegmentIds: string[];
|
|
146
|
+
clientSegmentSet: Set<string>;
|
|
147
|
+
stale: boolean;
|
|
148
|
+
|
|
149
|
+
// Previous navigation state
|
|
150
|
+
prevUrl: URL;
|
|
151
|
+
prevParams: Record<string, string>;
|
|
152
|
+
prevMatch: RouteMatchResult | null;
|
|
153
|
+
|
|
154
|
+
// Current route match
|
|
155
|
+
matched: RouteMatchResult;
|
|
156
|
+
manifestEntry: EntryData;
|
|
157
|
+
entries: EntryData[];
|
|
158
|
+
routeKey: string;
|
|
159
|
+
localRouteName: string;
|
|
160
|
+
|
|
161
|
+
// Handler context (for loaders)
|
|
162
|
+
handlerContext: HandlerContext<any, TEnv>;
|
|
163
|
+
loaderPromises: Map<string, Promise<any>>;
|
|
164
|
+
|
|
165
|
+
// Route map for server-side ctx.reverse() resolution
|
|
166
|
+
routeMap: Record<string, string>;
|
|
167
|
+
|
|
168
|
+
// Metrics
|
|
169
|
+
metricsStore: MetricsStore | undefined;
|
|
170
|
+
|
|
171
|
+
// Store for running within context
|
|
172
|
+
Store: any;
|
|
173
|
+
|
|
174
|
+
// Intercept detection
|
|
175
|
+
interceptContextMatch: RouteMatchResult | null;
|
|
176
|
+
interceptSelectorContext: InterceptSelectorContext;
|
|
177
|
+
isSameRouteNavigation: boolean;
|
|
178
|
+
interceptResult: InterceptResult | null;
|
|
179
|
+
|
|
180
|
+
// Cache
|
|
181
|
+
cacheScope: CacheScope | null;
|
|
182
|
+
isIntercept: boolean;
|
|
183
|
+
|
|
184
|
+
// Action context (if this is an action)
|
|
185
|
+
actionContext?: ActionContext;
|
|
186
|
+
isAction: boolean;
|
|
187
|
+
|
|
188
|
+
// Route middleware
|
|
189
|
+
routeMiddleware: Array<{
|
|
190
|
+
handler: any;
|
|
191
|
+
params: Record<string, string>;
|
|
192
|
+
}>;
|
|
193
|
+
|
|
194
|
+
// Full match flag (document requests vs partial/navigation requests)
|
|
195
|
+
// When true, uses simpler resolution without revalidation logic
|
|
196
|
+
isFullMatch: boolean;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Mutable state that flows through the pipeline
|
|
201
|
+
*/
|
|
202
|
+
export interface MatchPipelineState {
|
|
203
|
+
// Whether cache was hit
|
|
204
|
+
cacheHit: boolean;
|
|
205
|
+
|
|
206
|
+
// Cached segments (if cache hit)
|
|
207
|
+
cachedSegments?: ResolvedSegment[];
|
|
208
|
+
cachedMatchedIds?: string[];
|
|
209
|
+
|
|
210
|
+
// Whether cache should be revalidated (SWR)
|
|
211
|
+
shouldRevalidate?: boolean;
|
|
212
|
+
|
|
213
|
+
// Source of cache hit ("runtime" or "prerender")
|
|
214
|
+
cacheSource?: "runtime" | "prerender";
|
|
215
|
+
|
|
216
|
+
// Resolved segments from pipeline
|
|
217
|
+
segments: ResolvedSegment[];
|
|
218
|
+
matchedIds: string[];
|
|
219
|
+
|
|
220
|
+
// Intercept segments
|
|
221
|
+
interceptSegments: ResolvedSegment[];
|
|
222
|
+
|
|
223
|
+
// Slots state
|
|
224
|
+
slots: Record<
|
|
225
|
+
string,
|
|
226
|
+
{
|
|
227
|
+
active: boolean;
|
|
228
|
+
segments: ResolvedSegment[];
|
|
229
|
+
}
|
|
230
|
+
>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Create initial pipeline state
|
|
235
|
+
*/
|
|
236
|
+
export function createPipelineState(): MatchPipelineState {
|
|
237
|
+
return {
|
|
238
|
+
cacheHit: false,
|
|
239
|
+
segments: [],
|
|
240
|
+
matchedIds: [],
|
|
241
|
+
interceptSegments: [],
|
|
242
|
+
slots: {},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Input parameters for createMatchContext
|
|
248
|
+
*/
|
|
249
|
+
export interface CreateMatchContextInput<TEnv = any> {
|
|
250
|
+
request: Request;
|
|
251
|
+
env: TEnv;
|
|
252
|
+
actionContext?: ActionContext;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Result from createMatchContext - either a context or null (fall back to full match)
|
|
257
|
+
*/
|
|
258
|
+
export type CreateMatchContextResult<TEnv = any> =
|
|
259
|
+
| { type: "context"; ctx: MatchContext<TEnv> }
|
|
260
|
+
| { type: "fallback"; reason: string }
|
|
261
|
+
| { type: "error"; error: Error };
|
|
262
|
+
|
|
263
|
+
// Note: createMatchContext() will be implemented in Step J10 when we wire everything together.
|
|
264
|
+
// It requires access to RouterContext (findMatch, loadManifest, etc.) which are closure
|
|
265
|
+
// functions from createRouter(). The implementation will live in router.ts initially
|
|
266
|
+
// and call getRouterContext() to access these dependencies.
|
|
@@ -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
|
+
}
|