@rangojs/router 0.4.0 → 0.4.1

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 (482) hide show
  1. package/README.md +19 -1
  2. package/dist/types/browser/event-controller.d.ts +4 -0
  3. package/dist/types/browser/link-interceptor.d.ts +17 -7
  4. package/dist/types/browser/navigation-bridge.d.ts +13 -1
  5. package/dist/types/browser/notify-listeners.d.ts +2 -0
  6. package/dist/types/browser/prefetch/cache.d.ts +1 -1
  7. package/dist/types/browser/prefetch/default-strategy.d.ts +12 -3
  8. package/dist/types/browser/prefetch/invalidation.d.ts +6 -0
  9. package/dist/types/browser/prefetch/loader.d.ts +3 -1
  10. package/dist/types/browser/prefetch/observer.d.ts +3 -6
  11. package/dist/types/browser/rango-state.d.ts +4 -0
  12. package/dist/types/browser/react/Link.d.ts +4 -9
  13. package/dist/types/browser/react/context.d.ts +3 -0
  14. package/dist/types/browser/rsc-router.d.ts +7 -2
  15. package/dist/types/browser/types.d.ts +1 -0
  16. package/dist/types/cache/cache-key-utils.d.ts +11 -3
  17. package/dist/types/cache/cache-scope.d.ts +82 -3
  18. package/dist/types/cache/cf/cf-cache-store.d.ts +2 -2
  19. package/dist/types/cache/index.d.ts +3 -1
  20. package/dist/types/cache/search-params-filter.d.ts +64 -0
  21. package/dist/types/cache/shell-snapshot.d.ts +4 -4
  22. package/dist/types/cache/types.d.ts +30 -2
  23. package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -2
  24. package/dist/types/index.d.ts +1 -0
  25. package/dist/types/index.rsc.d.ts +1 -0
  26. package/dist/types/router/match-middleware/cache-lookup.d.ts +13 -0
  27. package/dist/types/router/navigation-snapshot.d.ts +29 -0
  28. package/dist/types/router/router-options.d.ts +27 -3
  29. package/dist/types/rsc/shell-build-manifest.d.ts +7 -1
  30. package/dist/types/rsc/shell-serve.d.ts +7 -1
  31. package/dist/types/rsc/types.d.ts +17 -0
  32. package/dist/types/server/request-context.d.ts +57 -4
  33. package/dist/types/testing/render-route.d.ts +10 -1
  34. package/dist/types/testing/shell-status.d.ts +6 -3
  35. package/dist/types/vite/plugin-types.d.ts +1 -1
  36. package/dist/vite/index.js +5 -5
  37. package/package.json +23 -22
  38. package/skills/caching/SKILL.md +39 -0
  39. package/skills/comparison/references/framework-comparison.md +7 -1
  40. package/skills/links/SKILL.md +24 -0
  41. package/skills/ppr/SKILL.md +53 -4
  42. package/skills/router-setup/SKILL.md +7 -2
  43. package/skills/testing/client-components.md +15 -14
  44. package/skills/vercel/SKILL.md +1 -1
  45. package/src/browser/event-controller.ts +110 -11
  46. package/src/browser/link-interceptor.ts +469 -20
  47. package/src/browser/navigation-bridge.ts +71 -2
  48. package/src/browser/navigation-store.ts +24 -1
  49. package/src/browser/notify-listeners.ts +22 -0
  50. package/src/browser/prefetch/cache.ts +4 -2
  51. package/src/browser/prefetch/default-strategy.ts +43 -3
  52. package/src/browser/prefetch/invalidation.ts +30 -0
  53. package/src/browser/prefetch/loader.ts +19 -12
  54. package/src/browser/prefetch/observer.ts +50 -22
  55. package/src/browser/rango-state.ts +21 -0
  56. package/src/browser/react/Link.tsx +97 -88
  57. package/src/browser/react/NavigationProvider.tsx +1 -0
  58. package/src/browser/react/context.ts +4 -0
  59. package/src/browser/rsc-router.tsx +22 -9
  60. package/src/browser/types.ts +1 -0
  61. package/src/cache/cache-key-utils.ts +18 -4
  62. package/src/cache/cache-runtime.ts +7 -2
  63. package/src/cache/cache-scope.ts +152 -23
  64. package/src/cache/cf/cf-cache-store.ts +51 -16
  65. package/src/cache/document-cache.ts +7 -1
  66. package/src/cache/index.ts +7 -0
  67. package/src/cache/search-params-filter.ts +118 -0
  68. package/src/cache/shell-snapshot.ts +8 -4
  69. package/src/cache/types.ts +33 -2
  70. package/src/cache/vercel/vercel-cache-store.ts +17 -3
  71. package/src/index.rsc.ts +4 -0
  72. package/src/index.ts +6 -0
  73. package/src/router/match-middleware/cache-lookup.ts +146 -33
  74. package/src/router/match-middleware/cache-store.ts +70 -0
  75. package/src/router/navigation-snapshot.ts +46 -6
  76. package/src/router/router-options.ts +31 -4
  77. package/src/rsc/handler.ts +9 -0
  78. package/src/rsc/response-cache-serve.ts +1 -1
  79. package/src/rsc/rsc-rendering.ts +252 -27
  80. package/src/rsc/shell-build-manifest.ts +8 -1
  81. package/src/rsc/shell-capture.ts +5 -0
  82. package/src/rsc/shell-serve.ts +8 -2
  83. package/src/rsc/types.ts +17 -0
  84. package/src/server/request-context.ts +62 -3
  85. package/src/testing/dispatch.ts +21 -3
  86. package/src/testing/render-route.tsx +86 -17
  87. package/src/testing/shell-status.ts +20 -3
  88. package/src/vite/plugin-types.ts +1 -1
  89. package/src/vite/plugins/vercel-output.ts +2 -2
  90. package/dist/types.backup/__internal.d.ts +0 -127
  91. package/dist/types.backup/bin/rango.d.ts +0 -1
  92. package/dist/types.backup/browser/action-coordinator.d.ts +0 -57
  93. package/dist/types.backup/browser/action-fence.d.ts +0 -33
  94. package/dist/types.backup/browser/app-shell.d.ts +0 -34
  95. package/dist/types.backup/browser/app-version.d.ts +0 -6
  96. package/dist/types.backup/browser/connection-warmup.d.ts +0 -31
  97. package/dist/types.backup/browser/cookie-name.d.ts +0 -66
  98. package/dist/types.backup/browser/event-controller.d.ts +0 -221
  99. package/dist/types.backup/browser/history-state.d.ts +0 -26
  100. package/dist/types.backup/browser/index.d.ts +0 -1
  101. package/dist/types.backup/browser/intercept-utils.d.ts +0 -30
  102. package/dist/types.backup/browser/invalidate-client-cache.d.ts +0 -17
  103. package/dist/types.backup/browser/link-interceptor.d.ts +0 -43
  104. package/dist/types.backup/browser/logging.d.ts +0 -33
  105. package/dist/types.backup/browser/merge-segment-loaders.d.ts +0 -38
  106. package/dist/types.backup/browser/navigation-bridge.d.ts +0 -27
  107. package/dist/types.backup/browser/navigation-client.d.ts +0 -17
  108. package/dist/types.backup/browser/navigation-store-handle.d.ts +0 -25
  109. package/dist/types.backup/browser/navigation-store.d.ts +0 -95
  110. package/dist/types.backup/browser/navigation-transaction.d.ts +0 -75
  111. package/dist/types.backup/browser/network-error-handler.d.ts +0 -35
  112. package/dist/types.backup/browser/partial-update.d.ts +0 -61
  113. package/dist/types.backup/browser/prefetch/cache.d.ts +0 -183
  114. package/dist/types.backup/browser/prefetch/fetch.d.ts +0 -52
  115. package/dist/types.backup/browser/prefetch/observer.d.ts +0 -27
  116. package/dist/types.backup/browser/prefetch/policy.d.ts +0 -13
  117. package/dist/types.backup/browser/prefetch/queue.d.ts +0 -48
  118. package/dist/types.backup/browser/prefetch/resource-ready.d.ts +0 -28
  119. package/dist/types.backup/browser/rango-state.d.ts +0 -52
  120. package/dist/types.backup/browser/react/Link.d.ts +0 -140
  121. package/dist/types.backup/browser/react/NavigationProvider.d.ts +0 -88
  122. package/dist/types.backup/browser/react/ScrollRestoration.d.ts +0 -78
  123. package/dist/types.backup/browser/react/context.d.ts +0 -54
  124. package/dist/types.backup/browser/react/filter-segment-order.d.ts +0 -35
  125. package/dist/types.backup/browser/react/index.d.ts +0 -1
  126. package/dist/types.backup/browser/react/location-state-shared.d.ts +0 -162
  127. package/dist/types.backup/browser/react/location-state.d.ts +0 -29
  128. package/dist/types.backup/browser/react/mount-context.d.ts +0 -23
  129. package/dist/types.backup/browser/react/nonce-context.d.ts +0 -14
  130. package/dist/types.backup/browser/react/shallow-equal.d.ts +0 -5
  131. package/dist/types.backup/browser/react/use-action.d.ts +0 -61
  132. package/dist/types.backup/browser/react/use-handle.d.ts +0 -21
  133. package/dist/types.backup/browser/react/use-href.d.ts +0 -32
  134. package/dist/types.backup/browser/react/use-link-status.d.ts +0 -36
  135. package/dist/types.backup/browser/react/use-mount.d.ts +0 -24
  136. package/dist/types.backup/browser/react/use-navigation.d.ts +0 -15
  137. package/dist/types.backup/browser/react/use-params.d.ts +0 -21
  138. package/dist/types.backup/browser/react/use-pathname.d.ts +0 -13
  139. package/dist/types.backup/browser/react/use-reverse.d.ts +0 -40
  140. package/dist/types.backup/browser/react/use-router.d.ts +0 -23
  141. package/dist/types.backup/browser/react/use-search-params.d.ts +0 -19
  142. package/dist/types.backup/browser/react/use-segments.d.ts +0 -29
  143. package/dist/types.backup/browser/response-adapter.d.ts +0 -58
  144. package/dist/types.backup/browser/rsc-router.d.ts +0 -141
  145. package/dist/types.backup/browser/scroll-restoration.d.ts +0 -103
  146. package/dist/types.backup/browser/segment-reconciler.d.ts +0 -74
  147. package/dist/types.backup/browser/segment-structure-assert.d.ts +0 -16
  148. package/dist/types.backup/browser/server-action-bridge.d.ts +0 -29
  149. package/dist/types.backup/browser/types.d.ts +0 -530
  150. package/dist/types.backup/browser/validate-redirect-origin.d.ts +0 -28
  151. package/dist/types.backup/build/collect-fallback-refs.d.ts +0 -5
  152. package/dist/types.backup/build/generate-manifest.d.ts +0 -100
  153. package/dist/types.backup/build/generate-route-types.d.ts +0 -8
  154. package/dist/types.backup/build/index.d.ts +0 -21
  155. package/dist/types.backup/build/prefix-tree-utils.d.ts +0 -56
  156. package/dist/types.backup/build/route-trie.d.ts +0 -89
  157. package/dist/types.backup/build/route-types/ast-helpers.d.ts +0 -3
  158. package/dist/types.backup/build/route-types/ast-route-extraction.d.ts +0 -13
  159. package/dist/types.backup/build/route-types/codegen.d.ts +0 -16
  160. package/dist/types.backup/build/route-types/include-resolution.d.ts +0 -74
  161. package/dist/types.backup/build/route-types/param-extraction.d.ts +0 -13
  162. package/dist/types.backup/build/route-types/per-module-writer.d.ts +0 -18
  163. package/dist/types.backup/build/route-types/router-processing.d.ts +0 -82
  164. package/dist/types.backup/build/route-types/scan-filter.d.ts +0 -17
  165. package/dist/types.backup/build/route-types/source-scan.d.ts +0 -13
  166. package/dist/types.backup/build/runtime-discovery.d.ts +0 -24
  167. package/dist/types.backup/cache/background-task.d.ts +0 -21
  168. package/dist/types.backup/cache/cache-error.d.ts +0 -71
  169. package/dist/types.backup/cache/cache-key-utils.d.ts +0 -35
  170. package/dist/types.backup/cache/cache-policy.d.ts +0 -59
  171. package/dist/types.backup/cache/cache-runtime.d.ts +0 -51
  172. package/dist/types.backup/cache/cache-scope.d.ts +0 -134
  173. package/dist/types.backup/cache/cache-tag.d.ts +0 -79
  174. package/dist/types.backup/cache/cf/cf-base64.d.ts +0 -4
  175. package/dist/types.backup/cache/cf/cf-cache-constants.d.ts +0 -105
  176. package/dist/types.backup/cache/cf/cf-cache-store.d.ts +0 -481
  177. package/dist/types.backup/cache/cf/cf-cache-types.d.ts +0 -300
  178. package/dist/types.backup/cache/cf/cf-kv-utils.d.ts +0 -22
  179. package/dist/types.backup/cache/cf/cf-tag-marker-memo.d.ts +0 -15
  180. package/dist/types.backup/cache/cf/index.d.ts +0 -3
  181. package/dist/types.backup/cache/document-cache.d.ts +0 -69
  182. package/dist/types.backup/cache/handle-capture.d.ts +0 -23
  183. package/dist/types.backup/cache/handle-snapshot.d.ts +0 -39
  184. package/dist/types.backup/cache/index.d.ts +0 -7
  185. package/dist/types.backup/cache/memory-segment-store.d.ts +0 -163
  186. package/dist/types.backup/cache/profile-registry.d.ts +0 -40
  187. package/dist/types.backup/cache/read-through-swr.d.ts +0 -60
  188. package/dist/types.backup/cache/segment-codec.d.ts +0 -78
  189. package/dist/types.backup/cache/shell-snapshot.d.ts +0 -162
  190. package/dist/types.backup/cache/tag-invalidation.d.ts +0 -74
  191. package/dist/types.backup/cache/taint.d.ts +0 -71
  192. package/dist/types.backup/cache/types.d.ts +0 -407
  193. package/dist/types.backup/cache/vercel/index.d.ts +0 -1
  194. package/dist/types.backup/cache/vercel/vercel-cache-store.d.ts +0 -267
  195. package/dist/types.backup/client.d.ts +0 -184
  196. package/dist/types.backup/client.rsc.d.ts +0 -39
  197. package/dist/types.backup/cloudflare/index.d.ts +0 -7
  198. package/dist/types.backup/cloudflare/tracing.d.ts +0 -53
  199. package/dist/types.backup/component-utils.d.ts +0 -46
  200. package/dist/types.backup/components/DefaultDocument.d.ts +0 -13
  201. package/dist/types.backup/context-var.d.ts +0 -84
  202. package/dist/types.backup/debug.d.ts +0 -57
  203. package/dist/types.backup/decode-loader-results.d.ts +0 -5
  204. package/dist/types.backup/default-error-boundary.d.ts +0 -10
  205. package/dist/types.backup/defer.d.ts +0 -89
  206. package/dist/types.backup/deps/browser.d.ts +0 -1
  207. package/dist/types.backup/deps/html-stream-client.d.ts +0 -1
  208. package/dist/types.backup/deps/html-stream-server.d.ts +0 -1
  209. package/dist/types.backup/deps/rsc.d.ts +0 -1
  210. package/dist/types.backup/deps/ssr.d.ts +0 -1
  211. package/dist/types.backup/encode-kv.d.ts +0 -35
  212. package/dist/types.backup/errors.d.ts +0 -226
  213. package/dist/types.backup/escape-script.d.ts +0 -44
  214. package/dist/types.backup/handle.d.ts +0 -93
  215. package/dist/types.backup/handles/MetaTags.d.ts +0 -17
  216. package/dist/types.backup/handles/Scripts.d.ts +0 -38
  217. package/dist/types.backup/handles/breadcrumbs.d.ts +0 -43
  218. package/dist/types.backup/handles/deferred-resolution.d.ts +0 -53
  219. package/dist/types.backup/handles/is-thenable.d.ts +0 -12
  220. package/dist/types.backup/handles/meta.d.ts +0 -43
  221. package/dist/types.backup/handles/script.d.ts +0 -139
  222. package/dist/types.backup/host/cookie-handler.d.ts +0 -8
  223. package/dist/types.backup/host/errors.d.ts +0 -40
  224. package/dist/types.backup/host/index.d.ts +0 -33
  225. package/dist/types.backup/host/pattern-matcher.d.ts +0 -30
  226. package/dist/types.backup/host/router.d.ts +0 -12
  227. package/dist/types.backup/host/testing.d.ts +0 -41
  228. package/dist/types.backup/host/types.d.ts +0 -148
  229. package/dist/types.backup/host/utils.d.ts +0 -20
  230. package/dist/types.backup/href-client.d.ts +0 -214
  231. package/dist/types.backup/index.d.ts +0 -112
  232. package/dist/types.backup/index.rsc.d.ts +0 -51
  233. package/dist/types.backup/internal-debug.d.ts +0 -1
  234. package/dist/types.backup/loader-store.d.ts +0 -193
  235. package/dist/types.backup/loader.d.ts +0 -18
  236. package/dist/types.backup/loader.rsc.d.ts +0 -18
  237. package/dist/types.backup/missing-id-error.d.ts +0 -1
  238. package/dist/types.backup/outlet-context.d.ts +0 -12
  239. package/dist/types.backup/outlet-provider.d.ts +0 -12
  240. package/dist/types.backup/prerender/build-shell-capture.d.ts +0 -104
  241. package/dist/types.backup/prerender/param-hash.d.ts +0 -6
  242. package/dist/types.backup/prerender/shell-manifest-key.d.ts +0 -18
  243. package/dist/types.backup/prerender/store.d.ts +0 -62
  244. package/dist/types.backup/prerender.d.ts +0 -292
  245. package/dist/types.backup/redirect-origin.d.ts +0 -55
  246. package/dist/types.backup/regex-escape.d.ts +0 -6
  247. package/dist/types.backup/render-error-thrower.d.ts +0 -13
  248. package/dist/types.backup/response-utils.d.ts +0 -35
  249. package/dist/types.backup/reverse.d.ts +0 -206
  250. package/dist/types.backup/root-error-boundary.d.ts +0 -32
  251. package/dist/types.backup/route-content-wrapper.d.ts +0 -40
  252. package/dist/types.backup/route-definition/dsl-helpers.d.ts +0 -130
  253. package/dist/types.backup/route-definition/helper-factories.d.ts +0 -22
  254. package/dist/types.backup/route-definition/helpers-types.d.ts +0 -392
  255. package/dist/types.backup/route-definition/index.d.ts +0 -7
  256. package/dist/types.backup/route-definition/redirect.d.ts +0 -48
  257. package/dist/types.backup/route-definition/resolve-handler-use.d.ts +0 -19
  258. package/dist/types.backup/route-definition/use-item-types.d.ts +0 -1
  259. package/dist/types.backup/route-definition.d.ts +0 -1
  260. package/dist/types.backup/route-map-builder.d.ts +0 -127
  261. package/dist/types.backup/route-name.d.ts +0 -27
  262. package/dist/types.backup/route-types.d.ts +0 -172
  263. package/dist/types.backup/router/basename.d.ts +0 -10
  264. package/dist/types.backup/router/content-negotiation.d.ts +0 -91
  265. package/dist/types.backup/router/debug-manifest.d.ts +0 -7
  266. package/dist/types.backup/router/error-handling.d.ts +0 -76
  267. package/dist/types.backup/router/find-match.d.ts +0 -19
  268. package/dist/types.backup/router/handler-context.d.ts +0 -41
  269. package/dist/types.backup/router/instrument.d.ts +0 -161
  270. package/dist/types.backup/router/intercept-resolution.d.ts +0 -79
  271. package/dist/types.backup/router/lazy-includes.d.ts +0 -26
  272. package/dist/types.backup/router/loader-resolution.d.ts +0 -63
  273. package/dist/types.backup/router/logging.d.ts +0 -41
  274. package/dist/types.backup/router/manifest.d.ts +0 -8
  275. package/dist/types.backup/router/match-api.d.ts +0 -19
  276. package/dist/types.backup/router/match-context.d.ts +0 -184
  277. package/dist/types.backup/router/match-handlers.d.ts +0 -49
  278. package/dist/types.backup/router/match-middleware/background-revalidation.d.ts +0 -113
  279. package/dist/types.backup/router/match-middleware/cache-lookup.d.ts +0 -113
  280. package/dist/types.backup/router/match-middleware/cache-store.d.ts +0 -112
  281. package/dist/types.backup/router/match-middleware/index.d.ts +0 -80
  282. package/dist/types.backup/router/match-middleware/intercept-resolution.d.ts +0 -116
  283. package/dist/types.backup/router/match-middleware/segment-resolution.d.ts +0 -94
  284. package/dist/types.backup/router/match-pipelines.d.ts +0 -103
  285. package/dist/types.backup/router/match-result.d.ts +0 -114
  286. package/dist/types.backup/router/metrics.d.ts +0 -6
  287. package/dist/types.backup/router/middleware-types.d.ts +0 -74
  288. package/dist/types.backup/router/middleware.d.ts +0 -116
  289. package/dist/types.backup/router/navigation-snapshot.d.ts +0 -22
  290. package/dist/types.backup/router/params-util.d.ts +0 -8
  291. package/dist/types.backup/router/parse-pattern.d.ts +0 -38
  292. package/dist/types.backup/router/pattern-matching.d.ts +0 -169
  293. package/dist/types.backup/router/prefetch-cache-ttl.d.ts +0 -27
  294. package/dist/types.backup/router/prefetch-limits.d.ts +0 -20
  295. package/dist/types.backup/router/prerender-match.d.ts +0 -50
  296. package/dist/types.backup/router/preview-match.d.ts +0 -22
  297. package/dist/types.backup/router/request-classification.d.ts +0 -104
  298. package/dist/types.backup/router/revalidation.d.ts +0 -57
  299. package/dist/types.backup/router/route-snapshot.d.ts +0 -112
  300. package/dist/types.backup/router/router-context.d.ts +0 -137
  301. package/dist/types.backup/router/router-interfaces.d.ts +0 -432
  302. package/dist/types.backup/router/router-options.d.ts +0 -738
  303. package/dist/types.backup/router/router-registry.d.ts +0 -15
  304. package/dist/types.backup/router/segment-resolution/fresh.d.ts +0 -55
  305. package/dist/types.backup/router/segment-resolution/helpers.d.ts +0 -93
  306. package/dist/types.backup/router/segment-resolution/loader-cache.d.ts +0 -33
  307. package/dist/types.backup/router/segment-resolution/loader-mask.d.ts +0 -44
  308. package/dist/types.backup/router/segment-resolution/loader-snapshot.d.ts +0 -90
  309. package/dist/types.backup/router/segment-resolution/mask-nested.d.ts +0 -53
  310. package/dist/types.backup/router/segment-resolution/revalidation.d.ts +0 -85
  311. package/dist/types.backup/router/segment-resolution/static-store.d.ts +0 -17
  312. package/dist/types.backup/router/segment-resolution/streamed-handler-telemetry.d.ts +0 -16
  313. package/dist/types.backup/router/segment-resolution/view-transition-default.d.ts +0 -28
  314. package/dist/types.backup/router/segment-resolution.d.ts +0 -3
  315. package/dist/types.backup/router/segment-wrappers.d.ts +0 -53
  316. package/dist/types.backup/router/state-cookie-name.d.ts +0 -1
  317. package/dist/types.backup/router/substitute-pattern-params.d.ts +0 -23
  318. package/dist/types.backup/router/telemetry-otel.d.ts +0 -113
  319. package/dist/types.backup/router/telemetry.d.ts +0 -215
  320. package/dist/types.backup/router/timeout.d.ts +0 -68
  321. package/dist/types.backup/router/tracing.d.ts +0 -125
  322. package/dist/types.backup/router/trie-matching.d.ts +0 -32
  323. package/dist/types.backup/router/types.d.ts +0 -98
  324. package/dist/types.backup/router/url-params.d.ts +0 -26
  325. package/dist/types.backup/router.d.ts +0 -7
  326. package/dist/types.backup/rsc/capture-queue.d.ts +0 -6
  327. package/dist/types.backup/rsc/full-payload.d.ts +0 -22
  328. package/dist/types.backup/rsc/handler-context.d.ts +0 -31
  329. package/dist/types.backup/rsc/handler.d.ts +0 -9
  330. package/dist/types.backup/rsc/helpers.d.ts +0 -213
  331. package/dist/types.backup/rsc/index.d.ts +0 -17
  332. package/dist/types.backup/rsc/json-route-result.d.ts +0 -20
  333. package/dist/types.backup/rsc/loader-fetch.d.ts +0 -14
  334. package/dist/types.backup/rsc/manifest-init.d.ts +0 -18
  335. package/dist/types.backup/rsc/nonce.d.ts +0 -28
  336. package/dist/types.backup/rsc/origin-guard.d.ts +0 -50
  337. package/dist/types.backup/rsc/progressive-enhancement.d.ts +0 -19
  338. package/dist/types.backup/rsc/redirect-guard.d.ts +0 -35
  339. package/dist/types.backup/rsc/response-cache-serve.d.ts +0 -46
  340. package/dist/types.backup/rsc/response-error.d.ts +0 -19
  341. package/dist/types.backup/rsc/response-route-handler.d.ts +0 -29
  342. package/dist/types.backup/rsc/rsc-rendering.d.ts +0 -23
  343. package/dist/types.backup/rsc/runtime-warnings.d.ts +0 -22
  344. package/dist/types.backup/rsc/server-action.d.ts +0 -68
  345. package/dist/types.backup/rsc/shell-build-manifest.d.ts +0 -84
  346. package/dist/types.backup/rsc/shell-capture-constants.d.ts +0 -27
  347. package/dist/types.backup/rsc/shell-capture.d.ts +0 -374
  348. package/dist/types.backup/rsc/shell-serve.d.ts +0 -136
  349. package/dist/types.backup/rsc/ssr-setup.d.ts +0 -48
  350. package/dist/types.backup/rsc/transition-gate.d.ts +0 -27
  351. package/dist/types.backup/rsc/types.d.ts +0 -290
  352. package/dist/types.backup/runtime-env.d.ts +0 -1
  353. package/dist/types.backup/search-params.d.ts +0 -125
  354. package/dist/types.backup/segment-content-promise.d.ts +0 -13
  355. package/dist/types.backup/segment-fragments.d.ts +0 -56
  356. package/dist/types.backup/segment-loader-promise.d.ts +0 -22
  357. package/dist/types.backup/segment-system.d.ts +0 -84
  358. package/dist/types.backup/serialize.d.ts +0 -164
  359. package/dist/types.backup/server/context.d.ts +0 -494
  360. package/dist/types.backup/server/cookie-parse.d.ts +0 -10
  361. package/dist/types.backup/server/cookie-store.d.ts +0 -107
  362. package/dist/types.backup/server/fetchable-loader-store.d.ts +0 -20
  363. package/dist/types.backup/server/handle-store.d.ts +0 -100
  364. package/dist/types.backup/server/loader-registry.d.ts +0 -32
  365. package/dist/types.backup/server/request-context.d.ts +0 -596
  366. package/dist/types.backup/server/root-layout.d.ts +0 -3
  367. package/dist/types.backup/server.d.ts +0 -15
  368. package/dist/types.backup/ssr/index.d.ts +0 -233
  369. package/dist/types.backup/ssr/inject-rsc-eager.d.ts +0 -3
  370. package/dist/types.backup/ssr/preinit-client-references.d.ts +0 -71
  371. package/dist/types.backup/ssr/ssr-root.d.ts +0 -69
  372. package/dist/types.backup/static-handler.d.ts +0 -57
  373. package/dist/types.backup/testing/cache-status.d.ts +0 -63
  374. package/dist/types.backup/testing/collect-handle.d.ts +0 -20
  375. package/dist/types.backup/testing/dispatch.d.ts +0 -123
  376. package/dist/types.backup/testing/dom.entry.d.ts +0 -15
  377. package/dist/types.backup/testing/e2e/fixture.d.ts +0 -37
  378. package/dist/types.backup/testing/e2e/index.d.ts +0 -30
  379. package/dist/types.backup/testing/e2e/matchers.d.ts +0 -17
  380. package/dist/types.backup/testing/e2e/page-helpers.d.ts +0 -62
  381. package/dist/types.backup/testing/e2e/parity.d.ts +0 -111
  382. package/dist/types.backup/testing/e2e/server.d.ts +0 -35
  383. package/dist/types.backup/testing/flight-matchers.d.ts +0 -55
  384. package/dist/types.backup/testing/flight-normalize.d.ts +0 -1
  385. package/dist/types.backup/testing/flight-tree.d.ts +0 -192
  386. package/dist/types.backup/testing/flight.d.ts +0 -115
  387. package/dist/types.backup/testing/flight.entry.d.ts +0 -27
  388. package/dist/types.backup/testing/generated-routes.d.ts +0 -66
  389. package/dist/types.backup/testing/index.d.ts +0 -52
  390. package/dist/types.backup/testing/internal/context.d.ts +0 -225
  391. package/dist/types.backup/testing/internal/flight-client-globals.d.ts +0 -1
  392. package/dist/types.backup/testing/internal/seed-vars.d.ts +0 -30
  393. package/dist/types.backup/testing/render-handler.d.ts +0 -160
  394. package/dist/types.backup/testing/render-route.d.ts +0 -246
  395. package/dist/types.backup/testing/run-loader.d.ts +0 -186
  396. package/dist/types.backup/testing/run-middleware.d.ts +0 -132
  397. package/dist/types.backup/testing/run-transition-when.d.ts +0 -77
  398. package/dist/types.backup/testing/vitest-stubs/cloudflare-email.d.ts +0 -6
  399. package/dist/types.backup/testing/vitest-stubs/cloudflare-workers.d.ts +0 -13
  400. package/dist/types.backup/testing/vitest-stubs/plugin-rsc.d.ts +0 -7
  401. package/dist/types.backup/testing/vitest-stubs/version.d.ts +0 -1
  402. package/dist/types.backup/testing/vitest.d.ts +0 -205
  403. package/dist/types.backup/theme/ThemeProvider.d.ts +0 -13
  404. package/dist/types.backup/theme/ThemeScript.d.ts +0 -45
  405. package/dist/types.backup/theme/constants.d.ts +0 -39
  406. package/dist/types.backup/theme/index.d.ts +0 -29
  407. package/dist/types.backup/theme/theme-context.d.ts +0 -21
  408. package/dist/types.backup/theme/theme-script.d.ts +0 -26
  409. package/dist/types.backup/theme/types.d.ts +0 -162
  410. package/dist/types.backup/theme/use-theme.d.ts +0 -8
  411. package/dist/types.backup/types/boundaries.d.ts +0 -93
  412. package/dist/types.backup/types/cache-types.d.ts +0 -191
  413. package/dist/types.backup/types/error-types.d.ts +0 -114
  414. package/dist/types.backup/types/global-namespace.d.ts +0 -90
  415. package/dist/types.backup/types/handler-context.d.ts +0 -658
  416. package/dist/types.backup/types/index.d.ts +0 -11
  417. package/dist/types.backup/types/loader-types.d.ts +0 -182
  418. package/dist/types.backup/types/request-scope.d.ts +0 -93
  419. package/dist/types.backup/types/route-config.d.ts +0 -105
  420. package/dist/types.backup/types/route-entry.d.ts +0 -95
  421. package/dist/types.backup/types/segments.d.ts +0 -234
  422. package/dist/types.backup/types.d.ts +0 -1
  423. package/dist/types.backup/urls/include-helper.d.ts +0 -17
  424. package/dist/types.backup/urls/include-provider.d.ts +0 -27
  425. package/dist/types.backup/urls/index.d.ts +0 -6
  426. package/dist/types.backup/urls/path-helper-types.d.ts +0 -197
  427. package/dist/types.backup/urls/path-helper.d.ts +0 -12
  428. package/dist/types.backup/urls/pattern-types.d.ts +0 -166
  429. package/dist/types.backup/urls/response-types.d.ts +0 -67
  430. package/dist/types.backup/urls/type-extraction.d.ts +0 -157
  431. package/dist/types.backup/urls/urls-function.d.ts +0 -24
  432. package/dist/types.backup/urls.d.ts +0 -1
  433. package/dist/types.backup/use-loader.d.ts +0 -150
  434. package/dist/types.backup/vercel/index.d.ts +0 -10
  435. package/dist/types.backup/vercel/tracing.d.ts +0 -70
  436. package/dist/types.backup/vite/debug.d.ts +0 -80
  437. package/dist/types.backup/vite/discovery/bundle-postprocess.d.ts +0 -12
  438. package/dist/types.backup/vite/discovery/dev-prerender-cache.d.ts +0 -65
  439. package/dist/types.backup/vite/discovery/discover-routers.d.ts +0 -17
  440. package/dist/types.backup/vite/discovery/discovery-errors.d.ts +0 -113
  441. package/dist/types.backup/vite/discovery/gate-state.d.ts +0 -79
  442. package/dist/types.backup/vite/discovery/prerender-collection.d.ts +0 -24
  443. package/dist/types.backup/vite/discovery/route-types-writer.d.ts +0 -32
  444. package/dist/types.backup/vite/discovery/self-gen-tracking.d.ts +0 -22
  445. package/dist/types.backup/vite/discovery/shell-prerender-phase.d.ts +0 -40
  446. package/dist/types.backup/vite/discovery/state.d.ts +0 -162
  447. package/dist/types.backup/vite/discovery/virtual-module-codegen.d.ts +0 -15
  448. package/dist/types.backup/vite/index.d.ts +0 -11
  449. package/dist/types.backup/vite/inject-client-debug.d.ts +0 -56
  450. package/dist/types.backup/vite/plugin-types.d.ts +0 -298
  451. package/dist/types.backup/vite/plugins/cjs-to-esm.d.ts +0 -6
  452. package/dist/types.backup/vite/plugins/client-ref-dedup.d.ts +0 -40
  453. package/dist/types.backup/vite/plugins/client-ref-hashing.d.ts +0 -35
  454. package/dist/types.backup/vite/plugins/cloudflare-protocol-stub.d.ts +0 -64
  455. package/dist/types.backup/vite/plugins/expose-action-id.d.ts +0 -18
  456. package/dist/types.backup/vite/plugins/expose-id-utils.d.ts +0 -37
  457. package/dist/types.backup/vite/plugins/expose-ids/export-analysis.d.ts +0 -19
  458. package/dist/types.backup/vite/plugins/expose-ids/handler-transform.d.ts +0 -10
  459. package/dist/types.backup/vite/plugins/expose-ids/loader-transform.d.ts +0 -8
  460. package/dist/types.backup/vite/plugins/expose-ids/router-transform.d.ts +0 -13
  461. package/dist/types.backup/vite/plugins/expose-ids/types.d.ts +0 -29
  462. package/dist/types.backup/vite/plugins/expose-internal-ids.d.ts +0 -6
  463. package/dist/types.backup/vite/plugins/performance-tracks.d.ts +0 -25
  464. package/dist/types.backup/vite/plugins/refresh-cmd.d.ts +0 -20
  465. package/dist/types.backup/vite/plugins/use-cache-transform.d.ts +0 -20
  466. package/dist/types.backup/vite/plugins/vercel-output.d.ts +0 -85
  467. package/dist/types.backup/vite/plugins/version-injector.d.ts +0 -21
  468. package/dist/types.backup/vite/plugins/version-plugin.d.ts +0 -19
  469. package/dist/types.backup/vite/plugins/virtual-entries.d.ts +0 -36
  470. package/dist/types.backup/vite/plugins/virtual-stub-plugin.d.ts +0 -7
  471. package/dist/types.backup/vite/rango.d.ts +0 -29
  472. package/dist/types.backup/vite/router-discovery.d.ts +0 -23
  473. package/dist/types.backup/vite/utils/ast-handler-extract.d.ts +0 -64
  474. package/dist/types.backup/vite/utils/banner.d.ts +0 -2
  475. package/dist/types.backup/vite/utils/bundle-analysis.d.ts +0 -28
  476. package/dist/types.backup/vite/utils/client-chunks.d.ts +0 -55
  477. package/dist/types.backup/vite/utils/directive-prologue.d.ts +0 -16
  478. package/dist/types.backup/vite/utils/forward-user-plugins.d.ts +0 -37
  479. package/dist/types.backup/vite/utils/manifest-utils.d.ts +0 -7
  480. package/dist/types.backup/vite/utils/package-resolution.d.ts +0 -6
  481. package/dist/types.backup/vite/utils/prerender-utils.d.ts +0 -32
  482. package/dist/types.backup/vite/utils/shared-utils.d.ts +0 -55
@@ -1,18 +1,164 @@
1
1
  import type { LinkInterceptorOptions, NavigateOptions } from "./types.js";
2
+ import {
3
+ subscribeToLocationChange,
4
+ type EventController,
5
+ } from "./event-controller.js";
6
+ import {
7
+ getDefaultPrefetchStrategy,
8
+ resolveAdaptiveStrategy,
9
+ subscribeToAdaptiveStrategyChange,
10
+ } from "./prefetch/default-strategy.js";
11
+ import { observeForPrefetch } from "./prefetch/observer.js";
12
+ import { subscribeToPrefetchCacheInvalidation } from "./prefetch/invalidation.js";
13
+ import { notifyListeners } from "./notify-listeners.js";
14
+ import type { PrefetchStrategy } from "../router/prefetch-default.js";
15
+
16
+ const ELIGIBILITY_ATTRIBUTES = {
17
+ href: "href",
18
+ target: "target",
19
+ download: "download",
20
+ noIntercept: "data-no-intercept",
21
+ linkComponent: "data-link-component",
22
+ external: "data-external",
23
+ prefetch: "data-prefetch",
24
+ prefetchScope: "data-prefetch-scope",
25
+ } as const;
26
+
27
+ const ELIGIBILITY_ATTRIBUTE_FILTER = Object.values(ELIGIBILITY_ATTRIBUTES);
28
+ const ANCHOR_SELECTOR = "a";
29
+ const ELIGIBLE_ANCHOR_SELECTOR = `a[${ELIGIBILITY_ATTRIBUTES.href}]`;
30
+ const LINK_COMPONENT_SELECTOR = `a[${ELIGIBILITY_ATTRIBUTES.linkComponent}]`;
31
+ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
32
+ const PREFETCH_OPT_OUT_VALUES = new Set(["false", "none"]);
33
+ const PREFETCH_SCOPE_OPT_OUT_SELECTOR =
34
+ `[${ELIGIBILITY_ATTRIBUTES.prefetchScope}="false"],` +
35
+ `[${ELIGIBILITY_ATTRIBUTES.prefetchScope}="none"]`;
36
+ const STATIC_RESOURCE_EXTENSION =
37
+ /\.(?:7z|avif|bmp|bz2|cjs|css|csv|docx?|eot|gif|gz|ico|jpe?g|js|json|m4a|map|mjs|mov|mp3|mp4|ogg|ogv|otf|pdf|png|pptx?|rar|svg|tar|tgz|tiff?|ttf|txt|wasm|wav|webm|webp|woff2?|xlsx?|xml|zip)$/i;
38
+
39
+ function isElementNode(value: unknown): value is Element {
40
+ return (
41
+ typeof value === "object" &&
42
+ value !== null &&
43
+ (value as Node).nodeType === 1 &&
44
+ typeof (value as Element).matches === "function"
45
+ );
46
+ }
47
+
48
+ function isNode(value: unknown): value is Node {
49
+ return (
50
+ typeof value === "object" &&
51
+ value !== null &&
52
+ typeof (value as Node).nodeType === "number"
53
+ );
54
+ }
55
+
56
+ type PrefetchScopeChangeListener = () => void;
57
+
58
+ interface PrefetchScopeObserverState {
59
+ observer: MutationObserver;
60
+ subscriptions: Map<Element, Set<PrefetchScopeChangeListener>>;
61
+ }
62
+
63
+ const prefetchScopeObservers = new WeakMap<
64
+ Document,
65
+ PrefetchScopeObserverState
66
+ >();
67
+
68
+ function createPrefetchScopeObserverState(
69
+ ownerDocument: Document,
70
+ ): PrefetchScopeObserverState | undefined {
71
+ if (
72
+ typeof MutationObserver === "undefined" ||
73
+ !ownerDocument.documentElement
74
+ ) {
75
+ return undefined;
76
+ }
77
+
78
+ const subscriptions = new Map<Element, Set<PrefetchScopeChangeListener>>();
79
+ const observer = new MutationObserver((mutations) => {
80
+ const affected = new Set<PrefetchScopeChangeListener>();
81
+ const collect = (element: Element) => {
82
+ subscriptions.get(element)?.forEach((listener) => affected.add(listener));
83
+ };
84
+
85
+ for (const mutation of mutations) {
86
+ if (!isElementNode(mutation.target)) continue;
87
+ collect(mutation.target);
88
+ mutation.target
89
+ .querySelectorAll(LINK_COMPONENT_SELECTOR)
90
+ .forEach(collect);
91
+ }
92
+ notifyListeners(affected, (listener) => listener());
93
+ });
94
+ observer.observe(ownerDocument.documentElement, {
95
+ subtree: true,
96
+ attributes: true,
97
+ attributeFilter: [ELIGIBILITY_ATTRIBUTES.prefetchScope],
98
+ });
99
+ return { observer, subscriptions };
100
+ }
101
+
102
+ export function subscribeToPrefetchScopeChange(
103
+ element: HTMLAnchorElement,
104
+ listener: PrefetchScopeChangeListener,
105
+ ): () => void {
106
+ const ownerDocument = element.ownerDocument;
107
+ let state = prefetchScopeObservers.get(ownerDocument);
108
+ if (!state) {
109
+ state = createPrefetchScopeObserverState(ownerDocument);
110
+ if (!state) return () => {};
111
+ prefetchScopeObservers.set(ownerDocument, state);
112
+ }
113
+
114
+ let listeners = state.subscriptions.get(element);
115
+ if (!listeners) {
116
+ listeners = new Set();
117
+ state.subscriptions.set(element, listeners);
118
+ }
119
+ listeners.add(listener);
120
+
121
+ let active = true;
122
+ return () => {
123
+ if (!active) return;
124
+ active = false;
125
+ listeners.delete(listener);
126
+ if (
127
+ listeners.size === 0 &&
128
+ state.subscriptions.get(element) === listeners
129
+ ) {
130
+ state.subscriptions.delete(element);
131
+ }
132
+ if (
133
+ state.subscriptions.size === 0 &&
134
+ prefetchScopeObservers.get(ownerDocument) === state
135
+ ) {
136
+ state.observer.disconnect();
137
+ prefetchScopeObservers.delete(ownerDocument);
138
+ }
139
+ };
140
+ }
2
141
 
3
142
  /**
4
143
  * Check if an anchor points to the same page with only a hash change.
5
144
  * Used by both Link component and link-interceptor to let the browser
6
145
  * handle anchor scrolling natively.
7
146
  */
8
- export function isHashOnlyNavigation(anchor: HTMLAnchorElement): boolean {
147
+ function isHashOnlyNavigationToPath(
148
+ anchor: HTMLAnchorElement,
149
+ pathname: string,
150
+ ): boolean {
9
151
  return (
10
- anchor.pathname === window.location.pathname &&
152
+ pathname === window.location.pathname &&
11
153
  anchor.search === window.location.search &&
12
154
  !!anchor.hash
13
155
  );
14
156
  }
15
157
 
158
+ export function isHashOnlyNavigation(anchor: HTMLAnchorElement): boolean {
159
+ return isHashOnlyNavigationToPath(anchor, anchor.pathname);
160
+ }
161
+
16
162
  /**
17
163
  * Default link interception predicate
18
164
  *
@@ -27,50 +173,119 @@ export function isHashOnlyNavigation(anchor: HTMLAnchorElement): boolean {
27
173
  * @returns true if the link should be intercepted
28
174
  */
29
175
  export function defaultShouldIntercept(link: HTMLAnchorElement): boolean {
30
- // Only intercept same-origin links
31
- if (link.origin !== window.location.origin) {
176
+ if (!isEligiblePlainAnchor(link)) return false;
177
+
178
+ // Don't intercept hash-only navigation (same path, only fragment changes).
179
+ // Let the browser handle anchor scrolling natively.
180
+ return !isHashOnlyNavigation(link);
181
+ }
182
+
183
+ function isEligiblePlainAnchor(link: HTMLAnchorElement): boolean {
184
+ // Namespace identity survives adoptNode/importNode across realms; instanceof
185
+ // does not. Structural test doubles omit namespaceURI and retain the legacy
186
+ // property-based behavior.
187
+ if (link.namespaceURI && link.namespaceURI !== HTML_NAMESPACE) {
32
188
  return false;
33
189
  }
34
190
 
35
- // Don't intercept if it has download attribute
36
- if (link.hasAttribute("download")) {
191
+ // Only handle same-origin links
192
+ if (link.origin !== window.location.origin) {
37
193
  return false;
38
194
  }
39
195
 
40
- // Don't intercept if target is set to something other than _self
41
- if (link.target && link.target !== "_self") {
196
+ // Skip links with a download attribute
197
+ if (link.hasAttribute(ELIGIBILITY_ATTRIBUTES.download)) {
42
198
  return false;
43
199
  }
44
200
 
45
- // Don't intercept if explicitly disabled
46
- if (link.getAttribute("data-no-intercept") === "true") {
201
+ // Skip links targeting another browsing context
202
+ const target = link.getAttribute(ELIGIBILITY_ATTRIBUTES.target);
203
+ if (target && target !== "_self") {
47
204
  return false;
48
205
  }
49
206
 
50
- // Don't intercept Link component anchors - they handle their own navigation
51
- if (link.hasAttribute("data-link-component")) {
207
+ // Skip links explicitly excluded from delegated handling
208
+ if (link.getAttribute(ELIGIBILITY_ATTRIBUTES.noIntercept) === "true") {
52
209
  return false;
53
210
  }
54
211
 
55
- // Don't intercept external links
56
- if (link.hasAttribute("data-external")) {
212
+ // Link components handle their own navigation and prefetch
213
+ if (link.hasAttribute(ELIGIBILITY_ATTRIBUTES.linkComponent)) {
57
214
  return false;
58
215
  }
59
216
 
60
- // Don't intercept hash-only navigation (same path, only fragment changes).
61
- // Let the browser handle anchor scrolling natively.
62
- if (isHashOnlyNavigation(link)) {
217
+ // Skip links explicitly marked external
218
+ if (link.hasAttribute(ELIGIBILITY_ATTRIBUTES.external)) {
63
219
  return false;
64
220
  }
65
221
 
66
222
  return true;
67
223
  }
68
224
 
225
+ function normalizePathname(pathname: string): string {
226
+ return pathname
227
+ .replace(/%[0-9a-f]{2}/gi, (escape) => escape.toUpperCase())
228
+ .replace(/\/+$/, "");
229
+ }
230
+
231
+ function canonicalizeBasenamePathname(basename?: string): string | undefined {
232
+ if (!basename) return undefined;
233
+ return normalizePathname(new URL(basename, window.location.origin).pathname);
234
+ }
235
+
236
+ export function isPrefetchScopeDisabled(element: Element): boolean {
237
+ return (
238
+ typeof element.closest === "function" &&
239
+ element.closest(PREFETCH_SCOPE_OPT_OUT_SELECTOR) !== null
240
+ );
241
+ }
242
+
243
+ type PrefetchEligibility = "eligible" | "location-dependent" | "ineligible";
244
+
245
+ function defaultPrefetchEligibilityInBasename(
246
+ link: HTMLAnchorElement,
247
+ basename?: string,
248
+ ): PrefetchEligibility {
249
+ if (!isEligiblePlainAnchor(link)) return "ineligible";
250
+ if (isPrefetchScopeDisabled(link)) return "ineligible";
251
+
252
+ const prefetch = link.getAttribute(ELIGIBILITY_ATTRIBUTES.prefetch);
253
+ if (prefetch && PREFETCH_OPT_OUT_VALUES.has(prefetch)) return "ineligible";
254
+
255
+ const rawPathname = link.pathname;
256
+ if (isHashOnlyNavigationToPath(link, rawPathname)) {
257
+ return "location-dependent";
258
+ }
259
+ const pathname = normalizePathname(rawPathname);
260
+ if (
261
+ basename !== undefined &&
262
+ pathname !== basename &&
263
+ !pathname.startsWith(`${basename}/`)
264
+ ) {
265
+ return "ineligible";
266
+ }
267
+
268
+ if (prefetch === "true") return "eligible";
269
+
270
+ // Scope is decided on canonical encoded path segments. Decode only for
271
+ // resource classification so malformed escapes cannot expand router scope.
272
+ let resourcePathname: string;
273
+ try {
274
+ resourcePathname = decodeURIComponent(pathname);
275
+ } catch {
276
+ return "ineligible";
277
+ }
278
+ if (STATIC_RESOURCE_EXTENSION.test(resourcePathname)) {
279
+ return "ineligible";
280
+ }
281
+ return "eligible";
282
+ }
283
+
69
284
  /**
70
285
  * Set up link interception for SPA navigation
71
286
  *
72
- * Attaches a global click handler to intercept clicks on anchor elements
73
- * and call the onNavigate callback instead of performing a full page load.
287
+ * Attaches a global click handler to intercept clicks on anchor elements and
288
+ * call the onNavigate callback instead of performing a full page load.
74
289
  *
75
290
  * @param onNavigate - Callback when a link should navigate via SPA
76
291
  * @param options - Configuration options
@@ -99,7 +314,8 @@ export function setupLinkInterception(
99
314
  return;
100
315
  }
101
316
 
102
- const target = event.target as HTMLElement;
317
+ if (!isElementNode(event.target)) return;
318
+ const target = event.target;
103
319
  const link = target.closest("a");
104
320
 
105
321
  if (!link || !shouldIntercept(link)) {
@@ -139,3 +355,236 @@ export function setupLinkInterception(
139
355
  document.removeEventListener("click", handleClick);
140
356
  };
141
357
  }
358
+
359
+ export type DelegatedPrefetchCallback = (
360
+ url: string,
361
+ priority: "direct" | "queued",
362
+ ) => void | (() => void);
363
+
364
+ export interface DelegatedPrefetchOptions {
365
+ eventController: Pick<EventController, "getState" | "subscribe">;
366
+ shouldPrefetch?: (link: HTMLAnchorElement) => boolean;
367
+ defaultPrefetch?: PrefetchStrategy;
368
+ root?: HTMLElement;
369
+ basename?: string;
370
+ }
371
+
372
+ interface DelegatedPrefetchState {
373
+ stopObserving?: () => void;
374
+ cancelPending?: () => void;
375
+ }
376
+
377
+ export function setupDelegatedLinkPrefetch(
378
+ onPrefetch: DelegatedPrefetchCallback,
379
+ options: DelegatedPrefetchOptions,
380
+ ): () => void {
381
+ const defaultStrategy =
382
+ options.defaultPrefetch ?? getDefaultPrefetchStrategy();
383
+ if (defaultStrategy === "none") return () => {};
384
+
385
+ const basename = canonicalizeBasenamePathname(options.basename);
386
+ const customShouldPrefetch = options.shouldPrefetch;
387
+ const getEligibility = customShouldPrefetch
388
+ ? (link: HTMLAnchorElement): PrefetchEligibility => {
389
+ if (isPrefetchScopeDisabled(link)) return "ineligible";
390
+ return customShouldPrefetch(link) ? "eligible" : "ineligible";
391
+ }
392
+ : (link: HTMLAnchorElement) =>
393
+ defaultPrefetchEligibilityInBasename(link, basename);
394
+ const states = new Map<HTMLAnchorElement, DelegatedPrefetchState>();
395
+ const parked = new Set<HTMLAnchorElement>();
396
+ let strategy = resolveAdaptiveStrategy(defaultStrategy);
397
+
398
+ const disarm = (link: HTMLAnchorElement) => {
399
+ const state = states.get(link);
400
+ state?.stopObserving?.();
401
+ state?.cancelPending?.();
402
+ states.delete(link);
403
+ if (strategy === "hover") syncMutationObserver();
404
+ };
405
+
406
+ const evaluateEligibility = (link: HTMLAnchorElement): PrefetchEligibility =>
407
+ link.hasAttribute(ELIGIBILITY_ATTRIBUTES.href)
408
+ ? getEligibility(link)
409
+ : "ineligible";
410
+
411
+ const updateParked = (
412
+ link: HTMLAnchorElement,
413
+ eligibility: PrefetchEligibility,
414
+ ) => {
415
+ if (eligibility === "location-dependent" && strategy !== "hover") {
416
+ parked.add(link);
417
+ } else parked.delete(link);
418
+ };
419
+
420
+ const forget = (link: HTMLAnchorElement) => {
421
+ disarm(link);
422
+ parked.delete(link);
423
+ };
424
+
425
+ const trigger = (link: HTMLAnchorElement, priority: "direct" | "queued") => {
426
+ const eligibility = evaluateEligibility(link);
427
+ updateParked(link, eligibility);
428
+ if (eligibility !== "eligible") {
429
+ disarm(link);
430
+ return;
431
+ }
432
+
433
+ let state = states.get(link);
434
+ if (!state) {
435
+ state = {};
436
+ states.set(link, state);
437
+ }
438
+ state.cancelPending?.();
439
+ state.cancelPending = undefined;
440
+ try {
441
+ state.cancelPending = onPrefetch(link.href, priority) ?? undefined;
442
+ } finally {
443
+ if (strategy === "hover" && !state.cancelPending) states.delete(link);
444
+ syncMutationObserver();
445
+ }
446
+ };
447
+
448
+ const register = (link: HTMLAnchorElement) => {
449
+ disarm(link);
450
+ const eligibility = evaluateEligibility(link);
451
+ updateParked(link, eligibility);
452
+ if (eligibility !== "eligible") return;
453
+ if (strategy === "hover") return;
454
+
455
+ const state: DelegatedPrefetchState = {};
456
+ states.set(link, state);
457
+
458
+ if (strategy === "render") {
459
+ trigger(link, "queued");
460
+ } else if (strategy === "viewport") {
461
+ state.stopObserving = observeForPrefetch(link, () => {
462
+ state.stopObserving = undefined;
463
+ trigger(link, "queued");
464
+ });
465
+ }
466
+ };
467
+
468
+ const visitAnchors = (
469
+ node: Node,
470
+ visit: (link: HTMLAnchorElement) => void,
471
+ ) => {
472
+ if (!isElementNode(node)) return;
473
+ if (node.matches(ANCHOR_SELECTOR)) {
474
+ visit(node as HTMLAnchorElement);
475
+ }
476
+ node
477
+ .querySelectorAll<HTMLAnchorElement>(ANCHOR_SELECTOR)
478
+ .forEach((link) => visit(link));
479
+ };
480
+
481
+ const root = options.root ?? document.documentElement;
482
+ let mutationObserver: MutationObserver | undefined;
483
+ function syncMutationObserver(): void {
484
+ const shouldObserve =
485
+ strategy === "viewport" || strategy === "render" || states.size > 0;
486
+ if (!shouldObserve) {
487
+ mutationObserver?.disconnect();
488
+ mutationObserver = undefined;
489
+ return;
490
+ }
491
+ if (mutationObserver || typeof MutationObserver === "undefined" || !root) {
492
+ return;
493
+ }
494
+
495
+ mutationObserver = new MutationObserver((mutations) => {
496
+ const affected = new Set<HTMLAnchorElement>();
497
+ const markAffected = (link: HTMLAnchorElement) => affected.add(link);
498
+ for (const mutation of mutations) {
499
+ if (mutation.type === "attributes") {
500
+ if (mutation.attributeName === ELIGIBILITY_ATTRIBUTES.prefetchScope) {
501
+ visitAnchors(mutation.target, markAffected);
502
+ } else if (
503
+ isElementNode(mutation.target) &&
504
+ mutation.target.matches(ANCHOR_SELECTOR)
505
+ ) {
506
+ affected.add(mutation.target as HTMLAnchorElement);
507
+ }
508
+ continue;
509
+ }
510
+ mutation.removedNodes.forEach((node) =>
511
+ visitAnchors(node, markAffected),
512
+ );
513
+ mutation.addedNodes.forEach((node) => visitAnchors(node, markAffected));
514
+ }
515
+ for (const link of affected) {
516
+ if (link.isConnected && root.contains(link)) register(link);
517
+ else forget(link);
518
+ }
519
+ });
520
+ mutationObserver.observe(root, {
521
+ subtree: true,
522
+ childList: true,
523
+ attributes: true,
524
+ attributeFilter: ELIGIBILITY_ATTRIBUTE_FILTER,
525
+ });
526
+ }
527
+
528
+ const rescan = () => {
529
+ for (const link of [...states.keys()]) disarm(link);
530
+ parked.clear();
531
+ strategy = resolveAdaptiveStrategy(defaultStrategy);
532
+ syncMutationObserver();
533
+ if ((strategy === "viewport" || strategy === "render") && root) {
534
+ visitAnchors(root, register);
535
+ }
536
+ };
537
+
538
+ rescan();
539
+
540
+ const handleMouseOver = (event: MouseEvent) => {
541
+ if (!isElementNode(event.target)) return;
542
+
543
+ const link = event.target.closest<HTMLAnchorElement>(
544
+ ELIGIBLE_ANCHOR_SELECTOR,
545
+ );
546
+ if (!link || !root.contains(link)) return;
547
+ if (isNode(event.relatedTarget) && link.contains(event.relatedTarget)) {
548
+ return;
549
+ }
550
+ trigger(link, "direct");
551
+ };
552
+
553
+ if (strategy === "hover" || strategy === "viewport") {
554
+ root.addEventListener("mouseover", handleMouseOver);
555
+ }
556
+
557
+ const unsubscribeLocation =
558
+ defaultStrategy === "viewport" ||
559
+ defaultStrategy === "render" ||
560
+ defaultStrategy === "adaptive"
561
+ ? subscribeToLocationChange(options.eventController, () => {
562
+ if (strategy !== "viewport" && strategy !== "render") return;
563
+ for (const link of [...parked]) {
564
+ if (link.isConnected && root.contains(link)) register(link);
565
+ else forget(link);
566
+ }
567
+ })
568
+ : undefined;
569
+ const unsubscribeAdaptive =
570
+ defaultStrategy === "adaptive"
571
+ ? subscribeToAdaptiveStrategyChange(rescan)
572
+ : undefined;
573
+ const unsubscribeInvalidation = subscribeToPrefetchCacheInvalidation(() => {
574
+ if (strategy !== "viewport" && strategy !== "render") return;
575
+ for (const link of [...states.keys()]) {
576
+ if (link.isConnected && root.contains(link)) register(link);
577
+ else forget(link);
578
+ }
579
+ });
580
+
581
+ return () => {
582
+ mutationObserver?.disconnect();
583
+ root.removeEventListener("mouseover", handleMouseOver);
584
+ unsubscribeLocation?.();
585
+ unsubscribeAdaptive?.();
586
+ unsubscribeInvalidation();
587
+ for (const link of [...states.keys()]) disarm(link);
588
+ parked.clear();
589
+ };
590
+ }
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  NavigationBridge,
3
3
  NavigationBridgeConfig,
4
+ NavigationStore,
4
5
  NavigateOptionsInternal,
5
6
  ResolvedSegment,
6
7
  } from "./types.js";
@@ -24,7 +25,10 @@ import {
24
25
  const addTransitionType: ((type: string) => void) | undefined =
25
26
  "addTransitionType" in React ? (React as any).addTransitionType : undefined;
26
27
 
27
- import { setupLinkInterception } from "./link-interceptor.js";
28
+ import {
29
+ setupDelegatedLinkPrefetch,
30
+ setupLinkInterception,
31
+ } from "./link-interceptor.js";
28
32
  import { createPartialUpdater } from "./partial-update.js";
29
33
  import { generateHistoryKey } from "./navigation-store.js";
30
34
  import type { EventController } from "./event-controller.js";
@@ -38,6 +42,12 @@ import {
38
42
  import { debugLog } from "./logging.js";
39
43
  import { ServerRedirect } from "../errors.js";
40
44
  import { validateRedirectOrigin } from "./validate-redirect-origin.js";
45
+ import {
46
+ prefetchDirect,
47
+ prefetchQueued,
48
+ schedulePrefetchWhenRouterIdle,
49
+ } from "./prefetch/loader.js";
50
+ import type { PrefetchStrategy } from "../router/prefetch-default.js";
41
51
 
42
52
  // Polyfill Symbol.dispose for Safari and older browsers
43
53
  if (typeof Symbol.dispose === "undefined") {
@@ -53,6 +63,48 @@ export interface NavigationBridgeConfigWithController extends NavigationBridgeCo
53
63
  eventController: EventController;
54
64
  /** RSC version from initial payload metadata. */
55
65
  version?: string;
66
+ /** Server-resolved default used by both Links and delegated anchors. */
67
+ defaultPrefetch?: PrefetchStrategy;
68
+ /** Canonical router basename used to scope delegated anchor prefetch. */
69
+ basename?: string;
70
+ }
71
+
72
+ export interface NavigationBridgeDelegatedPrefetchOptions {
73
+ defaultPrefetch?: PrefetchStrategy;
74
+ root?: HTMLElement;
75
+ basename?: string;
76
+ }
77
+
78
+ /** Register delegated anchor prefetch with the production bridge wiring. */
79
+ export function setupNavigationBridgeDelegatedPrefetch(
80
+ store: NavigationStore,
81
+ eventController: EventController,
82
+ getVersion: () => string | undefined,
83
+ options: NavigationBridgeDelegatedPrefetchOptions = {},
84
+ ): () => void {
85
+ return setupDelegatedLinkPrefetch(
86
+ (url, priority) => {
87
+ const trigger = () => {
88
+ const segmentState = store.getSegmentState();
89
+ const prefetch =
90
+ priority === "direct" ? prefetchDirect : prefetchQueued;
91
+ prefetch(
92
+ url,
93
+ segmentState.currentSegmentIds,
94
+ getVersion(),
95
+ store.getRouterId?.(),
96
+ );
97
+ };
98
+
99
+ if (priority === "direct") {
100
+ trigger();
101
+ return;
102
+ }
103
+
104
+ return schedulePrefetchWhenRouterIdle(eventController, trigger);
105
+ },
106
+ { eventController, ...options },
107
+ );
56
108
  }
57
109
 
58
110
  /**
@@ -71,7 +123,15 @@ export interface NavigationBridgeConfigWithController extends NavigationBridgeCo
71
123
  export function createNavigationBridge(
72
124
  config: NavigationBridgeConfigWithController,
73
125
  ): NavigationBridge {
74
- const { store, client, eventController, onUpdate, renderSegments } = config;
126
+ const {
127
+ store,
128
+ client,
129
+ eventController,
130
+ onUpdate,
131
+ renderSegments,
132
+ defaultPrefetch,
133
+ basename,
134
+ } = config;
75
135
  let version = config.version;
76
136
 
77
137
  // Create shared partial updater
@@ -724,6 +784,15 @@ export function createNavigationBridge(
724
784
  };
725
785
  },
726
786
 
787
+ registerDelegatedPrefetch(): () => void {
788
+ return setupNavigationBridgeDelegatedPrefetch(
789
+ store,
790
+ eventController,
791
+ () => version,
792
+ { defaultPrefetch, basename },
793
+ );
794
+ },
795
+
727
796
  getVersion(): string | undefined {
728
797
  return version;
729
798
  },
@@ -8,6 +8,11 @@ import type {
8
8
  HandleData,
9
9
  } from "./types.js";
10
10
  import { clearPrefetchCache } from "./prefetch/cache.js";
11
+ import {
12
+ adoptRangoState,
13
+ getRangoState,
14
+ getRangoStateCookieName,
15
+ } from "./rango-state.js";
11
16
 
12
17
  // Maximum number of history entries to cache (URLs visited)
13
18
  const HISTORY_CACHE_SIZE = 20;
@@ -316,6 +321,8 @@ export function createNavigationStore(
316
321
  type: "invalidate",
317
322
  path: currentPath,
318
323
  segmentIds: currentSegmentIds,
324
+ rangoState: getRangoState(),
325
+ stateCookieName: getRangoStateCookieName(),
319
326
  });
320
327
  }
321
328
  }
@@ -341,7 +348,23 @@ export function createNavigationStore(
341
348
  return;
342
349
  }
343
350
 
344
- markCacheAsStaleInternal();
351
+ const rangoState = event.data.rangoState;
352
+ const stateCookieName = event.data.stateCookieName;
353
+ if (
354
+ typeof rangoState === "string" &&
355
+ typeof stateCookieName === "string"
356
+ ) {
357
+ if (stateCookieName !== getRangoStateCookieName()) return;
358
+ // The sender already rotated the same-origin cookie. Adopt that
359
+ // value before clearing locally so tabs cannot ping-pong rotations
360
+ // and obsolete each other's post-invalidation prefetches.
361
+ const adopted = adoptRangoState(rangoState);
362
+ markHistoryStale();
363
+ clearPrefetchCache(!adopted);
364
+ } else {
365
+ // Compatibility with an already-open tab running an older sender.
366
+ markCacheAsStaleInternal();
367
+ }
345
368
 
346
369
  // Auto-refresh if enabled and callback is registered
347
370
  if (crossTabAutoRefresh && crossTabRefreshCallback) {