@rangojs/router 0.0.0-experimental.9 → 0.0.0-experimental.91

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 (1125) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +972 -4
  3. package/dist/__internal.d.ts +83 -0
  4. package/dist/__internal.d.ts.map +1 -0
  5. package/dist/__internal.js +19 -0
  6. package/dist/__internal.js.map +1 -0
  7. package/dist/__mocks__/version.d.ts +7 -0
  8. package/dist/__mocks__/version.d.ts.map +1 -0
  9. package/dist/__mocks__/version.js +7 -0
  10. package/dist/__mocks__/version.js.map +1 -0
  11. package/dist/__tests__/client-href.test.d.ts +2 -0
  12. package/dist/__tests__/client-href.test.d.ts.map +1 -0
  13. package/dist/__tests__/client-href.test.js +74 -0
  14. package/dist/__tests__/client-href.test.js.map +1 -0
  15. package/dist/__tests__/component-utils.test.d.ts +2 -0
  16. package/dist/__tests__/component-utils.test.d.ts.map +1 -0
  17. package/dist/__tests__/component-utils.test.js +51 -0
  18. package/dist/__tests__/component-utils.test.js.map +1 -0
  19. package/dist/__tests__/event-controller.test.d.ts +2 -0
  20. package/dist/__tests__/event-controller.test.d.ts.map +1 -0
  21. package/dist/__tests__/event-controller.test.js +538 -0
  22. package/dist/__tests__/event-controller.test.js.map +1 -0
  23. package/dist/__tests__/helpers/route-tree.d.ts +118 -0
  24. package/dist/__tests__/helpers/route-tree.d.ts.map +1 -0
  25. package/dist/__tests__/helpers/route-tree.js +374 -0
  26. package/dist/__tests__/helpers/route-tree.js.map +1 -0
  27. package/dist/__tests__/match-result.test.d.ts +2 -0
  28. package/dist/__tests__/match-result.test.d.ts.map +1 -0
  29. package/dist/__tests__/match-result.test.js +154 -0
  30. package/dist/__tests__/match-result.test.js.map +1 -0
  31. package/dist/__tests__/navigation-store.test.d.ts +2 -0
  32. package/dist/__tests__/navigation-store.test.d.ts.map +1 -0
  33. package/dist/__tests__/navigation-store.test.js +440 -0
  34. package/dist/__tests__/navigation-store.test.js.map +1 -0
  35. package/dist/__tests__/partial-update.test.d.ts +2 -0
  36. package/dist/__tests__/partial-update.test.d.ts.map +1 -0
  37. package/dist/__tests__/partial-update.test.js +1009 -0
  38. package/dist/__tests__/partial-update.test.js.map +1 -0
  39. package/dist/__tests__/reverse-types.test.d.ts +8 -0
  40. package/dist/__tests__/reverse-types.test.d.ts.map +1 -0
  41. package/dist/__tests__/reverse-types.test.js +656 -0
  42. package/dist/__tests__/reverse-types.test.js.map +1 -0
  43. package/dist/__tests__/route-definition.test.d.ts +2 -0
  44. package/dist/__tests__/route-definition.test.d.ts.map +1 -0
  45. package/dist/__tests__/route-definition.test.js +55 -0
  46. package/dist/__tests__/route-definition.test.js.map +1 -0
  47. package/dist/__tests__/router-helpers.test.d.ts +2 -0
  48. package/dist/__tests__/router-helpers.test.d.ts.map +1 -0
  49. package/dist/__tests__/router-helpers.test.js +377 -0
  50. package/dist/__tests__/router-helpers.test.js.map +1 -0
  51. package/dist/__tests__/router-integration-2.test.d.ts +2 -0
  52. package/dist/__tests__/router-integration-2.test.d.ts.map +1 -0
  53. package/dist/__tests__/router-integration-2.test.js +426 -0
  54. package/dist/__tests__/router-integration-2.test.js.map +1 -0
  55. package/dist/__tests__/router-integration.test.d.ts +2 -0
  56. package/dist/__tests__/router-integration.test.d.ts.map +1 -0
  57. package/dist/__tests__/router-integration.test.js +1051 -0
  58. package/dist/__tests__/router-integration.test.js.map +1 -0
  59. package/dist/__tests__/search-params.test.d.ts +5 -0
  60. package/dist/__tests__/search-params.test.d.ts.map +1 -0
  61. package/dist/__tests__/search-params.test.js +306 -0
  62. package/dist/__tests__/search-params.test.js.map +1 -0
  63. package/dist/__tests__/segment-system.test.d.ts +2 -0
  64. package/dist/__tests__/segment-system.test.d.ts.map +1 -0
  65. package/dist/__tests__/segment-system.test.js +627 -0
  66. package/dist/__tests__/segment-system.test.js.map +1 -0
  67. package/dist/__tests__/static-handler-types.test.d.ts +8 -0
  68. package/dist/__tests__/static-handler-types.test.d.ts.map +1 -0
  69. package/dist/__tests__/static-handler-types.test.js +63 -0
  70. package/dist/__tests__/static-handler-types.test.js.map +1 -0
  71. package/dist/__tests__/urls.test.d.ts +2 -0
  72. package/dist/__tests__/urls.test.d.ts.map +1 -0
  73. package/dist/__tests__/urls.test.js +421 -0
  74. package/dist/__tests__/urls.test.js.map +1 -0
  75. package/dist/__tests__/use-mount.test.d.ts +2 -0
  76. package/dist/__tests__/use-mount.test.d.ts.map +1 -0
  77. package/dist/__tests__/use-mount.test.js +35 -0
  78. package/dist/__tests__/use-mount.test.js.map +1 -0
  79. package/dist/bin/rango.d.ts +2 -0
  80. package/dist/bin/rango.d.ts.map +1 -0
  81. package/dist/bin/rango.js +1619 -155
  82. package/dist/bin/rango.js.map +1 -0
  83. package/dist/browser/event-controller.d.ts +191 -0
  84. package/dist/browser/event-controller.d.ts.map +1 -0
  85. package/dist/browser/event-controller.js +559 -0
  86. package/dist/browser/event-controller.js.map +1 -0
  87. package/dist/browser/index.d.ts +2 -0
  88. package/dist/browser/index.d.ts.map +1 -0
  89. package/dist/browser/index.js +14 -0
  90. package/dist/browser/index.js.map +1 -0
  91. package/dist/browser/link-interceptor.d.ts +38 -0
  92. package/dist/browser/link-interceptor.d.ts.map +1 -0
  93. package/dist/browser/link-interceptor.js +99 -0
  94. package/dist/browser/link-interceptor.js.map +1 -0
  95. package/dist/browser/logging.d.ts +10 -0
  96. package/dist/browser/logging.d.ts.map +1 -0
  97. package/dist/browser/logging.js +29 -0
  98. package/dist/browser/logging.js.map +1 -0
  99. package/dist/browser/lru-cache.d.ts +17 -0
  100. package/dist/browser/lru-cache.d.ts.map +1 -0
  101. package/dist/browser/lru-cache.js +50 -0
  102. package/dist/browser/lru-cache.js.map +1 -0
  103. package/dist/browser/merge-segment-loaders.d.ts +39 -0
  104. package/dist/browser/merge-segment-loaders.d.ts.map +1 -0
  105. package/dist/browser/merge-segment-loaders.js +102 -0
  106. package/dist/browser/merge-segment-loaders.js.map +1 -0
  107. package/dist/browser/navigation-bridge.d.ts +102 -0
  108. package/dist/browser/navigation-bridge.d.ts.map +1 -0
  109. package/dist/browser/navigation-bridge.js +708 -0
  110. package/dist/browser/navigation-bridge.js.map +1 -0
  111. package/dist/browser/navigation-client.d.ts +25 -0
  112. package/dist/browser/navigation-client.d.ts.map +1 -0
  113. package/dist/browser/navigation-client.js +157 -0
  114. package/dist/browser/navigation-client.js.map +1 -0
  115. package/dist/browser/navigation-store.d.ts +101 -0
  116. package/dist/browser/navigation-store.d.ts.map +1 -0
  117. package/dist/browser/navigation-store.js +625 -0
  118. package/dist/browser/navigation-store.js.map +1 -0
  119. package/dist/browser/partial-update.d.ts +75 -0
  120. package/dist/browser/partial-update.d.ts.map +1 -0
  121. package/dist/browser/partial-update.js +426 -0
  122. package/dist/browser/partial-update.js.map +1 -0
  123. package/dist/browser/react/Link.d.ts +86 -0
  124. package/dist/browser/react/Link.d.ts.map +1 -0
  125. package/dist/browser/react/Link.js +128 -0
  126. package/dist/browser/react/Link.js.map +1 -0
  127. package/dist/browser/react/NavigationProvider.d.ts +63 -0
  128. package/dist/browser/react/NavigationProvider.d.ts.map +1 -0
  129. package/dist/browser/react/NavigationProvider.js +216 -0
  130. package/dist/browser/react/NavigationProvider.js.map +1 -0
  131. package/dist/browser/react/ScrollRestoration.d.ts +75 -0
  132. package/dist/browser/react/ScrollRestoration.d.ts.map +1 -0
  133. package/dist/browser/react/ScrollRestoration.js +57 -0
  134. package/dist/browser/react/ScrollRestoration.js.map +1 -0
  135. package/dist/browser/react/context.d.ts +46 -0
  136. package/dist/browser/react/context.d.ts.map +1 -0
  137. package/dist/browser/react/context.js +10 -0
  138. package/dist/browser/react/context.js.map +1 -0
  139. package/dist/browser/react/index.d.ts +11 -0
  140. package/dist/browser/react/index.d.ts.map +1 -0
  141. package/dist/browser/react/index.js +22 -0
  142. package/dist/browser/react/index.js.map +1 -0
  143. package/dist/browser/react/location-state-shared.d.ts +63 -0
  144. package/dist/browser/react/location-state-shared.d.ts.map +1 -0
  145. package/dist/browser/react/location-state-shared.js +81 -0
  146. package/dist/browser/react/location-state-shared.js.map +1 -0
  147. package/dist/browser/react/location-state.d.ts +23 -0
  148. package/dist/browser/react/location-state.d.ts.map +1 -0
  149. package/dist/browser/react/location-state.js +29 -0
  150. package/dist/browser/react/location-state.js.map +1 -0
  151. package/dist/browser/react/mount-context.d.ts +24 -0
  152. package/dist/browser/react/mount-context.d.ts.map +1 -0
  153. package/dist/browser/react/mount-context.js +24 -0
  154. package/dist/browser/react/mount-context.js.map +1 -0
  155. package/dist/browser/react/use-action.d.ts +64 -0
  156. package/dist/browser/react/use-action.d.ts.map +1 -0
  157. package/dist/browser/react/use-action.js +134 -0
  158. package/dist/browser/react/use-action.js.map +1 -0
  159. package/dist/browser/react/use-client-cache.d.ts +41 -0
  160. package/dist/browser/react/use-client-cache.d.ts.map +1 -0
  161. package/dist/browser/react/use-client-cache.js +39 -0
  162. package/dist/browser/react/use-client-cache.js.map +1 -0
  163. package/dist/browser/react/use-handle.d.ts +31 -0
  164. package/dist/browser/react/use-handle.d.ts.map +1 -0
  165. package/dist/browser/react/use-handle.js +144 -0
  166. package/dist/browser/react/use-handle.js.map +1 -0
  167. package/dist/browser/react/use-href.d.ts +33 -0
  168. package/dist/browser/react/use-href.d.ts.map +1 -0
  169. package/dist/browser/react/use-href.js +39 -0
  170. package/dist/browser/react/use-href.js.map +1 -0
  171. package/dist/browser/react/use-link-status.d.ts +37 -0
  172. package/dist/browser/react/use-link-status.d.ts.map +1 -0
  173. package/dist/browser/react/use-link-status.js +99 -0
  174. package/dist/browser/react/use-link-status.js.map +1 -0
  175. package/dist/browser/react/use-mount.d.ts +25 -0
  176. package/dist/browser/react/use-mount.d.ts.map +1 -0
  177. package/dist/browser/react/use-mount.js +30 -0
  178. package/dist/browser/react/use-mount.js.map +1 -0
  179. package/dist/browser/react/use-navigation.d.ts +27 -0
  180. package/dist/browser/react/use-navigation.d.ts.map +1 -0
  181. package/dist/browser/react/use-navigation.js +87 -0
  182. package/dist/browser/react/use-navigation.js.map +1 -0
  183. package/dist/browser/react/use-segments.d.ts +38 -0
  184. package/dist/browser/react/use-segments.d.ts.map +1 -0
  185. package/dist/browser/react/use-segments.js +130 -0
  186. package/dist/browser/react/use-segments.js.map +1 -0
  187. package/dist/browser/request-controller.d.ts +26 -0
  188. package/dist/browser/request-controller.d.ts.map +1 -0
  189. package/dist/browser/request-controller.js +147 -0
  190. package/dist/browser/request-controller.js.map +1 -0
  191. package/dist/browser/rsc-router.d.ts +129 -0
  192. package/dist/browser/rsc-router.d.ts.map +1 -0
  193. package/dist/browser/rsc-router.js +195 -0
  194. package/dist/browser/rsc-router.js.map +1 -0
  195. package/dist/browser/scroll-restoration.d.ts +93 -0
  196. package/dist/browser/scroll-restoration.d.ts.map +1 -0
  197. package/dist/browser/scroll-restoration.js +321 -0
  198. package/dist/browser/scroll-restoration.js.map +1 -0
  199. package/dist/browser/segment-structure-assert.d.ts +17 -0
  200. package/dist/browser/segment-structure-assert.d.ts.map +1 -0
  201. package/dist/browser/segment-structure-assert.js +59 -0
  202. package/dist/browser/segment-structure-assert.js.map +1 -0
  203. package/dist/browser/server-action-bridge.d.ts +26 -0
  204. package/dist/browser/server-action-bridge.d.ts.map +1 -0
  205. package/dist/browser/server-action-bridge.js +668 -0
  206. package/dist/browser/server-action-bridge.js.map +1 -0
  207. package/dist/browser/shallow.d.ts +12 -0
  208. package/dist/browser/shallow.d.ts.map +1 -0
  209. package/dist/browser/shallow.js +34 -0
  210. package/dist/browser/shallow.js.map +1 -0
  211. package/dist/browser/types.d.ts +369 -0
  212. package/dist/browser/types.d.ts.map +1 -0
  213. package/dist/browser/types.js +2 -0
  214. package/dist/browser/types.js.map +1 -0
  215. package/dist/build/__tests__/generate-cli.test.d.ts +2 -0
  216. package/dist/build/__tests__/generate-cli.test.d.ts.map +1 -0
  217. package/dist/build/__tests__/generate-cli.test.js +237 -0
  218. package/dist/build/__tests__/generate-cli.test.js.map +1 -0
  219. package/dist/build/__tests__/generate-manifest.test.d.ts +2 -0
  220. package/dist/build/__tests__/generate-manifest.test.d.ts.map +1 -0
  221. package/dist/build/__tests__/generate-manifest.test.js +119 -0
  222. package/dist/build/__tests__/generate-manifest.test.js.map +1 -0
  223. package/dist/build/__tests__/generate-route-types.test.d.ts +2 -0
  224. package/dist/build/__tests__/generate-route-types.test.d.ts.map +1 -0
  225. package/dist/build/__tests__/generate-route-types.test.js +620 -0
  226. package/dist/build/__tests__/generate-route-types.test.js.map +1 -0
  227. package/dist/build/__tests__/per-router-manifest.test.d.ts +2 -0
  228. package/dist/build/__tests__/per-router-manifest.test.d.ts.map +1 -0
  229. package/dist/build/__tests__/per-router-manifest.test.js +308 -0
  230. package/dist/build/__tests__/per-router-manifest.test.js.map +1 -0
  231. package/dist/build/generate-manifest.d.ts +81 -0
  232. package/dist/build/generate-manifest.d.ts.map +1 -0
  233. package/dist/build/generate-manifest.js +276 -0
  234. package/dist/build/generate-manifest.js.map +1 -0
  235. package/dist/build/generate-route-types.d.ts +115 -0
  236. package/dist/build/generate-route-types.d.ts.map +1 -0
  237. package/dist/build/generate-route-types.js +740 -0
  238. package/dist/build/generate-route-types.js.map +1 -0
  239. package/dist/build/index.d.ts +21 -0
  240. package/dist/build/index.d.ts.map +1 -0
  241. package/dist/build/index.js +21 -0
  242. package/dist/build/index.js.map +1 -0
  243. package/dist/build/route-trie.d.ts +71 -0
  244. package/dist/build/route-trie.d.ts.map +1 -0
  245. package/dist/build/route-trie.js +175 -0
  246. package/dist/build/route-trie.js.map +1 -0
  247. package/dist/cache/__tests__/cache-scope.test.d.ts +2 -0
  248. package/dist/cache/__tests__/cache-scope.test.d.ts.map +1 -0
  249. package/dist/cache/__tests__/cache-scope.test.js +208 -0
  250. package/dist/cache/__tests__/cache-scope.test.js.map +1 -0
  251. package/dist/cache/__tests__/document-cache.test.d.ts +2 -0
  252. package/dist/cache/__tests__/document-cache.test.d.ts.map +1 -0
  253. package/dist/cache/__tests__/document-cache.test.js +345 -0
  254. package/dist/cache/__tests__/document-cache.test.js.map +1 -0
  255. package/dist/cache/__tests__/memory-segment-store.test.d.ts +2 -0
  256. package/dist/cache/__tests__/memory-segment-store.test.d.ts.map +1 -0
  257. package/dist/cache/__tests__/memory-segment-store.test.js +425 -0
  258. package/dist/cache/__tests__/memory-segment-store.test.js.map +1 -0
  259. package/dist/cache/__tests__/memory-store.test.d.ts +2 -0
  260. package/dist/cache/__tests__/memory-store.test.d.ts.map +1 -0
  261. package/dist/cache/__tests__/memory-store.test.js +367 -0
  262. package/dist/cache/__tests__/memory-store.test.js.map +1 -0
  263. package/dist/cache/cache-scope.d.ts +102 -0
  264. package/dist/cache/cache-scope.d.ts.map +1 -0
  265. package/dist/cache/cache-scope.js +440 -0
  266. package/dist/cache/cache-scope.js.map +1 -0
  267. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts +2 -0
  268. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts.map +1 -0
  269. package/dist/cache/cf/__tests__/cf-cache-store.test.js +330 -0
  270. package/dist/cache/cf/__tests__/cf-cache-store.test.js.map +1 -0
  271. package/dist/cache/cf/cf-cache-store.d.ts +165 -0
  272. package/dist/cache/cf/cf-cache-store.d.ts.map +1 -0
  273. package/dist/cache/cf/cf-cache-store.js +242 -0
  274. package/dist/cache/cf/cf-cache-store.js.map +1 -0
  275. package/dist/cache/cf/index.d.ts +14 -0
  276. package/dist/cache/cf/index.d.ts.map +1 -0
  277. package/dist/cache/cf/index.js +17 -0
  278. package/dist/cache/cf/index.js.map +1 -0
  279. package/dist/cache/document-cache.d.ts +64 -0
  280. package/dist/cache/document-cache.d.ts.map +1 -0
  281. package/dist/cache/document-cache.js +228 -0
  282. package/dist/cache/document-cache.js.map +1 -0
  283. package/dist/cache/index.d.ts +19 -0
  284. package/dist/cache/index.d.ts.map +1 -0
  285. package/dist/cache/index.js +21 -0
  286. package/dist/cache/index.js.map +1 -0
  287. package/dist/cache/memory-segment-store.d.ts +110 -0
  288. package/dist/cache/memory-segment-store.d.ts.map +1 -0
  289. package/dist/cache/memory-segment-store.js +117 -0
  290. package/dist/cache/memory-segment-store.js.map +1 -0
  291. package/dist/cache/memory-store.d.ts +41 -0
  292. package/dist/cache/memory-store.d.ts.map +1 -0
  293. package/dist/cache/memory-store.js +191 -0
  294. package/dist/cache/memory-store.js.map +1 -0
  295. package/dist/cache/types.d.ts +317 -0
  296. package/dist/cache/types.d.ts.map +1 -0
  297. package/dist/cache/types.js +12 -0
  298. package/dist/cache/types.js.map +1 -0
  299. package/dist/client.d.ts +248 -0
  300. package/dist/client.d.ts.map +1 -0
  301. package/dist/client.js +367 -0
  302. package/dist/client.js.map +1 -0
  303. package/dist/client.rsc.d.ts +26 -0
  304. package/dist/client.rsc.d.ts.map +1 -0
  305. package/dist/client.rsc.js +46 -0
  306. package/dist/client.rsc.js.map +1 -0
  307. package/dist/component-utils.d.ts +36 -0
  308. package/dist/component-utils.d.ts.map +1 -0
  309. package/dist/component-utils.js +61 -0
  310. package/dist/component-utils.js.map +1 -0
  311. package/dist/components/DefaultDocument.d.ts +13 -0
  312. package/dist/components/DefaultDocument.d.ts.map +1 -0
  313. package/dist/components/DefaultDocument.js +15 -0
  314. package/dist/components/DefaultDocument.js.map +1 -0
  315. package/dist/debug.d.ts +58 -0
  316. package/dist/debug.d.ts.map +1 -0
  317. package/dist/debug.js +157 -0
  318. package/dist/debug.js.map +1 -0
  319. package/dist/default-error-boundary.d.ts +11 -0
  320. package/dist/default-error-boundary.d.ts.map +1 -0
  321. package/dist/default-error-boundary.js +45 -0
  322. package/dist/default-error-boundary.js.map +1 -0
  323. package/dist/deps/browser.d.ts +2 -0
  324. package/dist/deps/browser.d.ts.map +1 -0
  325. package/dist/deps/browser.js +3 -0
  326. package/dist/deps/browser.js.map +1 -0
  327. package/dist/deps/html-stream-client.d.ts +2 -0
  328. package/dist/deps/html-stream-client.d.ts.map +1 -0
  329. package/dist/deps/html-stream-client.js +3 -0
  330. package/dist/deps/html-stream-client.js.map +1 -0
  331. package/dist/deps/html-stream-server.d.ts +2 -0
  332. package/dist/deps/html-stream-server.d.ts.map +1 -0
  333. package/dist/deps/html-stream-server.js +3 -0
  334. package/dist/deps/html-stream-server.js.map +1 -0
  335. package/dist/deps/rsc.d.ts +2 -0
  336. package/dist/deps/rsc.d.ts.map +1 -0
  337. package/dist/deps/rsc.js +4 -0
  338. package/dist/deps/rsc.js.map +1 -0
  339. package/dist/deps/ssr.d.ts +2 -0
  340. package/dist/deps/ssr.d.ts.map +1 -0
  341. package/dist/deps/ssr.js +3 -0
  342. package/dist/deps/ssr.js.map +1 -0
  343. package/dist/errors.d.ts +174 -0
  344. package/dist/errors.d.ts.map +1 -0
  345. package/dist/errors.js +241 -0
  346. package/dist/errors.js.map +1 -0
  347. package/dist/handle.d.ts +78 -0
  348. package/dist/handle.d.ts.map +1 -0
  349. package/dist/handle.js +82 -0
  350. package/dist/handle.js.map +1 -0
  351. package/dist/handles/MetaTags.d.ts +14 -0
  352. package/dist/handles/MetaTags.d.ts.map +1 -0
  353. package/dist/handles/MetaTags.js +136 -0
  354. package/dist/handles/MetaTags.js.map +1 -0
  355. package/dist/handles/index.d.ts +6 -0
  356. package/dist/handles/index.d.ts.map +1 -0
  357. package/dist/handles/index.js +6 -0
  358. package/dist/handles/index.js.map +1 -0
  359. package/dist/handles/meta.d.ts +39 -0
  360. package/dist/handles/meta.d.ts.map +1 -0
  361. package/dist/handles/meta.js +202 -0
  362. package/dist/handles/meta.js.map +1 -0
  363. package/dist/host/__tests__/errors.test.d.ts +2 -0
  364. package/dist/host/__tests__/errors.test.d.ts.map +1 -0
  365. package/dist/host/__tests__/errors.test.js +76 -0
  366. package/dist/host/__tests__/errors.test.js.map +1 -0
  367. package/dist/host/__tests__/pattern-comprehensive.test.d.ts +2 -0
  368. package/dist/host/__tests__/pattern-comprehensive.test.d.ts.map +1 -0
  369. package/dist/host/__tests__/pattern-comprehensive.test.js +732 -0
  370. package/dist/host/__tests__/pattern-comprehensive.test.js.map +1 -0
  371. package/dist/host/__tests__/pattern-matcher.test.d.ts +2 -0
  372. package/dist/host/__tests__/pattern-matcher.test.d.ts.map +1 -0
  373. package/dist/host/__tests__/pattern-matcher.test.js +251 -0
  374. package/dist/host/__tests__/pattern-matcher.test.js.map +1 -0
  375. package/dist/host/__tests__/router.test.d.ts +2 -0
  376. package/dist/host/__tests__/router.test.d.ts.map +1 -0
  377. package/dist/host/__tests__/router.test.js +241 -0
  378. package/dist/host/__tests__/router.test.js.map +1 -0
  379. package/dist/host/__tests__/testing.test.d.ts +2 -0
  380. package/dist/host/__tests__/testing.test.d.ts.map +1 -0
  381. package/dist/host/__tests__/testing.test.js +64 -0
  382. package/dist/host/__tests__/testing.test.js.map +1 -0
  383. package/dist/host/__tests__/utils.test.d.ts +2 -0
  384. package/dist/host/__tests__/utils.test.d.ts.map +1 -0
  385. package/dist/host/__tests__/utils.test.js +29 -0
  386. package/dist/host/__tests__/utils.test.js.map +1 -0
  387. package/dist/host/cookie-handler.d.ts +34 -0
  388. package/dist/host/cookie-handler.d.ts.map +1 -0
  389. package/dist/host/cookie-handler.js +124 -0
  390. package/dist/host/cookie-handler.js.map +1 -0
  391. package/dist/host/errors.d.ts +56 -0
  392. package/dist/host/errors.d.ts.map +1 -0
  393. package/dist/host/errors.js +79 -0
  394. package/dist/host/errors.js.map +1 -0
  395. package/dist/host/index.d.ts +29 -0
  396. package/dist/host/index.d.ts.map +1 -0
  397. package/dist/host/index.js +32 -0
  398. package/dist/host/index.js.map +1 -0
  399. package/dist/host/pattern-matcher.d.ts +36 -0
  400. package/dist/host/pattern-matcher.d.ts.map +1 -0
  401. package/dist/host/pattern-matcher.js +172 -0
  402. package/dist/host/pattern-matcher.js.map +1 -0
  403. package/dist/host/router.d.ts +26 -0
  404. package/dist/host/router.d.ts.map +1 -0
  405. package/dist/host/router.js +218 -0
  406. package/dist/host/router.js.map +1 -0
  407. package/dist/host/testing.d.ts +36 -0
  408. package/dist/host/testing.d.ts.map +1 -0
  409. package/dist/host/testing.js +55 -0
  410. package/dist/host/testing.js.map +1 -0
  411. package/dist/host/types.d.ts +115 -0
  412. package/dist/host/types.d.ts.map +1 -0
  413. package/dist/host/types.js +7 -0
  414. package/dist/host/types.js.map +1 -0
  415. package/dist/host/utils.d.ts +21 -0
  416. package/dist/host/utils.d.ts.map +1 -0
  417. package/dist/host/utils.js +23 -0
  418. package/dist/host/utils.js.map +1 -0
  419. package/dist/href-client.d.ts +131 -0
  420. package/dist/href-client.d.ts.map +1 -0
  421. package/dist/href-client.js +64 -0
  422. package/dist/href-client.js.map +1 -0
  423. package/{src/href-context.ts → dist/href-context.d.ts} +7 -11
  424. package/dist/href-context.d.ts.map +1 -0
  425. package/dist/href-context.js +21 -0
  426. package/dist/href-context.js.map +1 -0
  427. package/dist/index.d.ts +73 -0
  428. package/dist/index.d.ts.map +1 -0
  429. package/dist/index.js +91 -0
  430. package/dist/index.js.map +1 -0
  431. package/dist/index.rsc.d.ts +32 -0
  432. package/dist/index.rsc.d.ts.map +1 -0
  433. package/dist/index.rsc.js +40 -0
  434. package/dist/index.rsc.js.map +1 -0
  435. package/dist/internal-debug.d.ts +2 -0
  436. package/dist/internal-debug.d.ts.map +1 -0
  437. package/dist/internal-debug.js +5 -0
  438. package/dist/internal-debug.js.map +1 -0
  439. package/dist/loader.d.ts +14 -0
  440. package/dist/loader.d.ts.map +1 -0
  441. package/dist/loader.js +20 -0
  442. package/dist/loader.js.map +1 -0
  443. package/dist/loader.rsc.d.ts +19 -0
  444. package/dist/loader.rsc.d.ts.map +1 -0
  445. package/dist/loader.rsc.js +99 -0
  446. package/dist/loader.rsc.js.map +1 -0
  447. package/dist/network-error-thrower.d.ts +17 -0
  448. package/dist/network-error-thrower.d.ts.map +1 -0
  449. package/dist/network-error-thrower.js +14 -0
  450. package/dist/network-error-thrower.js.map +1 -0
  451. package/dist/outlet-context.d.ts +13 -0
  452. package/dist/outlet-context.d.ts.map +1 -0
  453. package/dist/outlet-context.js +3 -0
  454. package/dist/outlet-context.js.map +1 -0
  455. package/dist/prerender/__tests__/param-hash.test.d.ts +2 -0
  456. package/dist/prerender/__tests__/param-hash.test.d.ts.map +1 -0
  457. package/dist/prerender/__tests__/param-hash.test.js +148 -0
  458. package/dist/prerender/__tests__/param-hash.test.js.map +1 -0
  459. package/dist/prerender/param-hash.d.ts +16 -0
  460. package/dist/prerender/param-hash.d.ts.map +1 -0
  461. package/dist/prerender/param-hash.js +36 -0
  462. package/dist/prerender/param-hash.js.map +1 -0
  463. package/dist/prerender/store.d.ts +38 -0
  464. package/dist/prerender/store.d.ts.map +1 -0
  465. package/dist/prerender/store.js +61 -0
  466. package/dist/prerender/store.js.map +1 -0
  467. package/dist/prerender.d.ts +66 -0
  468. package/dist/prerender.d.ts.map +1 -0
  469. package/dist/prerender.js +57 -0
  470. package/dist/prerender.js.map +1 -0
  471. package/dist/reverse.d.ts +196 -0
  472. package/dist/reverse.d.ts.map +1 -0
  473. package/dist/reverse.js +78 -0
  474. package/dist/reverse.js.map +1 -0
  475. package/dist/root-error-boundary.d.ts +33 -0
  476. package/dist/root-error-boundary.d.ts.map +1 -0
  477. package/dist/root-error-boundary.js +165 -0
  478. package/dist/root-error-boundary.js.map +1 -0
  479. package/dist/route-content-wrapper.d.ts +46 -0
  480. package/dist/route-content-wrapper.d.ts.map +1 -0
  481. package/dist/route-content-wrapper.js +77 -0
  482. package/dist/route-content-wrapper.js.map +1 -0
  483. package/dist/route-definition.d.ts +421 -0
  484. package/dist/route-definition.d.ts.map +1 -0
  485. package/dist/route-definition.js +868 -0
  486. package/dist/route-definition.js.map +1 -0
  487. package/dist/route-map-builder.d.ts +155 -0
  488. package/dist/route-map-builder.d.ts.map +1 -0
  489. package/dist/route-map-builder.js +237 -0
  490. package/dist/route-map-builder.js.map +1 -0
  491. package/dist/route-types.d.ts +165 -0
  492. package/dist/route-types.d.ts.map +1 -0
  493. package/dist/route-types.js +7 -0
  494. package/dist/route-types.js.map +1 -0
  495. package/dist/router/__tests__/handler-context.test.d.ts +2 -0
  496. package/dist/router/__tests__/handler-context.test.d.ts.map +1 -0
  497. package/dist/router/__tests__/handler-context.test.js +65 -0
  498. package/dist/router/__tests__/handler-context.test.js.map +1 -0
  499. package/dist/router/__tests__/loader-cycle-detection.test.d.ts +2 -0
  500. package/dist/router/__tests__/loader-cycle-detection.test.d.ts.map +1 -0
  501. package/dist/router/__tests__/loader-cycle-detection.test.js +221 -0
  502. package/dist/router/__tests__/loader-cycle-detection.test.js.map +1 -0
  503. package/dist/router/__tests__/match-context.test.d.ts +2 -0
  504. package/dist/router/__tests__/match-context.test.d.ts.map +1 -0
  505. package/dist/router/__tests__/match-context.test.js +92 -0
  506. package/dist/router/__tests__/match-context.test.js.map +1 -0
  507. package/dist/router/__tests__/match-pipelines.test.d.ts +2 -0
  508. package/dist/router/__tests__/match-pipelines.test.d.ts.map +1 -0
  509. package/dist/router/__tests__/match-pipelines.test.js +417 -0
  510. package/dist/router/__tests__/match-pipelines.test.js.map +1 -0
  511. package/dist/router/__tests__/match-result.test.d.ts +2 -0
  512. package/dist/router/__tests__/match-result.test.d.ts.map +1 -0
  513. package/dist/router/__tests__/match-result.test.js +457 -0
  514. package/dist/router/__tests__/match-result.test.js.map +1 -0
  515. package/dist/router/__tests__/on-error.test.d.ts +2 -0
  516. package/dist/router/__tests__/on-error.test.d.ts.map +1 -0
  517. package/dist/router/__tests__/on-error.test.js +678 -0
  518. package/dist/router/__tests__/on-error.test.js.map +1 -0
  519. package/dist/router/__tests__/pattern-matching.test.d.ts +2 -0
  520. package/dist/router/__tests__/pattern-matching.test.d.ts.map +1 -0
  521. package/dist/router/__tests__/pattern-matching.test.js +629 -0
  522. package/dist/router/__tests__/pattern-matching.test.js.map +1 -0
  523. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts +2 -0
  524. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts.map +1 -0
  525. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js +155 -0
  526. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js.map +1 -0
  527. package/dist/router/error-handling.d.ts +77 -0
  528. package/dist/router/error-handling.d.ts.map +1 -0
  529. package/dist/router/error-handling.js +202 -0
  530. package/dist/router/error-handling.js.map +1 -0
  531. package/dist/router/handler-context.d.ts +20 -0
  532. package/dist/router/handler-context.d.ts.map +1 -0
  533. package/dist/router/handler-context.js +198 -0
  534. package/dist/router/handler-context.js.map +1 -0
  535. package/dist/router/intercept-resolution.d.ts +66 -0
  536. package/dist/router/intercept-resolution.d.ts.map +1 -0
  537. package/dist/router/intercept-resolution.js +246 -0
  538. package/dist/router/intercept-resolution.js.map +1 -0
  539. package/dist/router/loader-resolution.d.ts +64 -0
  540. package/dist/router/loader-resolution.d.ts.map +1 -0
  541. package/dist/router/loader-resolution.js +284 -0
  542. package/dist/router/loader-resolution.js.map +1 -0
  543. package/dist/router/logging.d.ts +15 -0
  544. package/dist/router/logging.d.ts.map +1 -0
  545. package/dist/router/logging.js +99 -0
  546. package/dist/router/logging.js.map +1 -0
  547. package/dist/router/manifest.d.ts +22 -0
  548. package/dist/router/manifest.d.ts.map +1 -0
  549. package/dist/router/manifest.js +181 -0
  550. package/dist/router/manifest.js.map +1 -0
  551. package/dist/router/match-api.d.ts +35 -0
  552. package/dist/router/match-api.d.ts.map +1 -0
  553. package/dist/router/match-api.js +406 -0
  554. package/dist/router/match-api.js.map +1 -0
  555. package/dist/router/match-context.d.ts +206 -0
  556. package/dist/router/match-context.d.ts.map +1 -0
  557. package/dist/router/match-context.js +17 -0
  558. package/dist/router/match-context.js.map +1 -0
  559. package/dist/router/match-middleware/background-revalidation.d.ts +127 -0
  560. package/dist/router/match-middleware/background-revalidation.d.ts.map +1 -0
  561. package/dist/router/match-middleware/background-revalidation.js +75 -0
  562. package/dist/router/match-middleware/background-revalidation.js.map +1 -0
  563. package/dist/router/match-middleware/cache-lookup.d.ts +112 -0
  564. package/dist/router/match-middleware/cache-lookup.d.ts.map +1 -0
  565. package/dist/router/match-middleware/cache-lookup.js +257 -0
  566. package/dist/router/match-middleware/cache-lookup.js.map +1 -0
  567. package/dist/router/match-middleware/cache-store.d.ts +113 -0
  568. package/dist/router/match-middleware/cache-store.d.ts.map +1 -0
  569. package/dist/router/match-middleware/cache-store.js +108 -0
  570. package/dist/router/match-middleware/cache-store.js.map +1 -0
  571. package/dist/router/match-middleware/index.d.ts +81 -0
  572. package/dist/router/match-middleware/index.d.ts.map +1 -0
  573. package/dist/router/match-middleware/index.js +80 -0
  574. package/dist/router/match-middleware/index.js.map +1 -0
  575. package/dist/router/match-middleware/intercept-resolution.d.ts +117 -0
  576. package/dist/router/match-middleware/intercept-resolution.d.ts.map +1 -0
  577. package/dist/router/match-middleware/intercept-resolution.js +134 -0
  578. package/dist/router/match-middleware/intercept-resolution.js.map +1 -0
  579. package/dist/router/match-middleware/segment-resolution.d.ts +99 -0
  580. package/dist/router/match-middleware/segment-resolution.d.ts.map +1 -0
  581. package/dist/router/match-middleware/segment-resolution.js +53 -0
  582. package/dist/router/match-middleware/segment-resolution.js.map +1 -0
  583. package/dist/router/match-pipelines.d.ts +147 -0
  584. package/dist/router/match-pipelines.d.ts.map +1 -0
  585. package/dist/router/match-pipelines.js +82 -0
  586. package/dist/router/match-pipelines.js.map +1 -0
  587. package/dist/router/match-result.d.ts +126 -0
  588. package/dist/router/match-result.d.ts.map +1 -0
  589. package/dist/router/match-result.js +93 -0
  590. package/dist/router/match-result.js.map +1 -0
  591. package/dist/router/metrics.d.ts +20 -0
  592. package/dist/router/metrics.d.ts.map +1 -0
  593. package/dist/router/metrics.js +47 -0
  594. package/dist/router/metrics.js.map +1 -0
  595. package/dist/router/middleware.d.ts +249 -0
  596. package/dist/router/middleware.d.ts.map +1 -0
  597. package/dist/router/middleware.js +434 -0
  598. package/dist/router/middleware.js.map +1 -0
  599. package/dist/router/middleware.test.d.ts +2 -0
  600. package/dist/router/middleware.test.d.ts.map +1 -0
  601. package/dist/router/middleware.test.js +816 -0
  602. package/dist/router/middleware.test.js.map +1 -0
  603. package/dist/router/pattern-matching.d.ts +149 -0
  604. package/dist/router/pattern-matching.d.ts.map +1 -0
  605. package/dist/router/pattern-matching.js +349 -0
  606. package/dist/router/pattern-matching.js.map +1 -0
  607. package/dist/router/revalidation.d.ts +44 -0
  608. package/dist/router/revalidation.d.ts.map +1 -0
  609. package/dist/router/revalidation.js +147 -0
  610. package/dist/router/revalidation.js.map +1 -0
  611. package/dist/router/router-context.d.ts +135 -0
  612. package/dist/router/router-context.d.ts.map +1 -0
  613. package/dist/router/router-context.js +36 -0
  614. package/dist/router/router-context.js.map +1 -0
  615. package/dist/router/segment-resolution.d.ts +127 -0
  616. package/dist/router/segment-resolution.d.ts.map +1 -0
  617. package/dist/router/segment-resolution.js +919 -0
  618. package/dist/router/segment-resolution.js.map +1 -0
  619. package/dist/router/trie-matching.d.ts +40 -0
  620. package/dist/router/trie-matching.d.ts.map +1 -0
  621. package/dist/router/trie-matching.js +127 -0
  622. package/dist/router/trie-matching.js.map +1 -0
  623. package/dist/router/types.d.ts +136 -0
  624. package/dist/router/types.d.ts.map +1 -0
  625. package/dist/router/types.js +7 -0
  626. package/dist/router/types.js.map +1 -0
  627. package/dist/router.d.ts +753 -0
  628. package/dist/router.d.ts.map +1 -0
  629. package/dist/router.gen.d.ts +6 -0
  630. package/dist/router.gen.d.ts.map +1 -0
  631. package/dist/router.gen.js +6 -0
  632. package/dist/router.gen.js.map +1 -0
  633. package/dist/router.js +1304 -0
  634. package/dist/router.js.map +1 -0
  635. package/dist/rsc/__tests__/helpers.test.d.ts +2 -0
  636. package/dist/rsc/__tests__/helpers.test.d.ts.map +1 -0
  637. package/dist/rsc/__tests__/helpers.test.js +140 -0
  638. package/dist/rsc/__tests__/helpers.test.js.map +1 -0
  639. package/dist/rsc/handler.d.ts +45 -0
  640. package/dist/rsc/handler.d.ts.map +1 -0
  641. package/dist/rsc/handler.js +1172 -0
  642. package/dist/rsc/handler.js.map +1 -0
  643. package/dist/rsc/helpers.d.ts +16 -0
  644. package/dist/rsc/helpers.d.ts.map +1 -0
  645. package/dist/rsc/helpers.js +55 -0
  646. package/dist/rsc/helpers.js.map +1 -0
  647. package/dist/rsc/index.d.ts +22 -0
  648. package/dist/rsc/index.d.ts.map +1 -0
  649. package/dist/rsc/index.js +23 -0
  650. package/dist/rsc/index.js.map +1 -0
  651. package/dist/rsc/nonce.d.ts +9 -0
  652. package/dist/rsc/nonce.d.ts.map +1 -0
  653. package/dist/rsc/nonce.js +18 -0
  654. package/dist/rsc/nonce.js.map +1 -0
  655. package/dist/rsc/types.d.ts +206 -0
  656. package/dist/rsc/types.d.ts.map +1 -0
  657. package/dist/rsc/types.js +8 -0
  658. package/dist/rsc/types.js.map +1 -0
  659. package/dist/search-params.d.ts +103 -0
  660. package/dist/search-params.d.ts.map +1 -0
  661. package/dist/search-params.js +74 -0
  662. package/dist/search-params.js.map +1 -0
  663. package/dist/segment-system.d.ts +75 -0
  664. package/dist/segment-system.d.ts.map +1 -0
  665. package/dist/segment-system.js +336 -0
  666. package/dist/segment-system.js.map +1 -0
  667. package/dist/server/context.d.ts +245 -0
  668. package/dist/server/context.d.ts.map +1 -0
  669. package/dist/server/context.js +197 -0
  670. package/dist/server/context.js.map +1 -0
  671. package/dist/server/fetchable-loader-store.d.ts +18 -0
  672. package/dist/server/fetchable-loader-store.d.ts.map +1 -0
  673. package/dist/server/fetchable-loader-store.js +18 -0
  674. package/dist/server/fetchable-loader-store.js.map +1 -0
  675. package/dist/server/handle-store.d.ts +85 -0
  676. package/dist/server/handle-store.d.ts.map +1 -0
  677. package/dist/server/handle-store.js +142 -0
  678. package/dist/server/handle-store.js.map +1 -0
  679. package/dist/server/loader-registry.d.ts +55 -0
  680. package/dist/server/loader-registry.d.ts.map +1 -0
  681. package/dist/server/loader-registry.js +132 -0
  682. package/dist/server/loader-registry.js.map +1 -0
  683. package/dist/server/request-context.d.ts +226 -0
  684. package/dist/server/request-context.d.ts.map +1 -0
  685. package/dist/server/request-context.js +290 -0
  686. package/dist/server/request-context.js.map +1 -0
  687. package/dist/server/root-layout.d.ts +4 -0
  688. package/dist/server/root-layout.d.ts.map +1 -0
  689. package/dist/server/root-layout.js +5 -0
  690. package/dist/server/root-layout.js.map +1 -0
  691. package/dist/server.d.ts +15 -0
  692. package/dist/server.d.ts.map +1 -0
  693. package/dist/server.js +20 -0
  694. package/dist/server.js.map +1 -0
  695. package/dist/ssr/__tests__/ssr-handler.test.d.ts +2 -0
  696. package/dist/ssr/__tests__/ssr-handler.test.d.ts.map +1 -0
  697. package/dist/ssr/__tests__/ssr-handler.test.js +132 -0
  698. package/dist/ssr/__tests__/ssr-handler.test.js.map +1 -0
  699. package/dist/ssr/index.d.ts +98 -0
  700. package/dist/ssr/index.d.ts.map +1 -0
  701. package/dist/ssr/index.js +158 -0
  702. package/dist/ssr/index.js.map +1 -0
  703. package/dist/static-handler.d.ts +50 -0
  704. package/dist/static-handler.d.ts.map +1 -0
  705. package/dist/static-handler.gen.d.ts +5 -0
  706. package/dist/static-handler.gen.d.ts.map +1 -0
  707. package/dist/static-handler.gen.js +5 -0
  708. package/dist/static-handler.gen.js.map +1 -0
  709. package/dist/static-handler.js +29 -0
  710. package/dist/static-handler.js.map +1 -0
  711. package/dist/theme/ThemeProvider.d.ts +20 -0
  712. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  713. package/dist/theme/ThemeProvider.js +240 -0
  714. package/dist/theme/ThemeProvider.js.map +1 -0
  715. package/dist/theme/ThemeScript.d.ts +48 -0
  716. package/dist/theme/ThemeScript.d.ts.map +1 -0
  717. package/dist/theme/ThemeScript.js +13 -0
  718. package/dist/theme/ThemeScript.js.map +1 -0
  719. package/dist/theme/__tests__/theme.test.d.ts +2 -0
  720. package/dist/theme/__tests__/theme.test.d.ts.map +1 -0
  721. package/dist/theme/__tests__/theme.test.js +103 -0
  722. package/dist/theme/__tests__/theme.test.js.map +1 -0
  723. package/dist/theme/constants.d.ts +29 -0
  724. package/dist/theme/constants.d.ts.map +1 -0
  725. package/dist/theme/constants.js +48 -0
  726. package/dist/theme/constants.js.map +1 -0
  727. package/dist/theme/index.d.ts +31 -0
  728. package/dist/theme/index.d.ts.map +1 -0
  729. package/dist/theme/index.js +36 -0
  730. package/dist/theme/index.js.map +1 -0
  731. package/dist/theme/theme-context.d.ts +40 -0
  732. package/dist/theme/theme-context.d.ts.map +1 -0
  733. package/dist/theme/theme-context.js +60 -0
  734. package/dist/theme/theme-context.js.map +1 -0
  735. package/dist/theme/theme-script.d.ts +27 -0
  736. package/dist/theme/theme-script.d.ts.map +1 -0
  737. package/dist/theme/theme-script.js +147 -0
  738. package/dist/theme/theme-script.js.map +1 -0
  739. package/dist/theme/types.d.ts +163 -0
  740. package/dist/theme/types.d.ts.map +1 -0
  741. package/dist/theme/types.js +11 -0
  742. package/dist/theme/types.js.map +1 -0
  743. package/dist/theme/use-theme.d.ts +12 -0
  744. package/dist/theme/use-theme.d.ts.map +1 -0
  745. package/dist/theme/use-theme.js +40 -0
  746. package/dist/theme/use-theme.js.map +1 -0
  747. package/dist/types.d.ts +1479 -0
  748. package/dist/types.d.ts.map +1 -0
  749. package/dist/types.js +10 -0
  750. package/dist/types.js.map +1 -0
  751. package/dist/urls.d.ts +441 -0
  752. package/dist/urls.d.ts.map +1 -0
  753. package/dist/urls.gen.d.ts +8 -0
  754. package/dist/urls.gen.d.ts.map +1 -0
  755. package/dist/urls.gen.js +8 -0
  756. package/dist/urls.gen.js.map +1 -0
  757. package/dist/urls.js +443 -0
  758. package/dist/urls.js.map +1 -0
  759. package/dist/use-loader.d.ts +127 -0
  760. package/dist/use-loader.d.ts.map +1 -0
  761. package/dist/use-loader.js +237 -0
  762. package/dist/use-loader.js.map +1 -0
  763. package/dist/vite/__tests__/ast-handler-extract.test.d.ts +2 -0
  764. package/dist/vite/__tests__/ast-handler-extract.test.d.ts.map +1 -0
  765. package/dist/vite/__tests__/ast-handler-extract.test.js +294 -0
  766. package/dist/vite/__tests__/ast-handler-extract.test.js.map +1 -0
  767. package/dist/vite/__tests__/expose-id-utils.test.d.ts +2 -0
  768. package/dist/vite/__tests__/expose-id-utils.test.d.ts.map +1 -0
  769. package/dist/vite/__tests__/expose-id-utils.test.js +224 -0
  770. package/dist/vite/__tests__/expose-id-utils.test.js.map +1 -0
  771. package/dist/vite/__tests__/expose-internal-ids.test.d.ts +2 -0
  772. package/dist/vite/__tests__/expose-internal-ids.test.d.ts.map +1 -0
  773. package/dist/vite/__tests__/expose-internal-ids.test.js +647 -0
  774. package/dist/vite/__tests__/expose-internal-ids.test.js.map +1 -0
  775. package/dist/vite/__tests__/expose-router-id.test.d.ts +2 -0
  776. package/dist/vite/__tests__/expose-router-id.test.d.ts.map +1 -0
  777. package/dist/vite/__tests__/expose-router-id.test.js +39 -0
  778. package/dist/vite/__tests__/expose-router-id.test.js.map +1 -0
  779. package/dist/vite/ast-handler-extract.d.ts +49 -0
  780. package/dist/vite/ast-handler-extract.d.ts.map +1 -0
  781. package/dist/vite/ast-handler-extract.js +249 -0
  782. package/dist/vite/ast-handler-extract.js.map +1 -0
  783. package/dist/vite/expose-action-id.d.ts +19 -0
  784. package/dist/vite/expose-action-id.d.ts.map +1 -0
  785. package/dist/vite/expose-action-id.js +250 -0
  786. package/dist/vite/expose-action-id.js.map +1 -0
  787. package/dist/vite/expose-id-utils.d.ts +69 -0
  788. package/dist/vite/expose-id-utils.d.ts.map +1 -0
  789. package/dist/vite/expose-id-utils.js +289 -0
  790. package/dist/vite/expose-id-utils.js.map +1 -0
  791. package/dist/vite/expose-internal-ids.d.ts +22 -0
  792. package/dist/vite/expose-internal-ids.d.ts.map +1 -0
  793. package/dist/vite/expose-internal-ids.js +886 -0
  794. package/dist/vite/expose-internal-ids.js.map +1 -0
  795. package/dist/vite/index.d.ts +149 -0
  796. package/dist/vite/index.d.ts.map +1 -0
  797. package/dist/vite/index.js +5565 -2291
  798. package/dist/vite/index.js.bak +5448 -0
  799. package/dist/vite/index.js.map +1 -0
  800. package/dist/vite/index.named-routes.gen.ts +103 -0
  801. package/dist/vite/package-resolution.d.ts +43 -0
  802. package/dist/vite/package-resolution.d.ts.map +1 -0
  803. package/{src/vite/package-resolution.ts → dist/vite/package-resolution.js} +53 -66
  804. package/dist/vite/package-resolution.js.map +1 -0
  805. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  806. package/dist/vite/virtual-entries.d.ts +25 -0
  807. package/dist/vite/virtual-entries.d.ts.map +1 -0
  808. package/{src/vite/virtual-entries.ts → dist/vite/virtual-entries.js} +12 -16
  809. package/dist/vite/virtual-entries.js.map +1 -0
  810. package/package.json +72 -63
  811. package/skills/breadcrumbs/SKILL.md +252 -0
  812. package/skills/cache-guide/SKILL.md +294 -0
  813. package/skills/caching/SKILL.md +93 -23
  814. package/skills/composability/SKILL.md +172 -0
  815. package/skills/debug-manifest/SKILL.md +12 -8
  816. package/skills/document-cache/SKILL.md +18 -16
  817. package/skills/fonts/SKILL.md +6 -4
  818. package/skills/handler-use/SKILL.md +362 -0
  819. package/skills/hooks/SKILL.md +341 -71
  820. package/skills/host-router/SKILL.md +218 -0
  821. package/skills/intercept/SKILL.md +151 -8
  822. package/skills/layout/SKILL.md +122 -3
  823. package/skills/links/SKILL.md +158 -25
  824. package/skills/loader/SKILL.md +439 -46
  825. package/skills/middleware/SKILL.md +205 -37
  826. package/skills/migrate-nextjs/SKILL.md +560 -0
  827. package/skills/migrate-react-router/SKILL.md +765 -0
  828. package/skills/mime-routes/SKILL.md +15 -11
  829. package/skills/parallel/SKILL.md +263 -1
  830. package/skills/prerender/SKILL.md +467 -65
  831. package/skills/rango/SKILL.md +87 -21
  832. package/skills/response-routes/SKILL.md +152 -91
  833. package/skills/route/SKILL.md +281 -14
  834. package/skills/router-setup/SKILL.md +210 -32
  835. package/skills/streams-and-websockets/SKILL.md +283 -0
  836. package/skills/theme/SKILL.md +9 -8
  837. package/skills/typesafety/SKILL.md +327 -86
  838. package/skills/use-cache/SKILL.md +324 -0
  839. package/src/__internal.ts +102 -4
  840. package/src/bin/rango.ts +312 -15
  841. package/src/browser/action-coordinator.ts +97 -0
  842. package/src/browser/action-response-classifier.ts +99 -0
  843. package/src/browser/app-shell.ts +52 -0
  844. package/src/browser/app-version.ts +14 -0
  845. package/src/browser/event-controller.ts +92 -64
  846. package/src/browser/history-state.ts +80 -0
  847. package/src/browser/intercept-utils.ts +52 -0
  848. package/src/browser/link-interceptor.ts +24 -4
  849. package/src/browser/logging.ts +55 -0
  850. package/src/browser/merge-segment-loaders.ts +20 -12
  851. package/src/browser/navigation-bridge.ts +367 -561
  852. package/src/browser/navigation-client.ts +228 -70
  853. package/src/browser/navigation-store.ts +97 -55
  854. package/src/browser/navigation-transaction.ts +297 -0
  855. package/src/browser/network-error-handler.ts +61 -0
  856. package/src/browser/partial-update.ts +362 -316
  857. package/src/browser/prefetch/cache.ts +314 -0
  858. package/src/browser/prefetch/fetch.ts +282 -0
  859. package/src/browser/prefetch/observer.ts +65 -0
  860. package/src/browser/prefetch/policy.ts +48 -0
  861. package/src/browser/prefetch/queue.ts +191 -0
  862. package/src/browser/prefetch/resource-ready.ts +77 -0
  863. package/src/browser/rango-state.ts +152 -0
  864. package/src/browser/react/Link.tsx +255 -71
  865. package/src/browser/react/NavigationProvider.tsx +132 -17
  866. package/src/browser/react/context.ts +11 -0
  867. package/src/browser/react/filter-segment-order.ts +11 -0
  868. package/src/browser/react/index.ts +12 -12
  869. package/src/browser/react/location-state-shared.ts +95 -53
  870. package/src/browser/react/location-state.ts +60 -15
  871. package/src/browser/react/mount-context.ts +6 -1
  872. package/src/browser/react/nonce-context.ts +23 -0
  873. package/src/browser/react/shallow-equal.ts +27 -0
  874. package/src/browser/react/use-action.ts +29 -51
  875. package/src/browser/react/use-client-cache.ts +5 -3
  876. package/src/browser/react/use-handle.ts +30 -120
  877. package/src/browser/react/use-link-status.ts +6 -5
  878. package/src/browser/react/use-navigation.ts +44 -65
  879. package/src/browser/react/use-params.ts +75 -0
  880. package/src/browser/react/use-pathname.ts +47 -0
  881. package/src/browser/react/use-router.ts +83 -0
  882. package/src/browser/react/use-search-params.ts +56 -0
  883. package/src/browser/react/use-segments.ts +80 -97
  884. package/src/browser/response-adapter.ts +73 -0
  885. package/src/browser/rsc-router.tsx +246 -64
  886. package/src/browser/scroll-restoration.ts +127 -52
  887. package/src/browser/segment-reconciler.ts +243 -0
  888. package/src/browser/segment-structure-assert.ts +16 -0
  889. package/src/browser/server-action-bridge.ts +510 -603
  890. package/src/browser/shallow.ts +6 -1
  891. package/src/browser/types.ts +152 -48
  892. package/src/browser/validate-redirect-origin.ts +29 -0
  893. package/src/build/generate-manifest.ts +84 -23
  894. package/src/build/generate-route-types.ts +39 -752
  895. package/src/build/index.ts +6 -5
  896. package/src/build/route-trie.ts +83 -31
  897. package/src/build/route-types/ast-helpers.ts +25 -0
  898. package/src/build/route-types/ast-route-extraction.ts +98 -0
  899. package/src/build/route-types/codegen.ts +102 -0
  900. package/src/build/route-types/include-resolution.ts +418 -0
  901. package/src/build/route-types/param-extraction.ts +48 -0
  902. package/src/build/route-types/per-module-writer.ts +128 -0
  903. package/src/build/route-types/router-processing.ts +618 -0
  904. package/src/build/route-types/scan-filter.ts +85 -0
  905. package/src/build/runtime-discovery.ts +231 -0
  906. package/src/cache/background-task.ts +34 -0
  907. package/src/cache/cache-key-utils.ts +44 -0
  908. package/src/cache/cache-policy.ts +125 -0
  909. package/src/cache/cache-runtime.ts +342 -0
  910. package/src/cache/cache-scope.ts +167 -307
  911. package/src/cache/cf/cf-cache-store.ts +573 -21
  912. package/src/cache/cf/index.ts +13 -3
  913. package/src/cache/document-cache.ts +116 -77
  914. package/src/cache/handle-capture.ts +81 -0
  915. package/src/cache/handle-snapshot.ts +41 -0
  916. package/src/cache/index.ts +1 -15
  917. package/src/cache/memory-segment-store.ts +191 -13
  918. package/src/cache/profile-registry.ts +73 -0
  919. package/src/cache/read-through-swr.ts +134 -0
  920. package/src/cache/segment-codec.ts +256 -0
  921. package/src/cache/taint.ts +153 -0
  922. package/src/cache/types.ts +72 -122
  923. package/src/client.rsc.tsx +3 -1
  924. package/src/client.tsx +113 -301
  925. package/src/component-utils.ts +4 -4
  926. package/src/components/DefaultDocument.tsx +5 -1
  927. package/src/context-var.ts +156 -0
  928. package/src/debug.ts +19 -9
  929. package/src/errors.ts +77 -7
  930. package/src/handle.ts +55 -10
  931. package/src/handles/MetaTags.tsx +73 -20
  932. package/src/handles/breadcrumbs.ts +66 -0
  933. package/src/handles/index.ts +1 -0
  934. package/src/handles/meta.ts +30 -13
  935. package/src/host/cookie-handler.ts +21 -15
  936. package/src/host/errors.ts +8 -8
  937. package/src/host/index.ts +4 -7
  938. package/src/host/pattern-matcher.ts +27 -27
  939. package/src/host/router.ts +61 -39
  940. package/src/host/testing.ts +8 -8
  941. package/src/host/types.ts +15 -7
  942. package/src/host/utils.ts +1 -1
  943. package/src/href-client.ts +65 -45
  944. package/src/index.rsc.ts +138 -21
  945. package/src/index.ts +206 -51
  946. package/src/internal-debug.ts +11 -0
  947. package/src/loader.rsc.ts +25 -143
  948. package/src/loader.ts +27 -10
  949. package/src/network-error-thrower.tsx +3 -1
  950. package/src/outlet-context.ts +1 -1
  951. package/src/outlet-provider.tsx +45 -0
  952. package/src/prerender/param-hash.ts +4 -2
  953. package/src/prerender/store.ts +159 -13
  954. package/src/prerender.ts +397 -29
  955. package/src/response-utils.ts +28 -0
  956. package/src/reverse.ts +209 -121
  957. package/src/root-error-boundary.tsx +41 -29
  958. package/src/route-content-wrapper.tsx +7 -4
  959. package/src/route-definition/dsl-helpers.ts +1134 -0
  960. package/src/route-definition/helper-factories.ts +200 -0
  961. package/src/route-definition/helpers-types.ts +478 -0
  962. package/src/route-definition/index.ts +55 -0
  963. package/src/route-definition/redirect.ts +101 -0
  964. package/src/route-definition/resolve-handler-use.ts +155 -0
  965. package/src/route-definition.ts +1 -1431
  966. package/src/route-map-builder.ts +162 -123
  967. package/src/route-name.ts +53 -0
  968. package/src/route-types.ts +66 -9
  969. package/src/router/content-negotiation.ts +215 -0
  970. package/src/router/debug-manifest.ts +72 -0
  971. package/src/router/error-handling.ts +9 -9
  972. package/src/router/find-match.ts +160 -0
  973. package/src/router/handler-context.ts +455 -86
  974. package/src/router/intercept-resolution.ts +35 -20
  975. package/src/router/lazy-includes.ts +237 -0
  976. package/src/router/loader-resolution.ts +359 -128
  977. package/src/router/logging.ts +251 -0
  978. package/src/router/manifest.ts +98 -32
  979. package/src/router/match-api.ts +195 -261
  980. package/src/router/match-context.ts +4 -2
  981. package/src/router/match-handlers.ts +440 -0
  982. package/src/router/match-middleware/background-revalidation.ts +108 -93
  983. package/src/router/match-middleware/cache-lookup.ts +415 -86
  984. package/src/router/match-middleware/cache-store.ts +91 -29
  985. package/src/router/match-middleware/intercept-resolution.ts +48 -21
  986. package/src/router/match-middleware/segment-resolution.ts +73 -9
  987. package/src/router/match-pipelines.ts +10 -45
  988. package/src/router/match-result.ts +135 -35
  989. package/src/router/metrics.ts +240 -15
  990. package/src/router/middleware-cookies.ts +55 -0
  991. package/src/router/middleware-types.ts +200 -0
  992. package/src/router/middleware.ts +373 -371
  993. package/src/router/navigation-snapshot.ts +182 -0
  994. package/src/router/pattern-matching.ts +251 -44
  995. package/src/router/prerender-match.ts +502 -0
  996. package/src/router/preview-match.ts +98 -0
  997. package/src/router/request-classification.ts +310 -0
  998. package/src/router/revalidation.ts +152 -39
  999. package/src/router/route-snapshot.ts +245 -0
  1000. package/src/router/router-context.ts +41 -21
  1001. package/src/router/router-interfaces.ts +484 -0
  1002. package/src/router/router-options.ts +618 -0
  1003. package/src/router/router-registry.ts +24 -0
  1004. package/src/router/segment-resolution/fresh.ts +748 -0
  1005. package/src/router/segment-resolution/helpers.ts +268 -0
  1006. package/src/router/segment-resolution/loader-cache.ts +199 -0
  1007. package/src/router/segment-resolution/revalidation.ts +1384 -0
  1008. package/src/router/segment-resolution/static-store.ts +67 -0
  1009. package/src/router/segment-resolution.ts +21 -1315
  1010. package/src/router/segment-wrappers.ts +291 -0
  1011. package/src/router/telemetry-otel.ts +299 -0
  1012. package/src/router/telemetry.ts +300 -0
  1013. package/src/router/timeout.ts +148 -0
  1014. package/src/router/trie-matching.ts +103 -30
  1015. package/src/router/types.ts +17 -9
  1016. package/src/router/url-params.ts +49 -0
  1017. package/src/router.ts +647 -1988
  1018. package/src/rsc/handler-context.ts +45 -0
  1019. package/src/rsc/handler.ts +864 -1114
  1020. package/src/rsc/helpers.ts +181 -19
  1021. package/src/rsc/index.ts +0 -20
  1022. package/src/rsc/loader-fetch.ts +229 -0
  1023. package/src/rsc/manifest-init.ts +90 -0
  1024. package/src/rsc/nonce.ts +14 -0
  1025. package/src/rsc/origin-guard.ts +141 -0
  1026. package/src/rsc/progressive-enhancement.ts +393 -0
  1027. package/src/rsc/response-error.ts +37 -0
  1028. package/src/rsc/response-route-handler.ts +360 -0
  1029. package/src/rsc/rsc-rendering.ts +253 -0
  1030. package/src/rsc/runtime-warnings.ts +42 -0
  1031. package/src/rsc/server-action.ts +358 -0
  1032. package/src/rsc/ssr-setup.ts +128 -0
  1033. package/src/rsc/types.ts +46 -11
  1034. package/src/search-params.ts +230 -0
  1035. package/src/segment-content-promise.ts +67 -0
  1036. package/src/segment-loader-promise.ts +122 -0
  1037. package/src/segment-system.tsx +134 -36
  1038. package/src/server/context.ts +333 -59
  1039. package/src/server/cookie-store.ts +190 -0
  1040. package/src/server/fetchable-loader-store.ts +37 -0
  1041. package/src/server/handle-store.ts +113 -15
  1042. package/src/server/loader-registry.ts +24 -64
  1043. package/src/server/request-context.ts +603 -109
  1044. package/src/server.ts +35 -155
  1045. package/src/ssr/index.tsx +103 -30
  1046. package/src/static-handler.ts +126 -0
  1047. package/src/theme/ThemeProvider.tsx +21 -15
  1048. package/src/theme/ThemeScript.tsx +5 -5
  1049. package/src/theme/constants.ts +5 -2
  1050. package/src/theme/index.ts +4 -14
  1051. package/src/theme/theme-context.ts +4 -30
  1052. package/src/theme/theme-script.ts +21 -18
  1053. package/src/types/boundaries.ts +158 -0
  1054. package/src/types/cache-types.ts +198 -0
  1055. package/src/types/error-types.ts +192 -0
  1056. package/src/types/global-namespace.ts +100 -0
  1057. package/src/types/handler-context.ts +759 -0
  1058. package/src/types/index.ts +88 -0
  1059. package/src/types/loader-types.ts +209 -0
  1060. package/src/types/request-scope.ts +126 -0
  1061. package/src/types/route-config.ts +170 -0
  1062. package/src/types/route-entry.ts +120 -0
  1063. package/src/types/segments.ts +150 -0
  1064. package/src/types.ts +1 -1757
  1065. package/src/urls/include-helper.ts +207 -0
  1066. package/src/urls/index.ts +53 -0
  1067. package/src/urls/path-helper-types.ts +372 -0
  1068. package/src/urls/path-helper.ts +364 -0
  1069. package/src/urls/pattern-types.ts +107 -0
  1070. package/src/urls/response-types.ts +108 -0
  1071. package/src/urls/type-extraction.ts +372 -0
  1072. package/src/urls/urls-function.ts +98 -0
  1073. package/src/urls.ts +1 -1282
  1074. package/src/use-loader.tsx +161 -81
  1075. package/src/vite/debug.ts +184 -0
  1076. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  1077. package/src/vite/discovery/discover-routers.ts +376 -0
  1078. package/src/vite/discovery/prerender-collection.ts +486 -0
  1079. package/src/vite/discovery/route-types-writer.ts +258 -0
  1080. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  1081. package/src/vite/discovery/state.ts +117 -0
  1082. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  1083. package/src/vite/index.ts +15 -1963
  1084. package/src/vite/plugin-types.ts +103 -0
  1085. package/src/vite/plugins/cjs-to-esm.ts +98 -0
  1086. package/src/vite/plugins/client-ref-dedup.ts +131 -0
  1087. package/src/vite/plugins/client-ref-hashing.ts +117 -0
  1088. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  1089. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  1090. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  1091. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +107 -64
  1092. package/src/vite/plugins/expose-id-utils.ts +299 -0
  1093. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  1094. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  1095. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  1096. package/src/vite/plugins/expose-ids/router-transform.ts +127 -0
  1097. package/src/vite/plugins/expose-ids/types.ts +45 -0
  1098. package/src/vite/plugins/expose-internal-ids.ts +816 -0
  1099. package/src/vite/plugins/performance-tracks.ts +96 -0
  1100. package/src/vite/plugins/refresh-cmd.ts +127 -0
  1101. package/src/vite/plugins/use-cache-transform.ts +336 -0
  1102. package/src/vite/plugins/version-injector.ts +83 -0
  1103. package/src/vite/plugins/version-plugin.ts +266 -0
  1104. package/src/vite/plugins/virtual-entries.ts +123 -0
  1105. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  1106. package/src/vite/rango.ts +497 -0
  1107. package/src/vite/router-discovery.ts +1111 -0
  1108. package/src/vite/utils/ast-handler-extract.ts +517 -0
  1109. package/src/vite/utils/banner.ts +36 -0
  1110. package/src/vite/utils/bundle-analysis.ts +137 -0
  1111. package/src/vite/utils/manifest-utils.ts +70 -0
  1112. package/src/vite/utils/package-resolution.ts +161 -0
  1113. package/src/vite/utils/prerender-utils.ts +221 -0
  1114. package/src/vite/utils/shared-utils.ts +170 -0
  1115. package/CLAUDE.md +0 -43
  1116. package/src/browser/lru-cache.ts +0 -69
  1117. package/src/browser/request-controller.ts +0 -164
  1118. package/src/cache/memory-store.ts +0 -253
  1119. package/src/router.gen.ts +0 -6
  1120. package/src/urls.gen.ts +0 -8
  1121. package/src/vite/expose-handle-id.ts +0 -209
  1122. package/src/vite/expose-loader-id.ts +0 -426
  1123. package/src/vite/expose-location-state-id.ts +0 -177
  1124. package/src/vite/expose-prerender-handler-id.ts +0 -429
  1125. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@vitejs/plugin-rsc/types" />
2
- /// <reference path="../vite/version.d.ts" />
2
+ /// <reference path="../vite/plugins/version.d.ts" />
3
3
  /**
4
4
  * RSC Request Handler
5
5
  *
@@ -8,68 +8,88 @@
8
8
  */
9
9
 
10
10
  import { createElement } from "react";
11
- import { renderSegments } from "../segment-system.js";
12
- import { RouteNotFoundError, RouterError } from "../errors.js";
13
- import type { ResponseError } from "../urls.js";
14
- import { getLoaderLazy } from "../server/loader-registry.js";
15
- import {
16
- matchMiddleware,
17
- executeMiddleware,
18
- executeLoaderMiddleware,
19
- } from "../router/middleware.js";
11
+ import { RouteNotFoundError } from "../errors.js";
12
+ import { matchMiddleware, executeMiddleware } from "../router/middleware.js";
20
13
  import {
21
14
  runWithRequestContext,
22
15
  setRequestContextParams,
23
16
  requireRequestContext,
17
+ getRequestContext,
18
+ _getRequestContext,
24
19
  createRequestContext,
25
- type ExecutionContext,
26
20
  } from "../server/request-context.js";
27
21
  import * as rscDeps from "@vitejs/plugin-rsc/rsc";
28
-
29
22
  import type {
30
23
  RscPayload,
31
- ReactFormState,
32
24
  CreateRSCHandlerOptions,
25
+ LoadSSRModule,
26
+ SSRModule,
33
27
  } from "./types.js";
34
- import { hasBodyContent, createResponseWithMergedHeaders } from "./helpers.js";
35
- import { generateNonce } from "./nonce.js";
28
+ import {
29
+ createResponseWithMergedHeaders,
30
+ finalizeResponse,
31
+ interceptRedirectForPartial,
32
+ buildRouteMiddlewareEntries,
33
+ } from "./helpers.js";
34
+ import { isWebSocketUpgradeResponse } from "../response-utils.js";
35
+ import {
36
+ handleResponseRoute,
37
+ type ResponseRouteMatch,
38
+ } from "./response-route-handler.js";
39
+ import { generateNonce, nonce as nonceToken } from "./nonce.js";
36
40
  import { VERSION } from "@rangojs/router:version";
37
41
  import type { ErrorPhase } from "../types.js";
42
+ import type { RouterRequestInput } from "../router/router-interfaces.js";
38
43
  import { invokeOnError } from "../router/error-handling.js";
39
44
  import {
40
- getGlobalRouteMap,
45
+ createReverseFunction,
46
+ stripInternalParams,
47
+ } from "../router/handler-context.js";
48
+ import { getRouterContext } from "../router/router-context.js";
49
+ import { resolveSink, safeEmit } from "../router/telemetry.js";
50
+ import { contextSet } from "../context-var.js";
51
+ import {
41
52
  hasCachedManifest,
42
- setCachedManifest,
43
53
  getRouteTrie,
44
- setRouteTrie,
45
54
  getPrecomputedEntries,
46
55
  waitForManifestReady,
56
+ getRouterManifest,
57
+ getRouterTrie,
47
58
  } from "../route-map-builder.js";
48
-
49
- /**
50
- * Build a ResponseError payload from a caught error.
51
- * RouterError messages are always exposed (developer-crafted).
52
- * Standard Error messages are hidden in production.
53
- */
54
- function createResponseErrorPayload(error: unknown, isDev: boolean): ResponseError {
55
- if (error instanceof RouterError) {
56
- return {
57
- message: error.message,
58
- code: error.code,
59
- ...(error.type ? { type: error.type } : {}),
60
- ...(isDev && error.stack ? { stack: error.stack } : {}),
61
- };
62
- }
63
- if (error instanceof Error) {
64
- return {
65
- message: isDev ? error.message : "Internal Server Error",
66
- ...(isDev && error.stack ? { stack: error.stack } : {}),
67
- };
68
- }
69
- return {
70
- message: isDev ? String(error) : "Internal Server Error",
71
- };
72
- }
59
+ import type { HandlerContext } from "./handler-context.js";
60
+ import type { SegmentCacheStore } from "../cache/types.js";
61
+ import { buildRouterTrieFromUrlpatterns } from "./manifest-init.js";
62
+ import { handleProgressiveEnhancement } from "./progressive-enhancement.js";
63
+ import {
64
+ executeServerAction,
65
+ revalidateAfterAction,
66
+ type ActionContinuation,
67
+ } from "./server-action.js";
68
+ import { handleLoaderFetch } from "./loader-fetch.js";
69
+ import { checkRequestOrigin, type OriginCheckPhase } from "./origin-guard.js";
70
+ import { handleRscRendering } from "./rsc-rendering.js";
71
+ import {
72
+ withTimeout,
73
+ RouterTimeoutError,
74
+ createDefaultTimeoutResponse,
75
+ type TimeoutPhase,
76
+ } from "../router/timeout.js";
77
+ import {
78
+ createMetricsStore,
79
+ appendMetric,
80
+ buildMetricsTiming,
81
+ } from "../router/metrics.js";
82
+ import {
83
+ startSSRSetup,
84
+ getSSRSetup,
85
+ mayNeedSSR,
86
+ SSR_SETUP_VAR,
87
+ } from "./ssr-setup.js";
88
+ import {
89
+ classifyRequest,
90
+ type RequestPlan,
91
+ type ExecutableRequestPlan,
92
+ } from "../router/request-classification.js";
73
93
 
74
94
  /**
75
95
  * Create an RSC request handler.
@@ -121,33 +141,182 @@ export function createRSCHandler<
121
141
  decodeFormState,
122
142
  } = deps;
123
143
 
124
- // Use provided loadSSRModule or default to vite RSC module loader
125
- const loadSSRModule =
144
+ // Use provided loadSSRModule or default to vite RSC module loader.
145
+ // In production the SSR module is stable across requests, so memoize
146
+ // the dynamic import to avoid repeated module resolution overhead.
147
+ // In dev mode Vite may hot-reload the module, so skip memoization.
148
+ const rawLoadSSRModule: LoadSSRModule =
126
149
  options.loadSSRModule ??
127
150
  (() => import.meta.viteRsc.loadModule("ssr", "index"));
151
+ let _ssrModulePromise: Promise<SSRModule> | undefined;
152
+ const loadSSRModule: LoadSSRModule =
153
+ process.env.NODE_ENV === "production"
154
+ ? () =>
155
+ (_ssrModulePromise ??= rawLoadSSRModule().catch((err) => {
156
+ _ssrModulePromise = undefined;
157
+ throw err;
158
+ }))
159
+ : rawLoadSSRModule;
128
160
 
129
161
  /**
130
- * Wrapper for invokeOnError that binds the router's onError callback.
131
- * Uses the shared utility from router/error-handling.ts for consistent behavior.
162
+ * Per-request error reporter that deduplicates via the ALS request context.
163
+ *
164
+ * Uses the same _reportedErrors WeakSet as the router layer so errors
165
+ * that propagate across layers are only reported once per request.
132
166
  */
133
167
  function callOnError(
134
168
  error: unknown,
135
169
  phase: ErrorPhase,
136
170
  context: Parameters<typeof invokeOnError<TEnv>>[3],
137
171
  ): void {
172
+ // Guard: abort signal handlers fire asynchronously outside the ALS
173
+ // request scope, so the context may be gone. Skip dedup in that
174
+ // case — the error is from a cancelled stream, not a real failure.
175
+ const reqCtx = _getRequestContext();
176
+ if (error != null && typeof error === "object" && reqCtx) {
177
+ if (reqCtx._reportedErrors.has(error)) return;
178
+ reqCtx._reportedErrors.add(error);
179
+ }
138
180
  invokeOnError(router.onError, error, phase, context, "RSC");
139
181
  }
140
182
 
141
- return async function handler(
183
+ function getRequiredRouteMap(): Record<string, string> {
184
+ const routeMap = getRouterManifest(router.id);
185
+ if (!routeMap) {
186
+ throw new Error(
187
+ `Route manifest for router "${router.id}" is not available.`,
188
+ );
189
+ }
190
+ return routeMap;
191
+ }
192
+
193
+ /**
194
+ * Handle a timeout by reporting the error, emitting telemetry,
195
+ * and returning either the custom onTimeout response or a default 504.
196
+ */
197
+ async function handleTimeoutResponse(
142
198
  request: Request,
143
- env: TEnv & { ctx?: ExecutionContext } = {} as TEnv & {
144
- ctx?: ExecutionContext;
199
+ env: TEnv,
200
+ url: URL,
201
+ phase: TimeoutPhase,
202
+ durationMs: number,
203
+ routeKey?: string,
204
+ actionId?: string,
205
+ ): Promise<Response> {
206
+ const timeoutError = new RouterTimeoutError(phase, durationMs);
207
+
208
+ callOnError(timeoutError, phase === "action" ? "action" : "handler", {
209
+ request,
210
+ url,
211
+ env,
212
+ routeKey,
213
+ actionId,
214
+ handledByBoundary: false,
215
+ metadata: { timeout: true, phase, durationMs },
216
+ });
217
+
218
+ try {
219
+ const routerCtx = getRouterContext();
220
+ if (routerCtx?.telemetry) {
221
+ safeEmit(resolveSink(routerCtx.telemetry), {
222
+ type: "request.timeout" as const,
223
+ timestamp: performance.now(),
224
+ requestId: routerCtx.requestId,
225
+ phase,
226
+ pathname: url.pathname,
227
+ routeKey,
228
+ actionId,
229
+ durationMs,
230
+ customHandler: !!router.onTimeout,
231
+ });
232
+ }
233
+ } catch {
234
+ // Router context may not be available
235
+ }
236
+
237
+ if (router.onTimeout) {
238
+ try {
239
+ return await router.onTimeout({
240
+ phase,
241
+ request,
242
+ url,
243
+ env,
244
+ routeKey,
245
+ actionId,
246
+ durationMs,
247
+ });
248
+ } catch (e) {
249
+ if (process.env.NODE_ENV !== "production") {
250
+ console.error("[RSC] onTimeout callback error:", e);
251
+ }
252
+ return createDefaultTimeoutResponse(phase);
253
+ }
254
+ }
255
+
256
+ return createDefaultTimeoutResponse(phase);
257
+ }
258
+
259
+ /**
260
+ * Build a 200 Flight response that carries a redirect URL and optional state.
261
+ * Used when a partial/action request results in a redirect -- fetch
262
+ * auto-follows 3xx so we send the redirect as payload metadata instead.
263
+ */
264
+ function createRedirectFlightResponse(
265
+ redirectUrl: string,
266
+ locationState?: Record<string, unknown>,
267
+ ): Response {
268
+ const redirectPayload: RscPayload = {
269
+ metadata: {
270
+ pathname: redirectUrl,
271
+ segments: [],
272
+ redirect: { url: redirectUrl },
273
+ ...(locationState && { locationState }),
274
+ },
275
+ };
276
+ const rscStream = renderToReadableStream<RscPayload>(redirectPayload);
277
+ return createResponseWithMergedHeaders(rscStream, {
278
+ status: 200,
279
+ headers: { "content-type": "text/x-component;charset=utf-8" },
280
+ });
281
+ }
282
+
283
+ // Bundle shared dependencies for extracted handler functions.
284
+ // callOnError reads from ALS so it's inherently per-request scoped.
285
+ const handlerCtx: HandlerContext<TEnv> = {
286
+ router,
287
+ version,
288
+ renderToReadableStream,
289
+ decodeReply,
290
+ createTemporaryReferenceSet,
291
+ loadServerAction,
292
+ decodeAction,
293
+ decodeFormState,
294
+ loadSSRModule,
295
+ callOnError,
296
+ getRequiredRouteMap,
297
+ createRedirectFlightResponse,
298
+ resolveStreamMode: async (request, env, url) => {
299
+ const resolver = router.ssr?.resolveStreaming;
300
+ if (!resolver) return "stream";
301
+ return resolver({ request, env, url });
145
302
  },
303
+ };
304
+
305
+ return async function handler(
306
+ request: Request,
307
+ input: RouterRequestInput<TEnv> = {},
146
308
  ): Promise<Response> {
147
309
  const handlerStart = performance.now();
310
+ // Create the metrics store at handler start so handler:total has startTime=0
311
+ // and all metrics are relative to the request entry point.
312
+ const earlyMetricsStore = router.debugPerformance
313
+ ? createMetricsStore(true, handlerStart)
314
+ : undefined;
315
+
316
+ const { env = {} as TEnv, vars: initialVars, ctx: executionCtx } = input;
148
317
 
149
318
  // Connection warmup: return 204 immediately before any processing
150
- if (router.warmupEnabled && request.method === "HEAD") {
319
+ if (router?.warmupEnabled && request.method === "HEAD") {
151
320
  const warmupUrl = new URL(request.url);
152
321
  if (warmupUrl.searchParams.has("_rsc_warmup")) {
153
322
  return new Response(null, { status: 204 });
@@ -171,24 +340,27 @@ export function createRSCHandler<
171
340
  const mwMatchDur = performance.now() - mwMatchStart;
172
341
 
173
342
  // Shared variables between middleware and route handlers
174
- // Initialize from env.Variables if provided (allows pre-seeding from worker entry)
175
- const variables: Record<string, any> = {
176
- ...((env as any)?.Variables ?? {}),
177
- };
343
+ // Initialize from input.vars if provided (allows pre-seeding from worker entry)
344
+ const variables: Record<string, any> = initialVars
345
+ ? { ...initialVars }
346
+ : {};
178
347
 
179
- // Store nonce in variables so middleware can access via ctx.get('nonce')
348
+ // Store nonce via ContextVar token and string key for backward compat
180
349
  if (nonce) {
350
+ contextSet(variables, nonceToken, nonce);
181
351
  variables.nonce = nonce;
182
352
  }
183
353
 
184
354
  // Resolve cache store configuration
185
355
  // Priority: options.cache (handler override) > router.cache (router default)
186
356
  // Store is enabled only if: config provided, enabled, and no ?__no_cache query param
187
- let cacheStore = undefined;
357
+ let cacheStore: SegmentCacheStore | undefined;
188
358
  const cacheOption = options.cache ?? router.cache;
189
359
  if (cacheOption && !url.searchParams.has("__no_cache")) {
190
360
  const cacheConfig =
191
- typeof cacheOption === "function" ? cacheOption(env) : cacheOption;
361
+ typeof cacheOption === "function"
362
+ ? cacheOption(env, executionCtx)
363
+ : cacheOption;
192
364
 
193
365
  if (cacheConfig.enabled !== false) {
194
366
  cacheStore = cacheConfig.store;
@@ -201,60 +373,43 @@ export function createRSCHandler<
201
373
  // via setManifestReadyPromise(). In dev mode (Cloudflare), Miniflare runs
202
374
  // in a separate isolate where module-level state doesn't carry over, so
203
375
  // we generate inline from the router's urlpatterns.
376
+ //
377
+ // In multi-router setups (e.g. createHostRouter), each router must have
378
+ // its own per-router manifest. We check per-router data first: even if
379
+ // the global manifest was set by a different router, this router still
380
+ // needs its own trie and manifest for correct matching.
204
381
  const manifestCacheStart = performance.now();
205
- if (!hasCachedManifest()) {
206
- const readyPromise = waitForManifestReady();
207
- if (readyPromise) {
208
- await readyPromise;
209
- }
210
- if (!hasCachedManifest() && router.urlpatterns) {
211
- // Cloudflare dev: generate manifest inline (no caching needed)
212
- const { generateManifest } =
213
- await import("../build/generate-manifest.js");
214
- const generated = generateManifest(router.urlpatterns);
215
- setCachedManifest(generated.routeManifest);
216
- if (
217
- generated._routeAncestry &&
218
- Object.keys(generated._routeAncestry).length > 0
219
- ) {
220
- const { buildRouteTrie } = await import("../build/route-trie.js");
221
- // Map each route to its include() staticPrefix so the trie
222
- // returns the correct sp for lazy entry lookup in findMatch.
223
- const routeToStaticPrefix: Record<string, string> = {};
224
- for (const name of Object.keys(generated.routeManifest)) {
225
- routeToStaticPrefix[name] = "";
226
- }
227
- // Override with prefix from include() entries so the trie
228
- // returns the correct sp for lazy entry lookup in findMatch.
229
- if (generated.prefixTree) {
230
- for (const [prefix, node] of Object.entries(generated.prefixTree)) {
231
- for (const route of (node as { routes: string[] }).routes) {
232
- routeToStaticPrefix[route] = prefix;
233
- }
234
- }
235
- }
236
- const trie = buildRouteTrie(
237
- generated.routeManifest,
238
- generated._routeAncestry,
239
- routeToStaticPrefix,
240
- generated.routeTrailingSlash,
241
- undefined, // prerenderRouteNames
242
- undefined, // passthroughRouteNames
243
- generated.responseTypeRoutes,
244
- );
245
- setRouteTrie(trie);
382
+ const hasRouterData = getRouterManifest(router.id) !== undefined;
383
+ if (!hasRouterData) {
384
+ if (!hasCachedManifest()) {
385
+ const readyPromise = waitForManifestReady();
386
+ if (readyPromise) {
387
+ await readyPromise;
246
388
  }
247
389
  }
248
- if (!hasCachedManifest()) {
390
+ if (!getRouterManifest(router.id) && router.urlpatterns) {
391
+ // Cloudflare dev: generate manifest inline for this router.
392
+ // Each router generates its own manifest independently so
393
+ // multi-router setups (host routing) work correctly.
394
+ await buildRouterTrieFromUrlpatterns(router);
395
+ }
396
+ if (!getRouterManifest(router.id) && !hasCachedManifest()) {
249
397
  throw new Error(
250
398
  'Route manifest not available. Ensure "virtual:rsc-router/routes-manifest" is imported in your entry file.',
251
399
  );
252
400
  }
253
401
  }
254
- const manifestCacheDur = performance.now() - manifestCacheStart;
255
402
 
256
- // Note: Route map for useHref() is loaded lazily via getGlobalRouteMap()
257
- // This allows it to include all routes from lazy includes after manifest loading
403
+ // Rebuild the trie when the manifest exists but the per-router trie is
404
+ // missing. This happens in dev mode after HMR: the virtual module sets
405
+ // the manifest (from fresh gen files) but the trie is intentionally not
406
+ // injected to avoid stale discovery-time data. Without the trie, route
407
+ // matching falls back to regex iteration which does not handle wildcard
408
+ // priority correctly (catch-all patterns match before specific routes).
409
+ if (!getRouterTrie(router.id) && router.urlpatterns) {
410
+ await buildRouterTrieFromUrlpatterns(router);
411
+ }
412
+ const manifestCacheDur = performance.now() - manifestCacheStart;
258
413
 
259
414
  // Create unified request context with all methods
260
415
  // Includes: stub response, handle store, loader memoization, use(), cookies, headers, cache store
@@ -266,9 +421,27 @@ export function createRSCHandler<
266
421
  url,
267
422
  variables,
268
423
  cacheStore,
269
- executionContext: env.ctx,
424
+ cacheProfiles: router.cacheProfiles,
425
+ executionContext: executionCtx,
270
426
  themeConfig: router.themeConfig,
271
427
  });
428
+ if (earlyMetricsStore) {
429
+ requestContext._debugPerformance = true;
430
+ requestContext._metricsStore = earlyMetricsStore;
431
+ }
432
+ // Wire background error reporting so "use cache" and other subsystems
433
+ // can surface non-fatal errors through the router's onError callback.
434
+ requestContext._reportBackgroundError = (
435
+ error: unknown,
436
+ category: string,
437
+ ) => {
438
+ callOnError(error, "cache", {
439
+ request,
440
+ url,
441
+ metadata: { category },
442
+ });
443
+ };
444
+
272
445
  const ctxCreateDur = performance.now() - ctxCreateStart;
273
446
 
274
447
  // Accumulate handler-level timing for Server-Timing header
@@ -290,6 +463,9 @@ export function createRSCHandler<
290
463
  // - Server components during rendering
291
464
  // - Error boundaries
292
465
  // - Streaming
466
+ // Store basename on request context (scoped per-request via existing ALS)
467
+ requestContext._basename = router.basename;
468
+
293
469
  return runWithRequestContext(requestContext, async () => {
294
470
  // Core handler logic (wrapped by middleware)
295
471
  const coreHandler = async (): Promise<Response> => {
@@ -297,292 +473,104 @@ export function createRSCHandler<
297
473
  };
298
474
 
299
475
  // Execute middleware chain if any, otherwise call core handler directly
476
+ let response: Response;
300
477
  if (matchedMiddleware.length > 0) {
301
- return executeMiddleware(
478
+ const mwResponse = await executeMiddleware(
302
479
  matchedMiddleware,
303
480
  request,
304
481
  env,
305
482
  variables,
306
483
  coreHandler,
484
+ createReverseFunction(getRequiredRouteMap()),
307
485
  );
308
- }
309
-
310
- return coreHandler();
311
- });
312
- };
313
-
314
- // Core request handling logic (separated for middleware wrapping)
315
- async function coreRequestHandler(
316
- request: Request,
317
- env: TEnv,
318
- url: URL,
319
- variables: Record<string, any>,
320
- nonce: string | undefined,
321
- ): Promise<Response> {
322
- // First, check for route-level middleware
323
- const previewStart = performance.now();
324
- const preview = await router.previewMatch(request, env);
325
- const previewDur = performance.now() - previewStart;
326
- const handlerTiming: string[] = variables.__handlerTiming || [];
327
- handlerTiming.push(`handler-preview-match;dur=${previewDur.toFixed(2)}`);
328
- // Response route short-circuit: skip entire RSC pipeline
329
- if (preview?.responseType && preview.handler) {
330
- const isPartial = url.searchParams.has("_rsc_partial");
331
-
332
- // Partial requests (client-side navigation) to response routes
333
- // get X-RSC-Reload to trigger hard navigation in the browser
334
- if (isPartial) {
335
- const cleanUrl = new URL(url);
336
- cleanUrl.searchParams.delete("_rsc_partial");
337
- cleanUrl.searchParams.delete("_rsc_segments");
338
- cleanUrl.searchParams.delete("_rsc_v");
339
- cleanUrl.searchParams.delete("_rsc_stale");
340
- cleanUrl.searchParams.delete("_rsc_action");
341
- cleanUrl.searchParams.delete("_rsc_prev");
342
-
343
- return createResponseWithMergedHeaders(null, {
344
- status: 200,
345
- headers: {
346
- "X-RSC-Reload": cleanUrl.toString(),
347
- "content-type": "text/x-component;charset=utf-8",
348
- },
349
- });
350
- }
351
-
352
- // Build lightweight context for response handler
353
- const bindings = (env as any)?.Bindings ?? env;
354
- const reqCtx = requireRequestContext();
355
- const responseHandlerCtx = {
356
- request,
357
- params: preview.params || {},
358
- env: bindings,
359
- searchParams: url.searchParams,
360
- url,
361
- pathname: url.pathname,
362
- href: (name: string, hrefParams?: Record<string, string>) => {
363
- if (name.startsWith("/")) {
364
- if (!hrefParams) return name;
365
- return name.replace(/:([^/]+)/g, (_, key) => {
366
- const value = hrefParams[key];
367
- if (value === undefined) throw new Error(`Missing param "${key}" for path "${name}"`);
368
- return encodeURIComponent(value);
369
- });
370
- }
371
- return name;
372
- },
373
- get: (key: string) => variables[key],
374
- header: (name: string, value: string) => reqCtx.header(name, value),
375
- setCookie: (name: string, value: string, options?: any) => reqCtx.setCookie(name, value, options),
376
- };
377
-
378
- // Call handler directly, wrapped by route middleware if present
379
- const callHandler = async () => {
380
- // JSON response routes: wrap in { data } / { error } envelope
381
- if (preview.responseType === "json") {
382
- const errorCtx = { request, url, env };
383
- try {
384
- const result = await (preview.handler as Function)(responseHandlerCtx);
385
- if (result instanceof Response) {
386
- const mergedHeaders: Record<string, string> = {};
387
- result.headers.forEach((value, key) => {
388
- mergedHeaders[key] = value;
389
- });
390
- return createResponseWithMergedHeaders(result.body, {
391
- status: result.status,
392
- headers: mergedHeaders,
393
- });
394
- }
395
- return createResponseWithMergedHeaders(
396
- JSON.stringify({ data: result }),
397
- { status: 200, headers: { "content-type": "application/json;charset=utf-8" } },
398
- );
399
- } catch (error) {
400
- callOnError(error, "handler", errorCtx);
401
- const isDev = process.env.NODE_ENV !== "production";
402
- const status = error instanceof RouterError ? error.status : 500;
403
- return createResponseWithMergedHeaders(
404
- JSON.stringify({ error: createResponseErrorPayload(error, isDev) }),
405
- { status, headers: { "content-type": "application/json;charset=utf-8" } },
406
- );
407
- }
408
- }
409
-
410
- // Non-JSON response routes: catch errors and return plain Response
411
- const errorCtx = { request, url, env };
412
- try {
413
- const result = await (preview.handler as Function)(responseHandlerCtx);
414
-
415
- if (result instanceof Response) {
416
- // Handler returned a Response directly -- pass through
417
- const mergedHeaders: Record<string, string> = {};
418
- result.headers.forEach((value, key) => {
419
- mergedHeaders[key] = value;
420
- });
421
- return createResponseWithMergedHeaders(result.body, {
422
- status: result.status,
423
- headers: mergedHeaders,
424
- });
425
- }
426
486
 
427
- // Auto-wrap based on response type tag
428
- switch (preview.responseType) {
429
- case "text":
430
- return createResponseWithMergedHeaders(
431
- String(result),
432
- { status: 200, headers: { "content-type": "text/plain;charset=utf-8" } },
433
- );
434
- case "html":
435
- return createResponseWithMergedHeaders(
436
- String(result),
437
- { status: 200, headers: { "content-type": "text/html;charset=utf-8" } },
438
- );
439
- case "xml":
440
- return createResponseWithMergedHeaders(
441
- String(result),
442
- { status: 200, headers: { "content-type": "application/xml;charset=utf-8" } },
443
- );
444
- case "md":
445
- return createResponseWithMergedHeaders(
446
- String(result),
447
- { status: 200, headers: { "content-type": "text/markdown;charset=utf-8" } },
448
- );
449
- default:
450
- // image, stream, any -- must return Response
451
- throw new Error(
452
- `Response route handler for "${preview.responseType}" must return a Response object, got ${typeof result}`
453
- );
454
- }
455
- } catch (error) {
456
- callOnError(error, "handler", errorCtx);
457
- const isDev = process.env.NODE_ENV !== "production";
458
- const status = error instanceof RouterError ? error.status : 500;
459
- const message = error instanceof RouterError
460
- ? error.message
461
- : isDev && error instanceof Error
462
- ? error.message
463
- : "Internal Server Error";
464
- return createResponseWithMergedHeaders(message, {
465
- status,
466
- headers: { "content-type": "text/plain;charset=utf-8" },
467
- });
468
- }
469
- };
470
-
471
- // Wrap callHandler to append Vary: Accept on content-negotiated responses
472
- const callHandlerWithVary = async () => {
473
- const response = await callHandler();
474
- if (preview.negotiated) {
475
- response.headers.append("Vary", "Accept");
487
+ if (
488
+ url.searchParams.has("_rsc_partial") ||
489
+ url.searchParams.has("_rsc_action")
490
+ ) {
491
+ const intercepted = interceptRedirectForPartial(
492
+ mwResponse,
493
+ createRedirectFlightResponse,
494
+ );
495
+ response = intercepted ?? finalizeResponse(mwResponse);
496
+ } else {
497
+ response = finalizeResponse(mwResponse);
476
498
  }
477
- return response;
478
- };
479
-
480
- if (preview.routeMiddleware && preview.routeMiddleware.length > 0) {
481
- const middlewareEntries = preview.routeMiddleware.map((mw) => ({
482
- entry: {
483
- pattern: null,
484
- regex: null,
485
- paramNames: [],
486
- handler: mw.handler,
487
- mountPrefix: null,
488
- },
489
- params: mw.params,
490
- }));
491
- return executeMiddleware(middlewareEntries, request, env, variables, callHandlerWithVary);
499
+ } else {
500
+ response = await coreHandler();
492
501
  }
493
502
 
494
- return callHandlerWithVary();
495
- }
496
-
497
- // Wrap RSC handler to append Vary: Accept on content-negotiated routes
498
- const rscHandler = async () => {
499
- const response = await coreRequestHandlerInner(request, env, url, variables, nonce);
500
- if (preview?.negotiated) {
501
- response.headers.append("Vary", "Accept");
503
+ // Finalize metrics after all middleware (including post-next work)
504
+ // has completed so :post spans are captured in the timeline.
505
+ // Handler timing parts are always emitted (even without debug metrics)
506
+ // so non-debug requests still get bootstrap Server-Timing entries.
507
+ const handlerTimingArr: string[] = variables.__handlerTiming || [];
508
+ // Preserve any existing Server-Timing set by response routes or middleware
509
+ const existingTiming = response.headers.get("Server-Timing");
510
+ const timingParts = existingTiming
511
+ ? [existingTiming, ...handlerTimingArr]
512
+ : [...handlerTimingArr];
513
+
514
+ const metricsStore = requestContext._metricsStore;
515
+ if (metricsStore) {
516
+ // When the store was created at handler start (earlyMetricsStore),
517
+ // handler:total covers the full request. When ctx.debugPerformance()
518
+ // created the store mid-request, use its requestStart to avoid a
519
+ // negative startTime offset.
520
+ const totalStart = earlyMetricsStore
521
+ ? handlerStart
522
+ : metricsStore.requestStart;
523
+ appendMetric(
524
+ metricsStore,
525
+ "handler:total",
526
+ totalStart,
527
+ performance.now() - totalStart,
528
+ );
529
+ const metricsTiming = buildMetricsTiming(
530
+ request.method,
531
+ url.pathname,
532
+ metricsStore,
533
+ );
534
+ if (metricsTiming) timingParts.push(metricsTiming);
502
535
  }
503
- return response;
504
- };
505
-
506
- if (preview?.routeMiddleware && preview.routeMiddleware.length > 0) {
507
- // Convert route middleware to app middleware format for execution
508
- const middlewareEntries = preview.routeMiddleware.map((mw) => ({
509
- entry: {
510
- pattern: null,
511
- regex: null,
512
- paramNames: [],
513
- handler: mw.handler,
514
- mountPrefix: null,
515
- },
516
- params: mw.params,
517
- }));
518
536
 
519
- // Execute route middleware wrapping the actual request handling
520
- return executeMiddleware(middlewareEntries, request, env, variables, rscHandler);
521
- }
537
+ const fullTiming = timingParts.join(", ");
538
+ if (fullTiming && !isWebSocketUpgradeResponse(response)) {
539
+ response.headers.set("Server-Timing", fullTiming);
540
+ }
522
541
 
523
- // No route middleware, proceed directly
524
- return rscHandler();
525
- }
542
+ return response;
543
+ });
544
+ };
526
545
 
527
- // Inner request handler (actual RSC logic, wrapped by route middleware if any)
528
- async function coreRequestHandlerInner(
546
+ // Core request handling logic (separated for middleware wrapping).
547
+ // Uses the classify → execute model: classifyRequest produces a RequestPlan,
548
+ // then execution dispatches on the plan mode.
549
+ async function coreRequestHandler(
529
550
  request: Request,
530
551
  env: TEnv,
531
552
  url: URL,
532
553
  variables: Record<string, any>,
533
554
  nonce: string | undefined,
534
555
  ): Promise<Response> {
535
- const isPartial = url.searchParams.has("_rsc_partial");
536
- const isAction =
537
- request.headers.has("rsc-action") || url.searchParams.has("_rsc_action");
538
- const actionId =
539
- request.headers.get("rsc-action") || url.searchParams.get("_rsc_action");
540
-
541
- // Version mismatch detection - client may have stale code after HMR/deployment
542
- // If versions don't match, tell the client to reload
543
- const clientVersion = url.searchParams.get("_rsc_v");
544
- if (version && clientVersion && clientVersion !== version) {
545
- console.log(
546
- `[RSC] Version mismatch: client=${clientVersion}, server=${version}. Forcing reload.`,
547
- );
556
+ const handlerTiming: string[] = variables.__handlerTiming || [];
548
557
 
549
- // Clean URL by removing RSC params
550
- const cleanUrl = new URL(url);
551
- cleanUrl.searchParams.delete("_rsc_partial");
552
- cleanUrl.searchParams.delete("_rsc_segments");
553
- cleanUrl.searchParams.delete("_rsc_v");
554
- cleanUrl.searchParams.delete("_rsc_stale");
555
- cleanUrl.searchParams.delete("_rsc_action");
556
- cleanUrl.searchParams.delete("_rsc_prev");
557
-
558
- // For actions, reload current page (referer)
559
- // For navigation, load the target URL
560
- const reloadUrl = isAction
561
- ? request.headers.get("referer") || cleanUrl.toString()
562
- : cleanUrl.toString();
563
-
564
- // Return special response that tells client to reload
565
- return createResponseWithMergedHeaders(null, {
566
- status: 200,
567
- headers: {
568
- "X-RSC-Reload": reloadUrl,
569
- "content-type": "text/x-component;charset=utf-8",
570
- },
571
- });
572
- }
573
- // Debug manifest endpoint: ?__debug_manifest on any route.
574
- // Always available in dev, requires allowDebugManifest option in production.
558
+ // Debug manifest endpoint: handled before classification since it
559
+ // doesn't need a route match and needs trie access from the closure.
575
560
  const isDev = process.env.NODE_ENV !== "production";
576
561
  if (
577
562
  url.searchParams.has("__debug_manifest") &&
578
563
  (isDev || router.allowDebugManifest)
579
564
  ) {
580
- const trie = getRouteTrie();
581
- const { extractAncestryFromTrie } = await import("../build/route-trie.js");
565
+ const trie = getRouterTrie(router.id) ?? getRouteTrie();
566
+ const routeManifest = getRequiredRouteMap();
567
+ const { extractAncestryFromTrie } =
568
+ await import("../build/route-trie.js");
582
569
  return new Response(
583
570
  JSON.stringify(
584
571
  {
585
- routeManifest: getGlobalRouteMap(),
572
+ routerId: router.id,
573
+ routeManifest,
586
574
  routeAncestry: trie ? extractAncestryFromTrie(trie) : {},
587
575
  routeTrie: trie,
588
576
  precomputedEntries: getPrecomputedEntries(),
@@ -596,848 +584,610 @@ export function createRSCHandler<
596
584
  );
597
585
  }
598
586
 
599
- // Get handle store from request context (created at start of request)
600
- const handleStore = requireRequestContext()._handleStore;
601
-
587
+ // ---- 1. Classify ----
588
+ // classifyRequest may throw RouteNotFoundError for unknown routes.
589
+ // In that case, fall through to a full-render plan so the pipeline
590
+ // can render the 404 page via the existing error handling path.
591
+ const classifyStart = performance.now();
592
+ let plan: RequestPlan<TEnv>;
602
593
  try {
603
- // ============================================================================
604
- // PROGRESSIVE ENHANCEMENT: No-JS Form Submissions
605
- // ============================================================================
606
- const progressiveResult = await handleProgressiveEnhancement(
607
- request,
608
- env,
609
- url,
610
- isAction,
611
- handleStore,
612
- nonce,
613
- );
614
- if (progressiveResult) {
615
- return progressiveResult;
594
+ plan = await classifyRequest<TEnv>(request, url, {
595
+ findMatch: router.findMatch,
596
+ routerVersion: version,
597
+ routerId: router.id,
598
+ });
599
+ } catch (error) {
600
+ if (
601
+ error instanceof RouteNotFoundError ||
602
+ (error instanceof Error && error.name === "RouteNotFoundError")
603
+ ) {
604
+ // Let the render path handle 404 — match()/matchPartial() will
605
+ // re-throw RouteNotFoundError and the catch block in
606
+ // executeRenderWithMiddleware renders the not-found page.
607
+ plan = {
608
+ mode: "full-render",
609
+ route: {
610
+ matched: null as any,
611
+ manifestEntry: null as any,
612
+ entries: [],
613
+ routeKey: "",
614
+ localRouteName: "",
615
+ params: {},
616
+ routeMiddleware: [],
617
+ cacheScope: null,
618
+ isPassthrough: false,
619
+ },
620
+ negotiated: false,
621
+ };
622
+ } else {
623
+ throw error;
616
624
  }
617
-
618
- // ============================================================================
619
- // SERVER ACTION EXECUTION (JavaScript-enabled client)
620
- // ============================================================================
621
- if (isAction && actionId) {
622
- return handleServerAction(request, env, url, actionId, handleStore);
625
+ }
626
+ const classifyDur = performance.now() - classifyStart;
627
+ handlerTiming.push(`handler-classify;dur=${classifyDur.toFixed(2)}`);
628
+
629
+ // ---- 2. Terminal plans (no execution needed) ----
630
+ if (plan.mode === "redirect") {
631
+ // Redirects are handled by the pipeline (match/matchPartial),
632
+ // but for partial requests we short-circuit with a Flight redirect.
633
+ if (url.searchParams.has("_rsc_partial")) {
634
+ return createRedirectFlightResponse(plan.redirectUrl);
623
635
  }
636
+ // Full requests: let the pipeline handle the redirect via match()
637
+ // which returns { redirect: url }. Fall through to full-render.
638
+ }
624
639
 
625
- // ============================================================================
626
- // LOADER FETCH EXECUTION (data fetching with RSC serialization)
627
- // ============================================================================
628
- const isLoaderRequest = url.searchParams.has("_rsc_loader");
629
- if (isLoaderRequest) {
630
- return handleLoaderFetch(request, env, url, variables);
631
- }
640
+ if (plan.mode === "version-mismatch") {
641
+ console.log(
642
+ `[RSC] Version mismatch: client=${url.searchParams.get("_rsc_v")}, server=${version}. Forcing reload.`,
643
+ );
644
+ return createResponseWithMergedHeaders(null, {
645
+ status: 200,
646
+ headers: {
647
+ "X-RSC-Reload": plan.reloadUrl,
648
+ "content-type": "text/x-component;charset=utf-8",
649
+ },
650
+ });
651
+ }
632
652
 
633
- // ============================================================================
634
- // REGULAR RSC RENDERING (Navigation)
635
- // ============================================================================
636
- // Note: Must use "return await" for try/catch to catch async rejections
637
- return await handleRscRendering(
653
+ // ---- 3. Origin guard (gate for action/loader/PE modes) ----
654
+ const originPhase: OriginCheckPhase | null =
655
+ plan.mode === "action"
656
+ ? "action"
657
+ : plan.mode === "loader"
658
+ ? "loader"
659
+ : plan.mode === "pe-render"
660
+ ? "pe-form"
661
+ : null;
662
+ if (originPhase) {
663
+ const originResult = await checkRequestOrigin(
638
664
  request,
639
- env,
640
665
  url,
641
- isPartial,
642
- handleStore,
643
- nonce,
666
+ router.originCheck,
667
+ env,
668
+ router.id,
669
+ originPhase,
644
670
  );
645
- } catch (error) {
646
- // Check if middleware/handler returned Response
647
- if (error instanceof Response) {
648
- // During partial (client-side navigation), a 200 Response from a handler
649
- // means the route serves raw content (JSON, text, etc.), not JSX.
650
- // Signal the browser to hard-navigate so it renders the raw response.
651
- // Only for 200 — redirects (3xx) work already because the browser follows
652
- // them automatically to a URL that serves Flight data.
653
- if (isPartial && error.status === 200) {
654
- console.warn(
655
- `[RSC] Route handler at ${url.pathname} returned a Response during client-side navigation. ` +
656
- `Falling back to hard navigation. Use data-external on the <Link> to avoid the extra round-trip.`,
657
- );
658
- const cleanUrl = new URL(url);
659
- cleanUrl.searchParams.delete("_rsc_partial");
660
- cleanUrl.searchParams.delete("_rsc_segments");
661
- cleanUrl.searchParams.delete("_rsc_v");
662
- cleanUrl.searchParams.delete("_rsc_stale");
663
- cleanUrl.searchParams.delete("_rsc_action");
664
- cleanUrl.searchParams.delete("_rsc_prev");
665
- return createResponseWithMergedHeaders(null, {
666
- status: 200,
667
- headers: {
668
- "X-RSC-Reload": cleanUrl.toString(),
669
- "content-type": "text/x-component;charset=utf-8",
670
- },
671
- });
672
- }
673
- return error;
674
- }
671
+ if (originResult) {
672
+ const originError = new Error(
673
+ `Origin check rejected: ${request.headers.get("origin") ?? "none"} vs ${request.headers.get("host") ?? "none"}`,
674
+ );
675
+ originError.name = "OriginCheckError";
675
676
 
676
- // Render 404 page for unmatched routes
677
- // Check both instanceof and error.name for cross-bundle compatibility
678
- const isRouteNotFound =
679
- error instanceof RouteNotFoundError ||
680
- (error instanceof Error && error.name === "RouteNotFoundError");
681
- if (isRouteNotFound) {
682
- callOnError(error, "routing", {
677
+ callOnError(originError, "origin", {
683
678
  request,
684
679
  url,
685
680
  env,
686
- handledByBoundary: true, // Handled by notFound component
687
- });
688
-
689
- // Get notFound component from router options or use default
690
- const notFoundOption = router.notFound;
691
- const notFoundComponent =
692
- typeof notFoundOption === "function"
693
- ? notFoundOption({ pathname: url.pathname })
694
- : (notFoundOption ?? createElement("h1", null, "Not Found"));
695
-
696
- // Create a simple segment for the 404 page
697
- const notFoundSegment = {
698
- id: "notFound",
699
- namespace: "notFound",
700
- type: "route" as const,
701
- index: 0,
702
- component: notFoundComponent,
703
- params: {},
704
- };
705
-
706
- // Render with rootLayout to maintain app shell
707
- const root = await renderSegments([notFoundSegment], {
708
- rootLayout: router.rootLayout,
709
- // No routeName for not-found routes
710
- });
711
-
712
- const payload: RscPayload = {
713
- root,
681
+ handledByBoundary: false,
714
682
  metadata: {
715
- pathname: url.pathname,
716
- segments: [notFoundSegment],
717
- matched: [],
718
- diff: [],
719
- isPartial: false,
720
- handles: handleStore.stream(),
721
- version,
722
- themeConfig: router.themeConfig,
723
- warmupEnabled: router.warmupEnabled,
724
- initialTheme: requireRequestContext().theme,
725
- // No routeName for not-found routes
683
+ phase: originPhase,
684
+ origin: request.headers.get("origin"),
685
+ host: request.headers.get("host"),
726
686
  },
727
- };
728
-
729
- const rscStream = renderToReadableStream(payload);
730
-
731
- // Determine if this is an RSC request or HTML request
732
- const isRscRequest =
733
- (!request.headers.get("accept")?.includes("text/html") &&
734
- !url.searchParams.has("__html")) ||
735
- url.searchParams.has("__rsc");
687
+ });
736
688
 
737
- if (isRscRequest) {
738
- return createResponseWithMergedHeaders(rscStream, {
739
- status: 404,
740
- headers: { "content-type": "text/x-component;charset=utf-8" },
741
- });
689
+ try {
690
+ const routerCtx = getRouterContext();
691
+ if (routerCtx?.telemetry) {
692
+ safeEmit(resolveSink(routerCtx.telemetry), {
693
+ type: "request.origin-rejected" as const,
694
+ timestamp: performance.now(),
695
+ requestId: routerCtx.requestId,
696
+ method: request.method,
697
+ pathname: url.pathname,
698
+ phase: originPhase,
699
+ origin: request.headers.get("origin"),
700
+ host: request.headers.get("host"),
701
+ });
702
+ }
703
+ } catch {
704
+ // Router context may not be available
742
705
  }
743
706
 
744
- // Delegate to SSR for HTML response
745
- const ssrModule = await loadSSRModule();
746
- const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
747
-
748
- return createResponseWithMergedHeaders(htmlStream, {
749
- status: 404,
750
- headers: { "content-type": "text/html;charset=utf-8" },
751
- });
707
+ return originResult;
752
708
  }
753
-
754
- // Report unhandled errors
755
- callOnError(error, "routing", {
756
- request,
757
- url,
758
- env,
759
- handledByBoundary: false,
760
- });
761
- console.error(`[RSC] Error:`, error);
762
- throw error;
763
709
  }
710
+
711
+ // ---- 4. Execute ----
712
+ return executeRequest(
713
+ plan as ExecutableRequestPlan<TEnv>,
714
+ request,
715
+ env,
716
+ url,
717
+ variables,
718
+ nonce,
719
+ );
764
720
  }
765
721
 
766
- // ============================================================================
767
- // PROGRESSIVE ENHANCEMENT HANDLER
768
- // When JavaScript is disabled, React renders forms with hidden fields
769
- // ($ACTION_REF_*, $ACTION_KEY) containing the action reference.
770
- // We detect these and return HTML instead of RSC stream.
771
- // ============================================================================
772
- async function handleProgressiveEnhancement(
722
+ // Execute a classified request plan. Dispatches to the appropriate handler
723
+ // based on plan.mode. Lives in the createRSCHandler closure for access to
724
+ // handlerCtx, router, callOnError, etc.
725
+ // Only receives executable plans (version-mismatch is handled above).
726
+ async function executeRequest(
727
+ plan: ExecutableRequestPlan<TEnv>,
773
728
  request: Request,
774
729
  env: TEnv,
775
730
  url: URL,
776
- isAction: boolean,
777
- handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
731
+ variables: Record<string, any>,
778
732
  nonce: string | undefined,
779
- ): Promise<Response | null> {
780
- const contentType = request.headers.get("content-type") || "";
781
- const isFormSubmission =
782
- contentType.includes("multipart/form-data") ||
783
- contentType.includes("application/x-www-form-urlencoded");
784
-
785
- if (request.method !== "POST" || isAction || !isFormSubmission) {
786
- return null;
787
- }
788
-
789
- // Clone the request to read FormData without consuming it
790
- const formData = await request.clone().formData();
791
-
792
- // Look for React's progressive enhancement hidden fields
793
- let isDirectAction = false;
794
- let isUseActionState = false;
795
- let directActionId: string | null = null;
796
-
797
- formData.forEach((_value, key) => {
798
- if (key.startsWith("$ACTION_ID_")) {
799
- isDirectAction = true;
800
- directActionId = key.slice("$ACTION_ID_".length);
801
- } else if (key.startsWith("$ACTION_REF_")) {
802
- isUseActionState = true;
803
- }
804
- });
805
-
806
- if (!isDirectAction && !isUseActionState) {
807
- return null;
808
- }
809
-
810
- // Execute action and return HTML
811
- let actionResult: unknown = undefined;
812
- let reactFormState: ReactFormState | null = null;
733
+ ): Promise<Response> {
734
+ // Common setup
735
+ const handleStore = requireRequestContext()._handleStore;
813
736
 
814
- if (isUseActionState) {
815
- try {
816
- const boundAction = await decodeAction(formData);
817
- actionResult = await boundAction();
818
- } catch (error) {
819
- callOnError(error, "action", {
820
- request,
821
- url,
822
- env,
823
- handledByBoundary: false,
824
- });
825
- console.error("[RSC] Progressive enhancement action error:", error);
826
- }
827
- } else if (isDirectAction && directActionId) {
828
- const temporaryReferences = createTemporaryReferenceSet();
829
-
830
- let args: unknown[] = [];
737
+ // Wire up error reporting for late streaming-handle failures
738
+ handleStore.onError = (error: Error) => {
739
+ const reqCtx = requireRequestContext();
740
+ callOnError(error, "handler", {
741
+ request,
742
+ url,
743
+ routeKey: reqCtx._routeName,
744
+ params: reqCtx.params as Record<string, string>,
745
+ handledByBoundary: true,
746
+ });
831
747
  try {
832
- args = await decodeReply(formData, { temporaryReferences });
748
+ const routerCtx = getRouterContext();
749
+ if (routerCtx?.telemetry) {
750
+ safeEmit(resolveSink(routerCtx.telemetry), {
751
+ type: "handler.error" as const,
752
+ timestamp: performance.now(),
753
+ requestId: routerCtx.requestId,
754
+ error,
755
+ handledByBoundary: true,
756
+ pathname: url.pathname,
757
+ routeKey: reqCtx._routeName,
758
+ params: reqCtx.params as Record<string, string>,
759
+ });
760
+ }
833
761
  } catch {
834
- args = [formData];
762
+ // Router context may not be available (e.g. prerender path)
835
763
  }
764
+ };
836
765
 
837
- try {
838
- const loadedAction = await loadServerAction(directActionId);
839
- actionResult = await loadedAction.apply(null, args);
840
- } catch (error) {
841
- callOnError(error, "action", {
766
+ // Set route params early so all execution paths can access ctx.params.
767
+ // Also store the classified snapshot so match/matchPartial can reuse it
768
+ // instead of calling resolveRoute again.
769
+ if (plan.mode !== "redirect") {
770
+ setRequestContextParams(plan.route.params, plan.route.routeKey);
771
+ requireRequestContext()._classifiedRoute = plan.route;
772
+ }
773
+
774
+ const routeReverse = createReverseFunction(getRequiredRouteMap());
775
+
776
+ // ---- Response route: skip entire RSC pipeline ----
777
+ if (plan.mode === "response") {
778
+ // Build ResponseRouteMatch from plan fields. handleResponseRoute
779
+ // expects a flat object with params at the top level.
780
+ const responseMatch: ResponseRouteMatch = {
781
+ responseType: plan.responseType,
782
+ handler: plan.handler,
783
+ params: plan.route.params,
784
+ negotiated: plan.negotiated,
785
+ manifestEntry: plan.manifestEntry,
786
+ routeMiddleware: plan.routeMiddleware,
787
+ };
788
+ const responseOutcome = await withTimeout(
789
+ handleResponseRoute(
790
+ handlerCtx,
791
+ responseMatch,
842
792
  request,
793
+ env,
843
794
  url,
795
+ variables,
796
+ ),
797
+ router.timeouts.renderStartMs,
798
+ "render-start",
799
+ );
800
+ if (responseOutcome.timedOut) {
801
+ return handleTimeoutResponse(
802
+ request,
844
803
  env,
845
- actionId: directActionId,
846
- handledByBoundary: false,
847
- });
848
- console.error("[RSC] Progressive enhancement action error:", error);
804
+ url,
805
+ "render-start",
806
+ responseOutcome.durationMs,
807
+ plan.route.routeKey,
808
+ );
849
809
  }
810
+ const response = responseOutcome.result;
811
+ if (plan.negotiated && !isWebSocketUpgradeResponse(response)) {
812
+ response.headers.append("Vary", "Accept");
813
+ }
814
+ return response;
850
815
  }
851
816
 
852
- // Decode form state for useActionState progressive enhancement
853
- try {
854
- reactFormState = await decodeFormState(actionResult, formData);
855
- } catch (error) {
856
- callOnError(error, "action", {
817
+ // SSR setup: kick off in parallel for modes that need HTML rendering.
818
+ // Placed after response-route short-circuit so response/mime routes
819
+ // never pay for SSR work.
820
+ if (plan.mode !== "loader" && mayNeedSSR(request, url)) {
821
+ variables[SSR_SETUP_VAR] = startSSRSetup(
822
+ handlerCtx,
857
823
  request,
858
- url,
859
824
  env,
860
- handledByBoundary: false,
861
- });
862
- console.error("[RSC] Failed to decode form state:", error);
863
- }
864
-
865
- // Re-render the page and return HTML
866
- const renderRequest = new Request(url.toString(), {
867
- method: "GET",
868
- headers: new Headers({ accept: "text/html" }),
869
- });
870
-
871
- const match = await router.match(renderRequest, env);
872
-
873
- if (match.redirect) {
874
- return new Response(null, {
875
- status: 308,
876
- headers: { Location: match.redirect },
877
- });
825
+ url,
826
+ router.debugPerformance
827
+ ? () => requireRequestContext()._metricsStore
828
+ : undefined,
829
+ );
878
830
  }
879
831
 
880
- const root = renderSegments(match.segments, {
881
- rootLayout: router.rootLayout,
882
- });
883
-
884
- const payload: RscPayload = {
885
- root,
886
- metadata: {
887
- pathname: url.pathname,
888
- segments: match.segments,
889
- matched: match.matched,
890
- diff: match.diff,
891
- isPartial: false,
892
- rootLayout: router.rootLayout,
893
- handles: handleStore.stream(),
894
- version,
895
- themeConfig: router.themeConfig,
896
- warmupEnabled: router.warmupEnabled,
897
- initialTheme: requireRequestContext().theme,
898
- },
899
- formState: actionResult,
900
- };
901
-
902
- const rscStream = renderToReadableStream<RscPayload>(payload);
903
- const ssrModule = await loadSSRModule();
904
- const htmlStream = await ssrModule.renderHTML(rscStream, {
905
- formState: reactFormState,
906
- nonce,
907
- });
908
-
909
- return new Response(htmlStream, {
910
- headers: { "content-type": "text/html;charset=utf-8" },
911
- });
912
- }
913
-
914
- // ============================================================================
915
- // SERVER ACTION HANDLER
916
- // ============================================================================
917
- async function handleServerAction(
918
- request: Request,
919
- env: TEnv,
920
- url: URL,
921
- actionId: string,
922
- handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
923
- ): Promise<Response> {
924
- const temporaryReferences = createTemporaryReferenceSet();
925
-
926
- // Decode action arguments from request body
927
- const contentType = request.headers.get("content-type") || "";
928
- let args: unknown[] = [];
929
- let actionFormData: FormData | undefined;
930
-
931
- try {
932
- const body = contentType.includes("multipart/form-data")
933
- ? await request.formData()
934
- : await request.text();
935
-
936
- if (body instanceof FormData) {
937
- actionFormData = body;
938
- }
939
-
940
- if (hasBodyContent(body)) {
941
- args = await decodeReply(body, { temporaryReferences });
942
- }
943
- } catch (error) {
944
- callOnError(error, "action", {
832
+ // ---- Loader fetch ----
833
+ if (plan.mode === "loader") {
834
+ return handleLoaderFetch(
835
+ handlerCtx,
945
836
  request,
946
- url,
947
837
  env,
948
- actionId,
949
- handledByBoundary: false,
950
- });
951
- throw new Error(`Failed to decode action arguments: ${error}`, {
952
- cause: error,
953
- });
838
+ url,
839
+ variables,
840
+ plan.route.params,
841
+ );
954
842
  }
955
843
 
956
- // Execute the server action
957
- let returnValue: { ok: boolean; data: unknown };
958
- let actionStatus = 200;
959
- let loadedAction: Function | undefined;
960
-
961
- try {
962
- loadedAction = await loadServerAction(actionId);
963
- const data = await loadedAction!.apply(null, args);
964
- returnValue = { ok: true, data };
965
- } catch (error) {
966
- returnValue = { ok: false, data: error };
967
- actionStatus = 500;
968
-
969
- // Try to render error boundary
970
- const errorResult = await router.matchError(request, env, error, "route");
971
-
972
- // Report the action error (handledByBoundary indicates if error boundary will render)
973
- callOnError(error, "action", {
844
+ // ---- Progressive enhancement ----
845
+ if (plan.mode === "pe-render") {
846
+ const peResult = await handleProgressiveEnhancement(
847
+ handlerCtx,
974
848
  request,
975
- url,
976
849
  env,
977
- actionId,
978
- handledByBoundary: !!errorResult,
979
- });
980
-
981
- if (errorResult) {
982
- setRequestContextParams(errorResult.params);
983
-
984
- const payload: RscPayload = {
985
- root: null,
986
- metadata: {
987
- pathname: url.pathname,
988
- segments: errorResult.segments,
989
- isPartial: true,
990
- matched: errorResult.matched,
991
- diff: errorResult.diff,
992
- isError: true,
993
- handles: handleStore.stream(),
994
- version,
995
- },
996
- returnValue,
997
- };
998
-
999
- const rscStream = renderToReadableStream<RscPayload>(payload, {
1000
- temporaryReferences,
1001
- });
1002
-
1003
- return createResponseWithMergedHeaders(rscStream, {
1004
- status: actionStatus,
1005
- headers: { "content-type": "text/x-component;charset=utf-8" },
1006
- });
1007
- }
850
+ url,
851
+ false, // isAction = false for PE
852
+ handleStore,
853
+ nonce,
854
+ {
855
+ routeMiddleware: plan.route.routeMiddleware,
856
+ variables,
857
+ routeReverse,
858
+ },
859
+ );
860
+ if (peResult) return peResult;
861
+ // PE handler returned null (not a PE form) — fall through to render
1008
862
  }
1009
863
 
1010
- // Revalidate after action
1011
- const resolvedActionId =
1012
- (loadedAction as { $id?: string; $$id?: string } | undefined)?.$id ??
1013
- (loadedAction as { $$id?: string } | undefined)?.$$id ??
1014
- actionId;
1015
- const actionContext = {
1016
- actionId: resolvedActionId,
1017
- actionUrl: new URL(request.url),
1018
- actionResult: returnValue.data,
1019
- formData: actionFormData,
1020
- };
1021
-
1022
- const matchResult = await router.matchPartial(request, env, actionContext);
1023
-
1024
- if (!matchResult) {
1025
- // Fall back to full render
1026
- const fullMatch = await router.match(request, env);
1027
- setRequestContextParams(fullMatch.params);
1028
-
1029
- if (fullMatch.redirect) {
1030
- return createResponseWithMergedHeaders(null, {
1031
- status: 308,
1032
- headers: { Location: fullMatch.redirect },
864
+ // ---- Action: execute action, then revalidate wrapped in route middleware ----
865
+ if (plan.mode === "action") {
866
+ let actionContinuation: ActionContinuation | undefined;
867
+ try {
868
+ const actionOutcome = await withTimeout(
869
+ executeServerAction(
870
+ handlerCtx,
871
+ request,
872
+ env,
873
+ url,
874
+ plan.actionId,
875
+ handleStore,
876
+ ),
877
+ router.timeouts.actionMs,
878
+ "action",
879
+ );
880
+ if (actionOutcome.timedOut) {
881
+ return handleTimeoutResponse(
882
+ request,
883
+ env,
884
+ url,
885
+ "action",
886
+ actionOutcome.durationMs,
887
+ plan.route.routeKey,
888
+ plan.actionId,
889
+ );
890
+ }
891
+ const result = actionOutcome.result;
892
+ // Response means redirect or error boundary — done.
893
+ if (result instanceof Response) return result;
894
+ actionContinuation = result;
895
+ } catch (error) {
896
+ callOnError(error, "action", {
897
+ request,
898
+ url,
899
+ env,
900
+ actionId: plan.actionId,
901
+ handledByBoundary: false,
1033
902
  });
903
+ console.error(`[RSC] Action error:`, error);
904
+ throw error;
1034
905
  }
1035
906
 
1036
- const renderStart = performance.now();
1037
- const root = renderSegments(fullMatch.segments, {
1038
- rootLayout: router.rootLayout,
1039
- isAction: true,
1040
- });
1041
- const renderDuration = performance.now() - renderStart;
1042
- const serverTiming = fullMatch.serverTiming
1043
- ? `${fullMatch.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
1044
- : `rendering;dur=${renderDuration.toFixed(2)}`;
1045
-
1046
- const payload: RscPayload = {
1047
- root,
1048
- metadata: {
1049
- pathname: url.pathname,
1050
- segments: fullMatch.segments,
1051
- matched: fullMatch.matched,
1052
- diff: fullMatch.diff,
1053
- handles: handleStore.stream(),
1054
- version,
1055
- },
1056
- returnValue,
1057
- };
1058
-
1059
- const rscStream = renderToReadableStream<RscPayload>(payload, {
1060
- temporaryReferences,
1061
- });
1062
-
1063
- const headers: Record<string, string> = {
1064
- "content-type": "text/x-component;charset=utf-8",
1065
- };
1066
- if (serverTiming) {
1067
- headers["Server-Timing"] = serverTiming;
1068
- }
1069
-
1070
- return createResponseWithMergedHeaders(rscStream, {
1071
- status: actionStatus,
1072
- headers,
1073
- });
907
+ // Revalidation render wrapped in route middleware.
908
+ // Actions from client-side navigation include _rsc_partial — preserve
909
+ // the partial flag so the revalidation returns a Flight stream, not HTML.
910
+ // App-switch is already excluded by classifyRequest (would be full-render).
911
+ const isPartialAction = url.searchParams.has("_rsc_partial");
912
+ return executeRenderWithMiddleware(
913
+ plan.route.routeMiddleware,
914
+ plan.negotiated,
915
+ plan.route.routeKey,
916
+ routeReverse,
917
+ request,
918
+ env,
919
+ url,
920
+ variables,
921
+ nonce,
922
+ handleStore,
923
+ isPartialAction,
924
+ actionContinuation,
925
+ );
1074
926
  }
1075
927
 
1076
- // Return updated segments
1077
- setRequestContextParams(matchResult.params);
1078
-
1079
- const renderStart = performance.now();
1080
-
1081
- const renderDuration = performance.now() - renderStart;
1082
- const serverTiming = matchResult.serverTiming
1083
- ? `${matchResult.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
1084
- : `rendering;dur=${renderDuration.toFixed(2)}`;
1085
-
1086
- const payload: RscPayload = {
1087
- root: null,
1088
- metadata: {
1089
- pathname: url.pathname,
1090
- segments: matchResult.segments,
1091
- isPartial: true,
1092
- matched: matchResult.matched,
1093
- diff: matchResult.diff,
1094
- slots: matchResult.slots,
1095
- handles: handleStore.stream(),
1096
- version,
1097
- },
1098
- returnValue,
1099
- };
1100
-
1101
- const rscStream = renderToReadableStream<RscPayload>(payload, {
1102
- temporaryReferences,
1103
- });
928
+ // ---- Full render / Partial render (or PE that fell through) ----
929
+ if (plan.mode === "full-render" || plan.mode === "partial-render") {
930
+ const isPartial = plan.mode === "partial-render";
931
+ return executeRenderWithMiddleware(
932
+ plan.route.routeMiddleware,
933
+ plan.negotiated,
934
+ plan.route.routeKey,
935
+ routeReverse,
936
+ request,
937
+ env,
938
+ url,
939
+ variables,
940
+ nonce,
941
+ handleStore,
942
+ isPartial,
943
+ );
944
+ }
1104
945
 
1105
- const actionHeaders: Record<string, string> = {
1106
- "content-type": "text/x-component;charset=utf-8",
1107
- };
1108
- if (serverTiming) {
1109
- actionHeaders["Server-Timing"] = serverTiming;
946
+ // PE that fell through (handleProgressiveEnhancement returned null)
947
+ // falls back to full render
948
+ if (plan.mode === "pe-render") {
949
+ return executeRenderWithMiddleware(
950
+ plan.route.routeMiddleware,
951
+ false,
952
+ plan.route.routeKey,
953
+ routeReverse,
954
+ request,
955
+ env,
956
+ url,
957
+ variables,
958
+ nonce,
959
+ handleStore,
960
+ false,
961
+ );
1110
962
  }
1111
963
 
1112
- return createResponseWithMergedHeaders(rscStream, {
1113
- status: actionStatus,
1114
- headers: actionHeaders,
1115
- });
964
+ // Redirect plan that wasn't handled above (full-page redirect — let
965
+ // the pipeline handle it via match() which returns { redirect: url })
966
+ return executeRenderWithMiddleware(
967
+ plan.route.routeMiddleware,
968
+ false,
969
+ plan.route.routeKey,
970
+ routeReverse,
971
+ request,
972
+ env,
973
+ url,
974
+ variables,
975
+ nonce,
976
+ handleStore,
977
+ false,
978
+ );
1116
979
  }
1117
980
 
1118
- // ============================================================================
1119
- // LOADER FETCH HANDLER
1120
- // Supports GET (params in query string) and POST/PUT/PATCH/DELETE (JSON body)
1121
- // ============================================================================
1122
- async function handleLoaderFetch(
981
+ // Shared render execution: wraps handleRscRendering (or revalidateAfterAction)
982
+ // in route middleware and timeout handling. Consolidates the pattern used by
983
+ // action-revalidate, full-render, and partial-render modes.
984
+ async function executeRenderWithMiddleware(
985
+ routeMiddleware: import("../router/middleware-types.js").CollectedMiddleware[],
986
+ negotiated: boolean,
987
+ routeKey: string,
988
+ routeReverse: ReturnType<typeof createReverseFunction>,
1123
989
  request: Request,
1124
990
  env: TEnv,
1125
991
  url: URL,
1126
992
  variables: Record<string, any>,
993
+ nonce: string | undefined,
994
+ handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
995
+ isPartial: boolean,
996
+ actionContinuation?: ActionContinuation,
1127
997
  ): Promise<Response> {
1128
- const loaderId = url.searchParams.get("_rsc_loader");
1129
-
1130
- if (!loaderId) {
1131
- return createResponseWithMergedHeaders("Missing _rsc_loader parameter", {
1132
- status: 400,
1133
- });
1134
- }
1135
-
1136
- // Look up loader lazily
1137
- const registeredLoader = await getLoaderLazy(loaderId);
1138
- if (!registeredLoader) {
1139
- return createResponseWithMergedHeaders(
1140
- `Loader "${loaderId}" not found in registry`,
1141
- { status: 404 },
1142
- );
1143
- }
1144
-
1145
- // Parse params and body based on request method
1146
- let loaderParams: Record<string, string> = {};
1147
- let loaderBody: unknown = undefined;
1148
- const isBodyMethod = request.method !== "GET" && request.method !== "HEAD";
1149
-
1150
- if (isBodyMethod) {
998
+ const renderHandler = async (): Promise<Response> => {
1151
999
  try {
1152
- const contentType = request.headers.get("content-type") || "";
1153
- if (contentType.includes("application/json")) {
1154
- const jsonBody = (await request.json()) as {
1155
- params?: Record<string, string>;
1156
- body?: unknown;
1157
- };
1158
- loaderParams = jsonBody.params ?? {};
1159
- loaderBody = jsonBody.body;
1160
- }
1161
- } catch {
1162
- return createResponseWithMergedHeaders("Invalid JSON body", {
1163
- status: 400,
1164
- });
1165
- }
1166
- } else {
1167
- const loaderParamsJson = url.searchParams.get("_rsc_loader_params");
1168
- if (loaderParamsJson) {
1169
- try {
1170
- loaderParams = JSON.parse(loaderParamsJson);
1171
- } catch {
1172
- return createResponseWithMergedHeaders(
1173
- "Invalid _rsc_loader_params JSON",
1174
- { status: 400 },
1000
+ let response: Response;
1001
+ if (actionContinuation) {
1002
+ response = await revalidateAfterAction(
1003
+ handlerCtx,
1004
+ request,
1005
+ env,
1006
+ url,
1007
+ handleStore,
1008
+ actionContinuation,
1009
+ );
1010
+ } else {
1011
+ response = await handleRscRendering(
1012
+ handlerCtx,
1013
+ request,
1014
+ env,
1015
+ url,
1016
+ isPartial,
1017
+ handleStore,
1018
+ nonce,
1175
1019
  );
1176
1020
  }
1177
- }
1178
- }
1021
+ if (negotiated && !isWebSocketUpgradeResponse(response)) {
1022
+ response.headers.append("Vary", "Accept");
1023
+ }
1024
+ return response;
1025
+ } catch (error) {
1026
+ // Check if middleware/handler returned Response
1027
+ if (error instanceof Response) {
1028
+ // During partial (client-side navigation), a 200 Response from a handler
1029
+ // means the route serves raw content (JSON, text, etc.), not JSX.
1030
+ // Signal the browser to hard-navigate so it renders the raw response.
1031
+ if (isPartial && error.status === 200) {
1032
+ console.warn(
1033
+ `[RSC] Route handler at ${url.pathname} returned a Response during client-side navigation. ` +
1034
+ `Falling back to hard navigation. Use data-external on the <Link> to avoid the extra round-trip.`,
1035
+ );
1036
+ return createResponseWithMergedHeaders(null, {
1037
+ status: 200,
1038
+ headers: {
1039
+ "X-RSC-Reload": stripInternalParams(url).toString(),
1040
+ "content-type": "text/x-component;charset=utf-8",
1041
+ },
1042
+ });
1043
+ }
1179
1044
 
1180
- // Execute the loader with middleware
1181
- try {
1182
- const { fn, middleware } = registeredLoader;
1045
+ if (isPartial) {
1046
+ const intercepted = interceptRedirectForPartial(
1047
+ error,
1048
+ createRedirectFlightResponse,
1049
+ );
1050
+ if (intercepted) return intercepted;
1051
+ }
1183
1052
 
1184
- return await executeLoaderMiddleware(
1185
- middleware,
1186
- request,
1187
- env,
1188
- loaderParams,
1189
- variables,
1190
- async () => {
1191
- const ctx = requireRequestContext();
1192
- const loaderCtx: any = {
1193
- ...ctx,
1194
- params: loaderParams,
1195
- body: loaderBody,
1196
- };
1053
+ return error;
1054
+ }
1197
1055
 
1198
- const result = await fn(loaderCtx);
1056
+ // Render 404 page for unmatched routes
1057
+ const isRouteNotFound =
1058
+ error instanceof RouteNotFoundError ||
1059
+ (error instanceof Error && error.name === "RouteNotFoundError");
1060
+ if (isRouteNotFound) {
1061
+ callOnError(error, "routing", {
1062
+ request,
1063
+ url,
1064
+ env,
1065
+ handledByBoundary: true,
1066
+ });
1199
1067
 
1200
- interface LoaderPayload {
1201
- loaderResult: unknown;
1202
- }
1203
- const loaderPayload: LoaderPayload = { loaderResult: result };
1204
- const rscStream =
1205
- renderToReadableStream<LoaderPayload>(loaderPayload);
1068
+ const notFoundOption = router.notFound;
1069
+ const notFoundComponent =
1070
+ typeof notFoundOption === "function"
1071
+ ? notFoundOption({ pathname: url.pathname })
1072
+ : (notFoundOption ?? createElement("h1", null, "Not Found"));
1073
+
1074
+ const notFoundSegment = {
1075
+ id: "notFound",
1076
+ namespace: "notFound",
1077
+ type: "route" as const,
1078
+ index: 0,
1079
+ component: notFoundComponent,
1080
+ params: {},
1081
+ };
1206
1082
 
1207
- return createResponseWithMergedHeaders(rscStream, {
1208
- headers: { "content-type": "text/x-component;charset=utf-8" },
1209
- });
1210
- },
1211
- );
1212
- } catch (error) {
1213
- const err = error instanceof Error ? error : new Error(String(error));
1214
- const isDev = process.env.NODE_ENV !== "production";
1083
+ const payload: RscPayload = {
1084
+ metadata: {
1085
+ pathname: url.pathname,
1086
+ routerId: router.id,
1087
+ basename: router.basename,
1088
+ segments: [notFoundSegment],
1089
+ matched: [],
1090
+ diff: [],
1091
+ isPartial: false,
1092
+ rootLayout: router.rootLayout,
1093
+ handles: handleStore.stream(),
1094
+ version,
1095
+ themeConfig: router.themeConfig,
1096
+ warmupEnabled: router.warmupEnabled,
1097
+ initialTheme: requireRequestContext().theme,
1098
+ },
1099
+ };
1215
1100
 
1216
- console.error("[RSC] Loader error:", error);
1101
+ const rscStream = renderToReadableStream(payload, {
1102
+ onError: (error: unknown) => {
1103
+ callOnError(error, "rendering", { request, url, env });
1104
+ },
1105
+ });
1217
1106
 
1218
- callOnError(error, "loader", {
1219
- request,
1220
- url,
1221
- env,
1222
- loaderName: loaderId,
1223
- handledByBoundary: false,
1224
- });
1107
+ const isRscRequest =
1108
+ isPartial ||
1109
+ (!request.headers.get("accept")?.includes("text/html") &&
1110
+ !url.searchParams.has("__html")) ||
1111
+ url.searchParams.has("__rsc");
1225
1112
 
1226
- const errorPayload = {
1227
- loaderResult: null,
1228
- loaderError: {
1229
- message: isDev ? err.message : "An error occurred",
1230
- name: err.name,
1231
- },
1232
- };
1233
- const rscStream = renderToReadableStream(errorPayload);
1113
+ if (isRscRequest) {
1114
+ return createResponseWithMergedHeaders(rscStream, {
1115
+ status: 404,
1116
+ headers: { "content-type": "text/x-component;charset=utf-8" },
1117
+ });
1118
+ }
1234
1119
 
1235
- return createResponseWithMergedHeaders(rscStream, {
1236
- status: 500,
1237
- headers: { "content-type": "text/x-component;charset=utf-8" },
1238
- });
1239
- }
1240
- }
1120
+ const [ssrModule, streamMode] = await getSSRSetup(
1121
+ handlerCtx,
1122
+ request,
1123
+ env,
1124
+ url,
1125
+ requireRequestContext()._metricsStore,
1126
+ );
1127
+ const htmlStream = await ssrModule.renderHTML(rscStream, {
1128
+ nonce,
1129
+ streamMode,
1130
+ });
1241
1131
 
1242
- // ============================================================================
1243
- // RSC RENDERING HANDLER (Navigation)
1244
- // ============================================================================
1245
- async function handleRscRendering(
1246
- request: Request,
1247
- env: TEnv,
1248
- url: URL,
1249
- isPartial: boolean,
1250
- handleStore: ReturnType<typeof requireRequestContext>["_handleStore"],
1251
- nonce: string | undefined,
1252
- ): Promise<Response> {
1253
- // Retrieve handler-level timing from variables
1254
- const reqCtx = requireRequestContext();
1255
- const handlerTimingArr: string[] = reqCtx.var.__handlerTiming || [];
1256
- const handlerStart: number = reqCtx.var.__handlerStart || 0;
1257
-
1258
- let payload: RscPayload;
1259
- let serverTiming: string | undefined;
1260
-
1261
- if (isPartial) {
1262
- // Partial render (navigation)
1263
- const result = await router.matchPartial(request, env);
1264
-
1265
- if (!result) {
1266
- // Fall back to full render
1267
- const match = await router.match(request, env);
1268
- setRequestContextParams(match.params);
1269
-
1270
- if (match.redirect) {
1271
- return createResponseWithMergedHeaders(null, {
1272
- status: 308,
1273
- headers: { Location: match.redirect },
1132
+ return createResponseWithMergedHeaders(htmlStream, {
1133
+ status: 404,
1134
+ headers: { "content-type": "text/html;charset=utf-8" },
1274
1135
  });
1275
1136
  }
1276
1137
 
1277
- const renderStart = performance.now();
1278
- const root = renderSegments(match.segments, {
1279
- rootLayout: router.rootLayout,
1280
- });
1281
- const renderDuration = performance.now() - renderStart;
1282
- serverTiming = match.serverTiming
1283
- ? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
1284
- : `rendering;dur=${renderDuration.toFixed(2)}`;
1285
-
1286
- payload = {
1287
- root,
1288
- metadata: {
1289
- pathname: url.pathname,
1290
- segments: match.segments,
1291
- matched: match.matched,
1292
- diff: match.diff,
1293
- isPartial: false,
1294
- handles: handleStore.stream(),
1295
- version,
1296
- themeConfig: router.themeConfig,
1297
- initialTheme: reqCtx.theme,
1298
- },
1299
- };
1300
- } else {
1301
- setRequestContextParams(result.params);
1302
- serverTiming = result.serverTiming;
1303
-
1304
- payload = {
1305
- root: null,
1306
- metadata: {
1307
- pathname: url.pathname,
1308
- segments: result.segments,
1309
- matched: result.matched,
1310
- diff: result.diff,
1311
- isPartial: true,
1312
- slots: result.slots,
1313
- handles: handleStore.stream(),
1314
- version,
1315
- },
1316
- };
1317
- }
1318
- } else {
1319
- // Full render (initial page load)
1320
- const match = await router.match(request, env);
1321
- setRequestContextParams(match.params);
1322
-
1323
- if (match.redirect) {
1324
- return createResponseWithMergedHeaders(null, {
1325
- status: 308,
1326
- headers: { Location: match.redirect },
1138
+ // Report unhandled errors
1139
+ callOnError(error, "routing", {
1140
+ request,
1141
+ url,
1142
+ env,
1143
+ handledByBoundary: false,
1327
1144
  });
1145
+ console.error(`[RSC] Error:`, error);
1146
+ throw error;
1328
1147
  }
1148
+ };
1329
1149
 
1330
- // Caching is now handled in router.match() via cache provider in request context
1331
- // match.segments already contains cached or fresh segments as appropriate
1332
-
1333
- if (url.searchParams.has("__prerender_collect")) {
1334
- // Build-time prerender collection: serialize segments and handle data
1335
- // to JSON for storage as build artifacts. At runtime the worker
1336
- // deserializes these and feeds them through the normal segment pipeline.
1337
- const nonLoaderSegments = match.segments.filter((s) => s.type !== "loader");
1338
- await handleStore.settled;
1339
- const { serializeSegments } = await import("../cache/cache-scope.js");
1340
- const serializedSegments = await serializeSegments(nonLoaderSegments);
1341
- const handles: Record<string, Record<string, unknown[]>> = {};
1342
- for (const seg of nonLoaderSegments) {
1343
- handles[seg.id] = handleStore.getDataForSegment(seg.id);
1344
- }
1345
- return new Response(
1346
- JSON.stringify({
1347
- segments: serializedSegments,
1348
- handles,
1349
- routeName: match.routeName,
1350
- params: match.params,
1351
- }),
1352
- { headers: { "Content-Type": "application/json" } },
1150
+ // Wrap the render path in a renderStartMs timeout
1151
+ const executeRender = async (): Promise<Response> => {
1152
+ if (routeMiddleware.length > 0) {
1153
+ const mwResponse = await executeMiddleware(
1154
+ buildRouteMiddlewareEntries<TEnv>(routeMiddleware),
1155
+ request,
1156
+ env,
1157
+ variables,
1158
+ renderHandler,
1159
+ routeReverse,
1353
1160
  );
1354
- } else {
1355
- const renderStart = performance.now();
1356
- const root = renderSegments(match.segments, {
1357
- rootLayout: router.rootLayout,
1358
- });
1359
- const renderDuration = performance.now() - renderStart;
1360
- serverTiming = match.serverTiming
1361
- ? `${match.serverTiming}, rendering;dur=${renderDuration.toFixed(2)}`
1362
- : `rendering;dur=${renderDuration.toFixed(2)}`;
1363
1161
 
1364
- payload = {
1365
- root,
1366
- metadata: {
1367
- pathname: url.pathname,
1368
- segments: match.segments,
1369
- matched: match.matched,
1370
- diff: match.diff,
1371
- isPartial: false,
1372
- rootLayout: router.rootLayout,
1373
- handles: handleStore.stream(),
1374
- version,
1375
- themeConfig: router.themeConfig,
1376
- initialTheme: reqCtx.theme,
1377
- },
1378
- };
1379
- }
1380
- }
1381
-
1382
- // Serialize to RSC stream
1383
- const rscSerializeStart = performance.now();
1384
- const rscStream = renderToReadableStream<RscPayload>(payload);
1385
- const rscSerializeDur = performance.now() - rscSerializeStart;
1386
-
1387
- // Determine if this is an RSC request or HTML request
1388
- const isRscRequest =
1389
- (!request.headers.get("accept")?.includes("text/html") &&
1390
- !url.searchParams.has("__html")) ||
1391
- url.searchParams.has("__rsc");
1392
-
1393
- // Build complete Server-Timing: handler phases + match/manifest + rendering + RSC serialize
1394
- const timingParts: string[] = [...handlerTimingArr];
1395
- if (serverTiming) {
1396
- timingParts.push(serverTiming);
1397
- }
1398
- timingParts.push(`rsc-serialize;dur=${rscSerializeDur.toFixed(2)}`);
1162
+ if (isPartial || actionContinuation) {
1163
+ const intercepted = interceptRedirectForPartial(
1164
+ mwResponse,
1165
+ createRedirectFlightResponse,
1166
+ );
1167
+ if (intercepted) return intercepted;
1168
+ }
1399
1169
 
1400
- if (isRscRequest) {
1401
- const fullTiming = timingParts.join(", ");
1402
- const rscHeaders: Record<string, string> = {
1403
- "content-type": "text/x-component;charset=utf-8",
1404
- vary: "accept",
1405
- };
1406
- if (fullTiming) {
1407
- rscHeaders["Server-Timing"] = fullTiming;
1170
+ return finalizeResponse(mwResponse);
1408
1171
  }
1409
- return createResponseWithMergedHeaders(rscStream, {
1410
- headers: rscHeaders,
1411
- });
1412
- }
1413
1172
 
1414
- // Delegate to SSR for HTML response
1415
- const ssrModuleStart = performance.now();
1416
- const ssrModule = await loadSSRModule();
1417
- const ssrModuleDur = performance.now() - ssrModuleStart;
1418
- timingParts.push(`ssr-module-load;dur=${ssrModuleDur.toFixed(2)}`);
1419
-
1420
- const ssrRenderStart = performance.now();
1421
- const htmlStream = await ssrModule.renderHTML(rscStream, { nonce });
1422
- const ssrRenderDur = performance.now() - ssrRenderStart;
1423
- timingParts.push(`ssr-render-html;dur=${ssrRenderDur.toFixed(2)}`);
1424
-
1425
- // Add total handler duration
1426
- if (handlerStart) {
1427
- const totalHandler = performance.now() - handlerStart;
1428
- timingParts.push(`handler-total;dur=${totalHandler.toFixed(2)}`);
1429
- }
1430
-
1431
- const fullTiming = timingParts.join(", ");
1432
- const htmlHeaders: Record<string, string> = {
1433
- "content-type": "text/html;charset=utf-8",
1173
+ return renderHandler();
1434
1174
  };
1435
- if (fullTiming) {
1436
- htmlHeaders["Server-Timing"] = fullTiming;
1437
- }
1438
1175
 
1439
- return createResponseWithMergedHeaders(htmlStream, {
1440
- headers: htmlHeaders,
1441
- });
1176
+ const renderOutcome = await withTimeout(
1177
+ executeRender(),
1178
+ router.timeouts.renderStartMs,
1179
+ "render-start",
1180
+ );
1181
+ if (renderOutcome.timedOut) {
1182
+ return handleTimeoutResponse(
1183
+ request,
1184
+ env,
1185
+ url,
1186
+ "render-start",
1187
+ renderOutcome.durationMs,
1188
+ routeKey,
1189
+ );
1190
+ }
1191
+ return renderOutcome.result;
1442
1192
  }
1443
1193
  }