@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.80

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.
Files changed (312) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +942 -4
  3. package/dist/bin/rango.js +1689 -0
  4. package/dist/vite/index.js +4960 -935
  5. package/package.json +70 -60
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +294 -0
  8. package/skills/caching/SKILL.md +93 -23
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +18 -16
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/handler-use/SKILL.md +362 -0
  14. package/skills/hooks/SKILL.md +334 -72
  15. package/skills/host-router/SKILL.md +218 -0
  16. package/skills/intercept/SKILL.md +151 -8
  17. package/skills/layout/SKILL.md +122 -3
  18. package/skills/links/SKILL.md +92 -31
  19. package/skills/loader/SKILL.md +404 -44
  20. package/skills/middleware/SKILL.md +205 -37
  21. package/skills/migrate-nextjs/SKILL.md +560 -0
  22. package/skills/migrate-react-router/SKILL.md +764 -0
  23. package/skills/mime-routes/SKILL.md +128 -0
  24. package/skills/parallel/SKILL.md +263 -1
  25. package/skills/prerender/SKILL.md +685 -0
  26. package/skills/rango/SKILL.md +87 -16
  27. package/skills/response-routes/SKILL.md +411 -0
  28. package/skills/route/SKILL.md +281 -14
  29. package/skills/router-setup/SKILL.md +210 -32
  30. package/skills/tailwind/SKILL.md +129 -0
  31. package/skills/theme/SKILL.md +9 -8
  32. package/skills/typesafety/SKILL.md +328 -89
  33. package/skills/use-cache/SKILL.md +324 -0
  34. package/src/__internal.ts +102 -4
  35. package/src/bin/rango.ts +321 -0
  36. package/src/browser/action-coordinator.ts +97 -0
  37. package/src/browser/action-response-classifier.ts +99 -0
  38. package/src/browser/app-version.ts +14 -0
  39. package/src/browser/event-controller.ts +92 -64
  40. package/src/browser/history-state.ts +80 -0
  41. package/src/browser/intercept-utils.ts +52 -0
  42. package/src/browser/link-interceptor.ts +24 -4
  43. package/src/browser/logging.ts +55 -0
  44. package/src/browser/merge-segment-loaders.ts +20 -12
  45. package/src/browser/navigation-bridge.ts +317 -560
  46. package/src/browser/navigation-client.ts +206 -68
  47. package/src/browser/navigation-store.ts +73 -55
  48. package/src/browser/navigation-transaction.ts +297 -0
  49. package/src/browser/network-error-handler.ts +61 -0
  50. package/src/browser/partial-update.ts +343 -316
  51. package/src/browser/prefetch/cache.ts +216 -0
  52. package/src/browser/prefetch/fetch.ts +206 -0
  53. package/src/browser/prefetch/observer.ts +65 -0
  54. package/src/browser/prefetch/policy.ts +48 -0
  55. package/src/browser/prefetch/queue.ts +160 -0
  56. package/src/browser/prefetch/resource-ready.ts +77 -0
  57. package/src/browser/rango-state.ts +112 -0
  58. package/src/browser/react/Link.tsx +253 -74
  59. package/src/browser/react/NavigationProvider.tsx +87 -11
  60. package/src/browser/react/context.ts +11 -0
  61. package/src/browser/react/filter-segment-order.ts +11 -0
  62. package/src/browser/react/index.ts +12 -12
  63. package/src/browser/react/location-state-shared.ts +95 -53
  64. package/src/browser/react/location-state.ts +60 -15
  65. package/src/browser/react/mount-context.ts +6 -1
  66. package/src/browser/react/nonce-context.ts +23 -0
  67. package/src/browser/react/shallow-equal.ts +27 -0
  68. package/src/browser/react/use-action.ts +29 -51
  69. package/src/browser/react/use-client-cache.ts +5 -3
  70. package/src/browser/react/use-handle.ts +30 -126
  71. package/src/browser/react/use-href.tsx +2 -2
  72. package/src/browser/react/use-link-status.ts +6 -5
  73. package/src/browser/react/use-navigation.ts +44 -65
  74. package/src/browser/react/use-params.ts +65 -0
  75. package/src/browser/react/use-pathname.ts +47 -0
  76. package/src/browser/react/use-router.ts +76 -0
  77. package/src/browser/react/use-search-params.ts +56 -0
  78. package/src/browser/react/use-segments.ts +80 -97
  79. package/src/browser/response-adapter.ts +73 -0
  80. package/src/browser/rsc-router.tsx +214 -58
  81. package/src/browser/scroll-restoration.ts +127 -52
  82. package/src/browser/segment-reconciler.ts +243 -0
  83. package/src/browser/segment-structure-assert.ts +16 -0
  84. package/src/browser/server-action-bridge.ts +510 -603
  85. package/src/browser/shallow.ts +6 -1
  86. package/src/browser/types.ts +141 -48
  87. package/src/browser/validate-redirect-origin.ts +29 -0
  88. package/src/build/generate-manifest.ts +235 -24
  89. package/src/build/generate-route-types.ts +39 -0
  90. package/src/build/index.ts +13 -0
  91. package/src/build/route-trie.ts +291 -0
  92. package/src/build/route-types/ast-helpers.ts +25 -0
  93. package/src/build/route-types/ast-route-extraction.ts +98 -0
  94. package/src/build/route-types/codegen.ts +102 -0
  95. package/src/build/route-types/include-resolution.ts +418 -0
  96. package/src/build/route-types/param-extraction.ts +48 -0
  97. package/src/build/route-types/per-module-writer.ts +128 -0
  98. package/src/build/route-types/router-processing.ts +618 -0
  99. package/src/build/route-types/scan-filter.ts +85 -0
  100. package/src/build/runtime-discovery.ts +231 -0
  101. package/src/cache/background-task.ts +34 -0
  102. package/src/cache/cache-key-utils.ts +44 -0
  103. package/src/cache/cache-policy.ts +125 -0
  104. package/src/cache/cache-runtime.ts +342 -0
  105. package/src/cache/cache-scope.ts +167 -309
  106. package/src/cache/cf/cf-cache-store.ts +571 -17
  107. package/src/cache/cf/index.ts +13 -3
  108. package/src/cache/document-cache.ts +116 -77
  109. package/src/cache/handle-capture.ts +81 -0
  110. package/src/cache/handle-snapshot.ts +41 -0
  111. package/src/cache/index.ts +1 -15
  112. package/src/cache/memory-segment-store.ts +191 -13
  113. package/src/cache/profile-registry.ts +73 -0
  114. package/src/cache/read-through-swr.ts +134 -0
  115. package/src/cache/segment-codec.ts +256 -0
  116. package/src/cache/taint.ts +153 -0
  117. package/src/cache/types.ts +72 -122
  118. package/src/client.rsc.tsx +3 -1
  119. package/src/client.tsx +135 -301
  120. package/src/component-utils.ts +4 -4
  121. package/src/components/DefaultDocument.tsx +5 -1
  122. package/src/context-var.ts +156 -0
  123. package/src/debug.ts +19 -9
  124. package/src/errors.ts +108 -2
  125. package/src/handle.ts +55 -29
  126. package/src/handles/MetaTags.tsx +73 -20
  127. package/src/handles/breadcrumbs.ts +66 -0
  128. package/src/handles/index.ts +1 -0
  129. package/src/handles/meta.ts +30 -13
  130. package/src/host/cookie-handler.ts +21 -15
  131. package/src/host/errors.ts +8 -8
  132. package/src/host/index.ts +4 -7
  133. package/src/host/pattern-matcher.ts +27 -27
  134. package/src/host/router.ts +61 -39
  135. package/src/host/testing.ts +8 -8
  136. package/src/host/types.ts +15 -7
  137. package/src/host/utils.ts +1 -1
  138. package/src/href-client.ts +119 -29
  139. package/src/index.rsc.ts +155 -19
  140. package/src/index.ts +251 -30
  141. package/src/internal-debug.ts +11 -0
  142. package/src/loader.rsc.ts +26 -157
  143. package/src/loader.ts +27 -10
  144. package/src/network-error-thrower.tsx +3 -1
  145. package/src/outlet-provider.tsx +45 -0
  146. package/src/prerender/param-hash.ts +37 -0
  147. package/src/prerender/store.ts +186 -0
  148. package/src/prerender.ts +524 -0
  149. package/src/reverse.ts +354 -0
  150. package/src/root-error-boundary.tsx +41 -29
  151. package/src/route-content-wrapper.tsx +7 -4
  152. package/src/route-definition/dsl-helpers.ts +1121 -0
  153. package/src/route-definition/helper-factories.ts +200 -0
  154. package/src/route-definition/helpers-types.ts +478 -0
  155. package/src/route-definition/index.ts +55 -0
  156. package/src/route-definition/redirect.ts +101 -0
  157. package/src/route-definition/resolve-handler-use.ts +149 -0
  158. package/src/route-definition.ts +1 -1428
  159. package/src/route-map-builder.ts +217 -123
  160. package/src/route-name.ts +53 -0
  161. package/src/route-types.ts +77 -8
  162. package/src/router/content-negotiation.ts +215 -0
  163. package/src/router/debug-manifest.ts +72 -0
  164. package/src/router/error-handling.ts +9 -9
  165. package/src/router/find-match.ts +160 -0
  166. package/src/router/handler-context.ts +438 -86
  167. package/src/router/intercept-resolution.ts +402 -0
  168. package/src/router/lazy-includes.ts +237 -0
  169. package/src/router/loader-resolution.ts +356 -128
  170. package/src/router/logging.ts +251 -0
  171. package/src/router/manifest.ts +163 -35
  172. package/src/router/match-api.ts +555 -0
  173. package/src/router/match-context.ts +5 -3
  174. package/src/router/match-handlers.ts +440 -0
  175. package/src/router/match-middleware/background-revalidation.ts +108 -93
  176. package/src/router/match-middleware/cache-lookup.ts +460 -10
  177. package/src/router/match-middleware/cache-store.ts +98 -26
  178. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  179. package/src/router/match-middleware/segment-resolution.ts +80 -6
  180. package/src/router/match-pipelines.ts +10 -45
  181. package/src/router/match-result.ts +135 -35
  182. package/src/router/metrics.ts +240 -15
  183. package/src/router/middleware-cookies.ts +55 -0
  184. package/src/router/middleware-types.ts +220 -0
  185. package/src/router/middleware.ts +324 -369
  186. package/src/router/navigation-snapshot.ts +182 -0
  187. package/src/router/pattern-matching.ts +211 -43
  188. package/src/router/prerender-match.ts +502 -0
  189. package/src/router/preview-match.ts +98 -0
  190. package/src/router/request-classification.ts +310 -0
  191. package/src/router/revalidation.ts +137 -38
  192. package/src/router/route-snapshot.ts +245 -0
  193. package/src/router/router-context.ts +41 -21
  194. package/src/router/router-interfaces.ts +484 -0
  195. package/src/router/router-options.ts +618 -0
  196. package/src/router/router-registry.ts +24 -0
  197. package/src/router/segment-resolution/fresh.ts +748 -0
  198. package/src/router/segment-resolution/helpers.ts +268 -0
  199. package/src/router/segment-resolution/loader-cache.ts +199 -0
  200. package/src/router/segment-resolution/revalidation.ts +1379 -0
  201. package/src/router/segment-resolution/static-store.ts +67 -0
  202. package/src/router/segment-resolution.ts +21 -0
  203. package/src/router/segment-wrappers.ts +291 -0
  204. package/src/router/telemetry-otel.ts +299 -0
  205. package/src/router/telemetry.ts +300 -0
  206. package/src/router/timeout.ts +148 -0
  207. package/src/router/trie-matching.ts +239 -0
  208. package/src/router/types.ts +78 -3
  209. package/src/router.ts +740 -4252
  210. package/src/rsc/handler-context.ts +45 -0
  211. package/src/rsc/handler.ts +907 -797
  212. package/src/rsc/helpers.ts +140 -6
  213. package/src/rsc/index.ts +0 -20
  214. package/src/rsc/loader-fetch.ts +229 -0
  215. package/src/rsc/manifest-init.ts +90 -0
  216. package/src/rsc/nonce.ts +14 -0
  217. package/src/rsc/origin-guard.ts +141 -0
  218. package/src/rsc/progressive-enhancement.ts +391 -0
  219. package/src/rsc/response-error.ts +37 -0
  220. package/src/rsc/response-route-handler.ts +347 -0
  221. package/src/rsc/rsc-rendering.ts +246 -0
  222. package/src/rsc/runtime-warnings.ts +42 -0
  223. package/src/rsc/server-action.ts +356 -0
  224. package/src/rsc/ssr-setup.ts +128 -0
  225. package/src/rsc/types.ts +46 -11
  226. package/src/search-params.ts +230 -0
  227. package/src/segment-content-promise.ts +67 -0
  228. package/src/segment-loader-promise.ts +122 -0
  229. package/src/segment-system.tsx +134 -36
  230. package/src/server/context.ts +341 -61
  231. package/src/server/cookie-store.ts +190 -0
  232. package/src/server/fetchable-loader-store.ts +37 -0
  233. package/src/server/handle-store.ts +113 -15
  234. package/src/server/loader-registry.ts +24 -64
  235. package/src/server/request-context.ts +607 -81
  236. package/src/server.ts +35 -130
  237. package/src/ssr/index.tsx +103 -30
  238. package/src/static-handler.ts +126 -0
  239. package/src/theme/ThemeProvider.tsx +21 -15
  240. package/src/theme/ThemeScript.tsx +5 -5
  241. package/src/theme/constants.ts +5 -2
  242. package/src/theme/index.ts +4 -14
  243. package/src/theme/theme-context.ts +4 -30
  244. package/src/theme/theme-script.ts +21 -18
  245. package/src/types/boundaries.ts +158 -0
  246. package/src/types/cache-types.ts +198 -0
  247. package/src/types/error-types.ts +192 -0
  248. package/src/types/global-namespace.ts +100 -0
  249. package/src/types/handler-context.ts +791 -0
  250. package/src/types/index.ts +88 -0
  251. package/src/types/loader-types.ts +210 -0
  252. package/src/types/route-config.ts +170 -0
  253. package/src/types/route-entry.ts +120 -0
  254. package/src/types/segments.ts +150 -0
  255. package/src/types.ts +1 -1623
  256. package/src/urls/include-helper.ts +207 -0
  257. package/src/urls/index.ts +53 -0
  258. package/src/urls/path-helper-types.ts +372 -0
  259. package/src/urls/path-helper.ts +364 -0
  260. package/src/urls/pattern-types.ts +107 -0
  261. package/src/urls/response-types.ts +116 -0
  262. package/src/urls/type-extraction.ts +372 -0
  263. package/src/urls/urls-function.ts +98 -0
  264. package/src/urls.ts +1 -802
  265. package/src/use-loader.tsx +161 -81
  266. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  267. package/src/vite/discovery/discover-routers.ts +348 -0
  268. package/src/vite/discovery/prerender-collection.ts +439 -0
  269. package/src/vite/discovery/route-types-writer.ts +258 -0
  270. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  271. package/src/vite/discovery/state.ts +117 -0
  272. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  273. package/src/vite/index.ts +15 -1133
  274. package/src/vite/plugin-types.ts +103 -0
  275. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  276. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  277. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  278. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  279. package/src/vite/plugins/expose-id-utils.ts +299 -0
  280. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  281. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  282. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  283. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  284. package/src/vite/plugins/expose-ids/types.ts +45 -0
  285. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  286. package/src/vite/plugins/performance-tracks.ts +88 -0
  287. package/src/vite/plugins/refresh-cmd.ts +127 -0
  288. package/src/vite/plugins/use-cache-transform.ts +323 -0
  289. package/src/vite/plugins/version-injector.ts +83 -0
  290. package/src/vite/plugins/version-plugin.ts +266 -0
  291. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  292. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  293. package/src/vite/rango.ts +462 -0
  294. package/src/vite/router-discovery.ts +918 -0
  295. package/src/vite/utils/ast-handler-extract.ts +517 -0
  296. package/src/vite/utils/banner.ts +36 -0
  297. package/src/vite/utils/bundle-analysis.ts +137 -0
  298. package/src/vite/utils/manifest-utils.ts +70 -0
  299. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  300. package/src/vite/utils/prerender-utils.ts +221 -0
  301. package/src/vite/utils/shared-utils.ts +170 -0
  302. package/CLAUDE.md +0 -43
  303. package/src/browser/lru-cache.ts +0 -69
  304. package/src/browser/request-controller.ts +0 -164
  305. package/src/cache/memory-store.ts +0 -253
  306. package/src/href-context.ts +0 -33
  307. package/src/href.ts +0 -255
  308. package/src/server/route-manifest-cache.ts +0 -173
  309. package/src/vite/expose-handle-id.ts +0 -209
  310. package/src/vite/expose-loader-id.ts +0 -426
  311. package/src/vite/expose-location-state-id.ts +0 -177
  312. /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
+ }