@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.140

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 (460) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +432 -7
  3. package/dist/bin/rango.js +2073 -213
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +7258 -2714
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +140 -67
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +329 -0
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +487 -0
  12. package/skills/caching/SKILL.md +357 -25
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +246 -0
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +16 -10
  19. package/skills/document-cache/SKILL.md +87 -62
  20. package/skills/fonts/SKILL.md +6 -4
  21. package/skills/handler-use/SKILL.md +364 -0
  22. package/skills/hooks/SKILL.md +557 -79
  23. package/skills/host-router/SKILL.md +320 -0
  24. package/skills/i18n/SKILL.md +276 -0
  25. package/skills/intercept/SKILL.md +207 -15
  26. package/skills/layout/SKILL.md +146 -6
  27. package/skills/links/SKILL.md +304 -25
  28. package/skills/loader/SKILL.md +616 -54
  29. package/skills/middleware/SKILL.md +217 -37
  30. package/skills/migrate-nextjs/SKILL.md +611 -0
  31. package/skills/migrate-react-router/SKILL.md +927 -0
  32. package/skills/mime-routes/SKILL.md +42 -11
  33. package/skills/observability/SKILL.md +194 -0
  34. package/skills/parallel/SKILL.md +284 -3
  35. package/skills/ppr/SKILL.md +426 -0
  36. package/skills/prerender/SKILL.md +437 -52
  37. package/skills/rango/SKILL.md +369 -22
  38. package/skills/react-compiler/SKILL.md +168 -0
  39. package/skills/response-routes/SKILL.md +263 -121
  40. package/skills/route/SKILL.md +350 -21
  41. package/skills/router-setup/SKILL.md +246 -33
  42. package/skills/scripts/SKILL.md +179 -0
  43. package/skills/server-actions/SKILL.md +775 -0
  44. package/skills/shell-manifest/SKILL.md +185 -0
  45. package/skills/streams-and-websockets/SKILL.md +283 -0
  46. package/skills/tailwind/SKILL.md +27 -3
  47. package/skills/testing/SKILL.md +126 -222
  48. package/skills/testing/bindings.md +103 -0
  49. package/skills/testing/cache-prerender.md +127 -0
  50. package/skills/testing/client-components.md +124 -0
  51. package/skills/testing/e2e-parity.md +125 -0
  52. package/skills/testing/flight.md +91 -0
  53. package/skills/testing/handles.md +131 -0
  54. package/skills/testing/loader.md +128 -0
  55. package/skills/testing/middleware.md +99 -0
  56. package/skills/testing/render-handler.md +122 -0
  57. package/skills/testing/response-routes.md +95 -0
  58. package/skills/testing/reverse-and-types.md +85 -0
  59. package/skills/testing/server-actions.md +107 -0
  60. package/skills/testing/server-tree.md +128 -0
  61. package/skills/testing/setup.md +123 -0
  62. package/skills/theme/SKILL.md +9 -8
  63. package/skills/typesafety/SKILL.md +532 -103
  64. package/skills/use-cache/SKILL.md +367 -0
  65. package/skills/vercel/SKILL.md +128 -0
  66. package/skills/view-transitions/SKILL.md +337 -0
  67. package/src/__augment-tests__/augment.ts +81 -0
  68. package/src/__augment-tests__/augmented.check.ts +116 -0
  69. package/src/__internal.ts +77 -44
  70. package/src/bin/rango.ts +312 -15
  71. package/src/browser/action-coordinator.ts +114 -0
  72. package/src/browser/action-fence.ts +47 -0
  73. package/src/browser/app-shell.ts +39 -0
  74. package/src/browser/app-version.ts +14 -0
  75. package/src/browser/connection-warmup.ts +134 -0
  76. package/src/browser/cookie-name.ts +140 -0
  77. package/src/browser/event-controller.ts +293 -202
  78. package/src/browser/history-state.ts +101 -0
  79. package/src/browser/index.ts +3 -3
  80. package/src/browser/intercept-utils.ts +52 -0
  81. package/src/browser/invalidate-client-cache.ts +52 -0
  82. package/src/browser/link-interceptor.ts +24 -4
  83. package/src/browser/logging.ts +11 -0
  84. package/src/browser/merge-segment-loaders.ts +20 -12
  85. package/src/browser/navigation-bridge.ts +385 -576
  86. package/src/browser/navigation-client.ts +245 -75
  87. package/src/browser/navigation-store-handle.ts +38 -0
  88. package/src/browser/navigation-store.ts +184 -118
  89. package/src/browser/navigation-transaction.ts +247 -0
  90. package/src/browser/network-error-handler.ts +88 -0
  91. package/src/browser/partial-update.ts +412 -364
  92. package/src/browser/prefetch/cache.ts +359 -0
  93. package/src/browser/prefetch/fetch.ts +452 -0
  94. package/src/browser/prefetch/observer.ts +65 -0
  95. package/src/browser/prefetch/policy.ts +48 -0
  96. package/src/browser/prefetch/queue.ts +209 -0
  97. package/src/browser/prefetch/resource-ready.ts +77 -0
  98. package/src/browser/rango-state.ts +194 -0
  99. package/src/browser/react/Link.tsx +275 -68
  100. package/src/browser/react/NavigationProvider.tsx +265 -109
  101. package/src/browser/react/ScrollRestoration.tsx +10 -6
  102. package/src/browser/react/context.ts +11 -0
  103. package/src/browser/react/filter-segment-order.ts +70 -0
  104. package/src/browser/react/index.ts +0 -48
  105. package/src/browser/react/location-state-shared.ts +272 -60
  106. package/src/browser/react/location-state.ts +90 -20
  107. package/src/browser/react/mount-context.ts +6 -1
  108. package/src/browser/react/nonce-context.ts +23 -0
  109. package/src/browser/react/shallow-equal.ts +27 -0
  110. package/src/browser/react/use-action.ts +35 -66
  111. package/src/browser/react/use-handle.ts +39 -126
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +39 -13
  114. package/src/browser/react/use-navigation.ts +53 -69
  115. package/src/browser/react/use-params.ts +75 -0
  116. package/src/browser/react/use-pathname.ts +47 -0
  117. package/src/browser/react/use-reverse.ts +106 -0
  118. package/src/browser/react/use-router.ts +98 -0
  119. package/src/browser/react/use-search-params.ts +51 -0
  120. package/src/browser/react/use-segments.ts +72 -99
  121. package/src/browser/response-adapter.ts +164 -0
  122. package/src/browser/rsc-router.tsx +300 -72
  123. package/src/browser/scroll-restoration.ts +138 -50
  124. package/src/browser/segment-reconciler.ts +243 -0
  125. package/src/browser/segment-structure-assert.ts +17 -1
  126. package/src/browser/server-action-bridge.ts +668 -613
  127. package/src/browser/types.ts +223 -51
  128. package/src/browser/validate-redirect-origin.ts +56 -0
  129. package/src/build/collect-fallback-refs.ts +107 -0
  130. package/src/build/generate-manifest.ts +252 -161
  131. package/src/build/generate-route-types.ts +41 -1038
  132. package/src/build/index.ts +12 -7
  133. package/src/build/prefix-tree-utils.ts +123 -0
  134. package/src/build/route-trie.ts +225 -42
  135. package/src/build/route-types/ast-helpers.ts +25 -0
  136. package/src/build/route-types/ast-route-extraction.ts +105 -0
  137. package/src/build/route-types/codegen.ts +113 -0
  138. package/src/build/route-types/include-resolution.ts +812 -0
  139. package/src/build/route-types/param-extraction.ts +51 -0
  140. package/src/build/route-types/per-module-writer.ts +144 -0
  141. package/src/build/route-types/router-processing.ts +695 -0
  142. package/src/build/route-types/scan-filter.ts +85 -0
  143. package/src/build/route-types/source-scan.ts +216 -0
  144. package/src/build/runtime-discovery.ts +223 -0
  145. package/src/cache/background-task.ts +34 -0
  146. package/src/cache/cache-error.ts +104 -0
  147. package/src/cache/cache-key-utils.ts +60 -0
  148. package/src/cache/cache-policy.ts +199 -0
  149. package/src/cache/cache-runtime.ts +525 -0
  150. package/src/cache/cache-scope.ts +298 -332
  151. package/src/cache/cache-tag.ts +103 -0
  152. package/src/cache/cf/cf-base64.ts +33 -0
  153. package/src/cache/cf/cf-cache-constants.ts +127 -0
  154. package/src/cache/cf/cf-cache-store.ts +2500 -158
  155. package/src/cache/cf/cf-cache-types.ts +349 -0
  156. package/src/cache/cf/cf-kv-utils.ts +46 -0
  157. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  158. package/src/cache/cf/index.ts +17 -17
  159. package/src/cache/document-cache.ts +199 -92
  160. package/src/cache/handle-capture.ts +81 -0
  161. package/src/cache/handle-snapshot.ts +111 -0
  162. package/src/cache/index.ts +29 -35
  163. package/src/cache/memory-segment-store.ts +363 -30
  164. package/src/cache/profile-registry.ts +88 -0
  165. package/src/cache/read-through-swr.ts +178 -0
  166. package/src/cache/segment-codec.ts +248 -0
  167. package/src/cache/shell-cache.ts +386 -0
  168. package/src/cache/tag-invalidation.ts +230 -0
  169. package/src/cache/taint.ts +153 -0
  170. package/src/cache/types.ts +156 -211
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1102 -0
  173. package/src/client.rsc.tsx +43 -21
  174. package/src/client.tsx +131 -347
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +109 -0
  177. package/src/component-utils.ts +23 -4
  178. package/src/components/DefaultDocument.tsx +13 -3
  179. package/src/context-var.ts +168 -0
  180. package/src/debug.ts +19 -9
  181. package/src/decode-loader-results.ts +52 -0
  182. package/src/defer.ts +185 -0
  183. package/src/deps/ssr.ts +0 -1
  184. package/src/encode-kv.ts +49 -0
  185. package/src/errors.ts +106 -10
  186. package/src/escape-script.ts +52 -0
  187. package/src/handle.ts +110 -35
  188. package/src/handles/MetaTags.tsx +83 -59
  189. package/src/handles/Scripts.tsx +183 -0
  190. package/src/handles/breadcrumbs.ts +93 -0
  191. package/src/handles/deferred-resolution.ts +127 -0
  192. package/src/handles/is-thenable.ts +18 -0
  193. package/src/handles/meta.ts +44 -53
  194. package/src/handles/script.ts +244 -0
  195. package/src/host/cookie-handler.ts +20 -65
  196. package/src/host/errors.ts +21 -30
  197. package/src/host/index.ts +13 -9
  198. package/src/host/pattern-matcher.ts +50 -79
  199. package/src/host/router.ts +151 -121
  200. package/src/host/testing.ts +45 -32
  201. package/src/host/types.ts +52 -11
  202. package/src/host/utils.ts +2 -2
  203. package/src/href-client.ts +192 -57
  204. package/src/index.rsc.ts +177 -35
  205. package/src/index.ts +255 -71
  206. package/src/internal-debug.ts +9 -2
  207. package/src/loader-store.ts +500 -0
  208. package/src/loader.rsc.ts +31 -99
  209. package/src/loader.ts +30 -12
  210. package/src/missing-id-error.ts +68 -0
  211. package/src/outlet-context.ts +1 -1
  212. package/src/outlet-provider.tsx +41 -0
  213. package/src/prerender/param-hash.ts +16 -14
  214. package/src/prerender/store.ts +121 -21
  215. package/src/prerender.ts +460 -26
  216. package/src/redirect-origin.ts +100 -0
  217. package/src/regex-escape.ts +8 -0
  218. package/src/render-error-thrower.tsx +20 -0
  219. package/src/response-utils.ts +62 -0
  220. package/src/reverse.ts +198 -128
  221. package/src/root-error-boundary.tsx +42 -48
  222. package/src/route-content-wrapper.tsx +22 -77
  223. package/src/route-definition/dsl-helpers.ts +1116 -0
  224. package/src/route-definition/helper-factories.ts +88 -0
  225. package/src/route-definition/helpers-types.ts +505 -0
  226. package/src/route-definition/index.ts +54 -0
  227. package/src/route-definition/redirect.ts +134 -0
  228. package/src/route-definition/resolve-handler-use.ts +160 -0
  229. package/src/route-definition/use-item-types.ts +29 -0
  230. package/src/route-definition.ts +1 -1481
  231. package/src/route-map-builder.ts +82 -144
  232. package/src/route-name.ts +53 -0
  233. package/src/route-types.ts +71 -45
  234. package/src/router/basename.ts +14 -0
  235. package/src/router/content-negotiation.ts +263 -0
  236. package/src/router/debug-manifest.ts +72 -0
  237. package/src/router/error-handling.ts +54 -27
  238. package/src/router/find-match.ts +245 -0
  239. package/src/router/handler-context.ts +377 -125
  240. package/src/router/instrument.ts +350 -0
  241. package/src/router/intercept-resolution.ts +59 -28
  242. package/src/router/lazy-includes.ts +254 -0
  243. package/src/router/loader-resolution.ts +421 -157
  244. package/src/router/logging.ts +106 -6
  245. package/src/router/manifest.ts +131 -57
  246. package/src/router/match-api.ts +167 -246
  247. package/src/router/match-context.ts +4 -24
  248. package/src/router/match-handlers.ts +440 -0
  249. package/src/router/match-middleware/background-revalidation.ts +117 -93
  250. package/src/router/match-middleware/cache-lookup.ts +297 -150
  251. package/src/router/match-middleware/cache-store.ts +123 -51
  252. package/src/router/match-middleware/intercept-resolution.ts +44 -43
  253. package/src/router/match-middleware/segment-resolution.ts +64 -22
  254. package/src/router/match-pipelines.ts +11 -87
  255. package/src/router/match-result.ts +121 -50
  256. package/src/router/metrics.ts +219 -28
  257. package/src/router/middleware-types.ts +93 -0
  258. package/src/router/middleware.ts +505 -441
  259. package/src/router/navigation-snapshot.ts +133 -0
  260. package/src/router/params-util.ts +23 -0
  261. package/src/router/parse-pattern.ts +115 -0
  262. package/src/router/pattern-matching.ts +311 -142
  263. package/src/router/prefetch-cache-ttl.ts +51 -0
  264. package/src/router/prefetch-limits.ts +37 -0
  265. package/src/router/prerender-match.ts +547 -0
  266. package/src/router/preview-match.ts +102 -0
  267. package/src/router/request-classification.ts +278 -0
  268. package/src/router/revalidation.ts +203 -62
  269. package/src/router/route-snapshot.ts +246 -0
  270. package/src/router/router-context.ts +45 -48
  271. package/src/router/router-interfaces.ts +554 -0
  272. package/src/router/router-options.ts +779 -0
  273. package/src/router/router-registry.ts +21 -0
  274. package/src/router/segment-resolution/fresh.ts +772 -0
  275. package/src/router/segment-resolution/helpers.ts +348 -0
  276. package/src/router/segment-resolution/loader-cache.ts +250 -0
  277. package/src/router/segment-resolution/loader-mask.ts +44 -0
  278. package/src/router/segment-resolution/revalidation.ts +1331 -0
  279. package/src/router/segment-resolution/static-store.ts +81 -0
  280. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  281. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  282. package/src/router/segment-resolution.ts +25 -1354
  283. package/src/router/segment-wrappers.ts +292 -0
  284. package/src/router/state-cookie-name.ts +33 -0
  285. package/src/router/substitute-pattern-params.ts +75 -0
  286. package/src/router/telemetry-otel.ts +261 -0
  287. package/src/router/telemetry.ts +377 -0
  288. package/src/router/timeout.ts +128 -0
  289. package/src/router/tracing.ts +206 -0
  290. package/src/router/trie-matching.ts +240 -61
  291. package/src/router/types.ts +23 -70
  292. package/src/router/url-params.ts +57 -0
  293. package/src/router.ts +781 -2378
  294. package/src/rsc/full-payload.ts +70 -0
  295. package/src/rsc/handler-context.ts +46 -0
  296. package/src/rsc/handler.ts +905 -1142
  297. package/src/rsc/helpers.ts +275 -19
  298. package/src/rsc/index.ts +2 -25
  299. package/src/rsc/json-route-result.ts +38 -0
  300. package/src/rsc/loader-fetch.ts +305 -0
  301. package/src/rsc/manifest-init.ts +77 -0
  302. package/src/rsc/nonce.ts +14 -0
  303. package/src/rsc/origin-guard.ts +155 -0
  304. package/src/rsc/progressive-enhancement.ts +502 -0
  305. package/src/rsc/redirect-guard.ts +99 -0
  306. package/src/rsc/response-cache-serve.ts +238 -0
  307. package/src/rsc/response-error.ts +104 -0
  308. package/src/rsc/response-route-handler.ts +257 -0
  309. package/src/rsc/rsc-rendering.ts +337 -0
  310. package/src/rsc/runtime-warnings.ts +55 -0
  311. package/src/rsc/server-action.ts +522 -0
  312. package/src/rsc/shell-capture.ts +439 -0
  313. package/src/rsc/ssr-setup.ts +144 -0
  314. package/src/rsc/transition-gate.ts +89 -0
  315. package/src/rsc/types.ts +95 -12
  316. package/src/runtime-env.ts +18 -0
  317. package/src/search-params.ts +99 -82
  318. package/src/segment-content-promise.ts +67 -0
  319. package/src/segment-loader-promise.ts +149 -0
  320. package/src/segment-system.tsx +349 -134
  321. package/src/serialize.ts +243 -0
  322. package/src/server/context.ts +452 -85
  323. package/src/server/cookie-parse.ts +32 -0
  324. package/src/server/cookie-store.ts +310 -0
  325. package/src/server/fetchable-loader-store.ts +11 -6
  326. package/src/server/handle-store.ts +123 -42
  327. package/src/server/live.ts +130 -0
  328. package/src/server/loader-registry.ts +51 -100
  329. package/src/server/request-context.ts +842 -157
  330. package/src/server.ts +15 -8
  331. package/src/ssr/index.tsx +412 -136
  332. package/src/ssr/ssr-root.tsx +228 -0
  333. package/src/static-handler.ts +45 -18
  334. package/src/testing/cache-status.ts +162 -0
  335. package/src/testing/collect-handle.ts +46 -0
  336. package/src/testing/dispatch.ts +701 -0
  337. package/src/testing/dom.entry.ts +22 -0
  338. package/src/testing/e2e/fixture.ts +188 -0
  339. package/src/testing/e2e/index.ts +128 -0
  340. package/src/testing/e2e/matchers.ts +35 -0
  341. package/src/testing/e2e/page-helpers.ts +272 -0
  342. package/src/testing/e2e/parity.ts +387 -0
  343. package/src/testing/e2e/server.ts +195 -0
  344. package/src/testing/flight-matchers.ts +97 -0
  345. package/src/testing/flight-normalize.ts +11 -0
  346. package/src/testing/flight-runtime.d.ts +57 -0
  347. package/src/testing/flight-tree.ts +682 -0
  348. package/src/testing/flight.entry.ts +52 -0
  349. package/src/testing/flight.ts +257 -0
  350. package/src/testing/generated-routes.ts +199 -0
  351. package/src/testing/index.ts +105 -0
  352. package/src/testing/internal/context.ts +371 -0
  353. package/src/testing/internal/flight-client-globals.ts +30 -0
  354. package/src/testing/internal/seed-vars.ts +54 -0
  355. package/src/testing/render-handler.ts +357 -0
  356. package/src/testing/render-route.tsx +584 -0
  357. package/src/testing/run-loader.ts +385 -0
  358. package/src/testing/run-middleware.ts +205 -0
  359. package/src/testing/run-transition-when.ts +164 -0
  360. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  361. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  362. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  363. package/src/testing/vitest-stubs/version.ts +5 -0
  364. package/src/testing/vitest.ts +305 -0
  365. package/src/theme/ThemeProvider.tsx +40 -72
  366. package/src/theme/ThemeScript.tsx +12 -14
  367. package/src/theme/constants.ts +57 -15
  368. package/src/theme/index.ts +3 -20
  369. package/src/theme/theme-context.ts +5 -35
  370. package/src/theme/theme-script.ts +43 -39
  371. package/src/theme/use-theme.ts +0 -3
  372. package/src/types/boundaries.ts +123 -0
  373. package/src/types/cache-types.ts +207 -0
  374. package/src/types/error-types.ts +132 -0
  375. package/src/types/global-namespace.ts +113 -0
  376. package/src/types/handler-context.ts +839 -0
  377. package/src/types/index.ts +81 -0
  378. package/src/types/loader-types.ts +212 -0
  379. package/src/types/request-scope.ts +112 -0
  380. package/src/types/route-config.ts +138 -0
  381. package/src/types/route-entry.ts +114 -0
  382. package/src/types/segments.ts +271 -0
  383. package/src/types.ts +1 -1795
  384. package/src/urls/include-helper.ts +162 -0
  385. package/src/urls/include-provider.ts +71 -0
  386. package/src/urls/index.ts +43 -0
  387. package/src/urls/path-helper-types.ts +413 -0
  388. package/src/urls/path-helper.ts +275 -0
  389. package/src/urls/pattern-types.ts +124 -0
  390. package/src/urls/response-types.ts +109 -0
  391. package/src/urls/type-extraction.ts +316 -0
  392. package/src/urls/urls-function.ts +80 -0
  393. package/src/urls.ts +1 -1341
  394. package/src/use-loader.tsx +406 -141
  395. package/src/vercel/index.ts +11 -0
  396. package/src/vercel/tracing.ts +88 -0
  397. package/src/vite/debug.ts +185 -0
  398. package/src/vite/discovery/bundle-postprocess.ts +182 -0
  399. package/src/vite/discovery/discover-routers.ts +389 -0
  400. package/src/vite/discovery/discovery-errors.ts +255 -0
  401. package/src/vite/discovery/gate-state.ts +171 -0
  402. package/src/vite/discovery/prerender-collection.ts +467 -0
  403. package/src/vite/discovery/route-types-writer.ts +214 -0
  404. package/src/vite/discovery/self-gen-tracking.ts +73 -0
  405. package/src/vite/discovery/state.ts +161 -0
  406. package/src/vite/discovery/virtual-module-codegen.ts +183 -0
  407. package/src/vite/index.ts +23 -2255
  408. package/src/vite/inject-client-debug.ts +36 -0
  409. package/src/vite/plugin-types.ts +303 -0
  410. package/src/vite/plugins/cjs-to-esm.ts +90 -0
  411. package/src/vite/plugins/client-ref-dedup.ts +120 -0
  412. package/src/vite/plugins/client-ref-hashing.ts +118 -0
  413. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  414. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  415. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  416. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
  417. package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
  418. package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
  419. package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
  420. package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
  421. package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
  422. package/src/vite/plugins/expose-ids/types.ts +45 -0
  423. package/src/vite/plugins/expose-internal-ids.ts +805 -0
  424. package/src/vite/plugins/performance-tracks.ts +89 -0
  425. package/src/vite/plugins/refresh-cmd.ts +127 -0
  426. package/src/vite/plugins/use-cache-transform.ts +313 -0
  427. package/src/vite/plugins/vercel-output.ts +384 -0
  428. package/src/vite/plugins/version-injector.ts +94 -0
  429. package/src/vite/plugins/version-plugin.ts +263 -0
  430. package/src/vite/plugins/virtual-entries.ts +234 -0
  431. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  432. package/src/vite/rango.ts +560 -0
  433. package/src/vite/router-discovery.ts +1638 -0
  434. package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
  435. package/src/vite/utils/banner.ts +36 -0
  436. package/src/vite/utils/bundle-analysis.ts +132 -0
  437. package/src/vite/utils/client-chunks.ts +184 -0
  438. package/src/vite/utils/directive-prologue.ts +40 -0
  439. package/src/vite/utils/forward-user-plugins.ts +171 -0
  440. package/src/vite/utils/manifest-utils.ts +15 -0
  441. package/src/vite/utils/package-resolution.ts +89 -0
  442. package/src/vite/utils/prerender-utils.ts +249 -0
  443. package/src/vite/utils/shared-utils.ts +269 -0
  444. package/CLAUDE.md +0 -43
  445. package/dist/vite/index.named-routes.gen.ts +0 -103
  446. package/src/browser/lru-cache.ts +0 -69
  447. package/src/browser/react/use-client-cache.ts +0 -56
  448. package/src/browser/request-controller.ts +0 -164
  449. package/src/browser/shallow.ts +0 -35
  450. package/src/cache/memory-store.ts +0 -253
  451. package/src/handles/index.ts +0 -6
  452. package/src/href-context.ts +0 -33
  453. package/src/network-error-thrower.tsx +0 -21
  454. package/src/router.gen.ts +0 -6
  455. package/src/static-handler.gen.ts +0 -5
  456. package/src/urls.gen.ts +0 -8
  457. package/src/vite/expose-internal-ids.ts +0 -1167
  458. package/src/vite/package-resolution.ts +0 -125
  459. package/src/vite/virtual-entries.ts +0 -114
  460. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -12,20 +12,26 @@
12
12
  */
13
13
 
14
14
  import type { MiddlewareFn, MiddlewareContext } from "../router/middleware.js";
15
- import { getRequestContext } from "../server/request-context.js";
15
+ import { hasPerClientSignal } from "../browser/cookie-name.js";
16
+ import {
17
+ getRequestContext,
18
+ runWithRequestContext,
19
+ type RequestContext,
20
+ } from "../server/request-context.js";
21
+ import { mayNeedSSR } from "../rsc/ssr-setup.js";
22
+ import { sortedSearchString } from "./cache-key-utils.js";
23
+ import { runBackground } from "./background-task.js";
24
+ import { reportCacheError } from "./cache-error.js";
16
25
 
17
- // ============================================================================
18
- // Constants
19
- // ============================================================================
20
-
21
- /** Header indicating cache status for debugging */
22
26
  const CACHE_STATUS_HEADER = "x-document-cache-status";
23
27
 
24
- /**
25
- * Simple hash function for segment IDs.
26
- * Creates a short, deterministic hash to differentiate cache keys
27
- * based on which segments the client already has.
28
- */
28
+ function collectRequestTags(
29
+ requestCtx: RequestContext | undefined,
30
+ ): string[] | undefined {
31
+ const tags = requestCtx?._requestTags;
32
+ return tags && tags.size > 0 ? [...tags] : undefined;
33
+ }
34
+
29
35
  function hashSegmentIds(segmentIds: string): string {
30
36
  if (!segmentIds) return "";
31
37
 
@@ -34,12 +40,9 @@ function hashSegmentIds(segmentIds: string): string {
34
40
  const char = segmentIds.charCodeAt(i);
35
41
  hash = ((hash << 5) - hash + char) | 0;
36
42
  }
37
- // Convert to base36 for shorter string, take absolute value
38
43
  return Math.abs(hash).toString(36);
39
44
  }
40
45
 
41
- // ============================================================================
42
- // Cache Control Parsing
43
46
  // ============================================================================
44
47
 
45
48
  interface CacheDirectives {
@@ -53,6 +56,27 @@ interface CacheDirectives {
53
56
  function parseCacheControl(header: string | null): CacheDirectives | null {
54
57
  if (!header) return null;
55
58
 
59
+ // RFC 7234: in a SHARED cache, `private` and `no-store` forbid storage and
60
+ // MUST win over `s-maxage` even though `private, s-maxage` is contradictory.
61
+ // The document cache is a shared edge store, so refuse both regardless of any
62
+ // s-maxage / stale-while-revalidate also present. Match standalone directive
63
+ // tokens (start/end, whitespace, comma, semicolon, or `=` bounded), not a
64
+ // substring, so a value containing "private" cannot false-veto.
65
+ if (/(^|[\s,;])(private|no-store)(?=$|[\s,;=])/i.test(header)) {
66
+ return null;
67
+ }
68
+
69
+ // RFC 7234 §5.2.2.2: a shared cache MUST NOT serve a stored `no-cache`
70
+ // response without successful origin validation. This store's hit path has no
71
+ // validation step, so serving a stored no-cache response within s-maxage
72
+ // would hand the client content the origin marked must-revalidate. Refuse to
73
+ // store it. Only UNqualified `no-cache` (no `=`) vetoes — the field-name-
74
+ // scoped `no-cache="set-cookie"` form IS storable per the RFC, so the `=`
75
+ // boundary is excluded from the lookahead (unlike private/no-store above).
76
+ if (/(^|[\s,;])no-cache(?=$|[\s,;])/i.test(header)) {
77
+ return null;
78
+ }
79
+
56
80
  const directives: CacheDirectives = {};
57
81
 
58
82
  // Parse s-maxage
@@ -84,6 +108,16 @@ function shouldCacheResponse(response: Response): CacheDirectives | null {
84
108
  return null;
85
109
  }
86
110
 
111
+ // Never cache a per-client signal into a SHARED response store. A Set-Cookie
112
+ // (e.g. a rango state rotation from invalidateClientCache(), or any cookie a
113
+ // loader set) would be replayed to every client on a hit — pinning them to
114
+ // one value and even rolling a rotated client back to a prior one. The
115
+ // x-rango-keep-cache directive header is the mirror image: a replayed "keep"
116
+ // would suppress invalidation for every replayed client. Refuse both.
117
+ if (hasPerClientSignal(response.headers)) {
118
+ return null;
119
+ }
120
+
87
121
  const cacheControl = response.headers.get("Cache-Control");
88
122
  return parseCacheControl(cacheControl);
89
123
  }
@@ -110,15 +144,24 @@ function addCacheStatusHeader(
110
144
  }
111
145
 
112
146
  /**
113
- * Run onResponse callbacks registered on the request context
147
+ * Drain and run onResponse callbacks registered on the request context.
148
+ * Mirrors the drain semantics of finalizeResponse() in rsc/helpers.ts:
149
+ * callbacks are spliced out so they fire at most once per request.
114
150
  */
115
- function runOnResponseCallbacks(
151
+ function drainOnResponseCallbacks(
116
152
  response: Response,
117
- callbacks: Array<(response: Response) => Response>,
153
+ requestCtx:
154
+ | { _onResponseCallbacks: Array<(r: Response) => Response> }
155
+ | undefined,
118
156
  ): Response {
157
+ if (!requestCtx || requestCtx._onResponseCallbacks.length === 0) {
158
+ return response;
159
+ }
160
+ const callbacks = requestCtx._onResponseCallbacks;
161
+ requestCtx._onResponseCallbacks = [];
119
162
  let result = response;
120
163
  for (const callback of callbacks) {
121
- result = callback(result);
164
+ result = callback(result) ?? result;
122
165
  }
123
166
  return result;
124
167
  }
@@ -185,9 +228,7 @@ export function createDocumentCacheMiddleware<TEnv = any>(
185
228
  ): MiddlewareFn<TEnv> {
186
229
  const { skipPaths = [], keyGenerator, isEnabled, debug = false } = options;
187
230
 
188
- const log = debug
189
- ? (message: string) => console.log(message)
190
- : () => {};
231
+ const log = debug ? (message: string) => console.log(message) : () => {};
191
232
 
192
233
  return async function documentCacheMiddleware(
193
234
  ctx: MiddlewareContext<TEnv>,
@@ -195,13 +236,24 @@ export function createDocumentCacheMiddleware<TEnv = any>(
195
236
  ): Promise<Response> {
196
237
  const url = ctx.url;
197
238
 
239
+ // Use the original request URL for _rsc* param detection and cache key
240
+ // differentiation. ctx.url is stripped of _rsc* params by the middleware
241
+ // pipeline (stripInternalParams), so _rsc_partial, _rsc_segments, etc.
242
+ // are not visible on ctx.url in production.
243
+ const rawUrl = new URL(ctx.request.url);
244
+
245
+ // Only cache GET requests — mutations and other methods must not be cached
246
+ if (ctx.request.method !== "GET") {
247
+ return next();
248
+ }
249
+
198
250
  // Skip RSC action requests (mutations shouldn't be cached)
199
- if (url.searchParams.has("_rsc_action")) {
251
+ if (rawUrl.searchParams.has("_rsc_action")) {
200
252
  return next();
201
253
  }
202
254
 
203
255
  // Skip loader requests (have their own caching)
204
- if (url.searchParams.has("_rsc_loader")) {
256
+ if (rawUrl.searchParams.has("_rsc_loader")) {
205
257
  return next();
206
258
  }
207
259
 
@@ -227,21 +279,38 @@ export function createDocumentCacheMiddleware<TEnv = any>(
227
279
  return next();
228
280
  }
229
281
 
230
- // Determine request type for cache key differentiation
231
- const isPartial = url.searchParams.has("_rsc_partial");
232
- const typeLabel = isPartial ? "RSC" : "HTML";
282
+ // Determine request type for cache key differentiation.
283
+ // Uses rawUrl for _rsc* param checks and mayNeedSSR for Accept-based
284
+ // detection. Full-document RSC fetches must not share the HTML cache slot.
285
+ const isPartial = rawUrl.searchParams.has("_rsc_partial");
286
+ const isRscRequest = !mayNeedSSR(ctx.request, rawUrl);
287
+ const typeLabel = isRscRequest ? "RSC" : "HTML";
233
288
 
234
- // Generate cache key
235
- // For partial requests, include hash of client segments to prevent serving
236
- // wrong cached response when navigating from different pages with different layouts
237
- const clientSegments = url.searchParams.get("_rsc_segments") || "";
238
- const segmentHash = isPartial && clientSegments ? `:${hashSegmentIds(clientSegments)}` : "";
239
- const typeSuffix = isPartial ? ":rsc" : ":html";
240
- const cacheKey = keyGenerator
241
- ? keyGenerator(url) + segmentHash + typeSuffix
242
- : `${url.pathname}${segmentHash}${typeSuffix}`;
289
+ // Track whether next() has been called so the catch block knows
290
+ // whether it is safe to fall through to the handler.
291
+ let handlerCalled = false;
243
292
 
244
293
  try {
294
+ // Generate cache key inside try so a throwing keyGenerator degrades
295
+ // gracefully to the origin handler instead of rejecting the request.
296
+ // This is a deliberate fail-open-to-origin policy: the fallback is
297
+ // "serve uncached from origin", not "use a different cache key".
298
+ const clientSegments = rawUrl.searchParams.get("_rsc_segments") || "";
299
+ const segmentHash =
300
+ isPartial && clientSegments ? `:${hashSegmentIds(clientSegments)}` : "";
301
+ const typeSuffix = isRscRequest ? ":rsc" : ":html";
302
+
303
+ let searchSuffix = "";
304
+ if (!keyGenerator) {
305
+ const sorted = sortedSearchString(url.searchParams);
306
+ if (sorted) {
307
+ searchSuffix = `?${sorted}`;
308
+ }
309
+ }
310
+
311
+ const cacheKey = keyGenerator
312
+ ? keyGenerator(url) + segmentHash + typeSuffix
313
+ : `${url.pathname}${searchSuffix}${segmentHash}${typeSuffix}`;
245
314
  // 1. Check cache
246
315
  const cached = await store.getResponse(cacheKey);
247
316
 
@@ -249,79 +318,112 @@ export function createDocumentCacheMiddleware<TEnv = any>(
249
318
  if (!cached.shouldRevalidate) {
250
319
  // Fresh hit - return immediately
251
320
  log(`[DocumentCache] HIT ${typeLabel}: ${url.pathname}`);
252
- let response = addCacheStatusHeader(cached.response, "HIT");
253
- // Run onResponse callbacks even for cache hits
254
- if (requestCtx && requestCtx._onResponseCallbacks.length > 0) {
255
- response = runOnResponseCallbacks(
256
- response,
257
- requestCtx._onResponseCallbacks,
258
- );
259
- }
260
- return response;
321
+ return drainOnResponseCallbacks(
322
+ addCacheStatusHeader(cached.response, "HIT"),
323
+ requestCtx,
324
+ );
261
325
  }
262
326
 
263
327
  // Stale hit - return cached response, revalidate in background
264
- log(`[DocumentCache] STALE ${typeLabel}: ${url.pathname} (revalidating)`);
265
-
266
- if (requestCtx) {
267
- requestCtx.waitUntil(async () => {
268
- try {
269
- const fresh = await next();
270
- const directives = shouldCacheResponse(fresh);
271
-
272
- if (directives) {
273
- await store.putResponse!(
274
- cacheKey,
275
- fresh,
276
- directives.sMaxAge!,
277
- directives.staleWhileRevalidate,
278
- );
279
- log(`[DocumentCache] REVALIDATED ${typeLabel}: ${url.pathname}`);
280
- }
281
- } catch (error) {
282
- console.error(`[DocumentCache] Revalidation failed:`, error);
328
+ log(
329
+ `[DocumentCache] STALE ${typeLabel}: ${url.pathname} (revalidating)`,
330
+ );
331
+
332
+ runBackground(requestCtx, async () => {
333
+ try {
334
+ // Re-establish the request-context ALS around the background
335
+ // re-render: next() re-runs the full handler pipeline, and on
336
+ // workerd a waitUntil task runs detached from the request's I/O
337
+ // context, so a handler/component reading getRequestContext() would
338
+ // otherwise throw. Same fix as the route-level/use-cache background
339
+ // revalidation paths.
340
+ const fresh = await runWithRequestContext(requestCtx, () => next());
341
+ const directives = shouldCacheResponse(fresh);
342
+
343
+ if (directives && fresh.body) {
344
+ // Background revalidation: nothing streams to a client, so drain
345
+ // the fresh render fully before snapshotting tags (same
346
+ // render-complete barrier as the miss path).
347
+ const body = await new Response(fresh.body).arrayBuffer();
348
+ await store.putResponse!(
349
+ cacheKey,
350
+ new Response(body, fresh),
351
+ directives.sMaxAge!,
352
+ directives.staleWhileRevalidate,
353
+ collectRequestTags(requestCtx),
354
+ );
355
+ log(`[DocumentCache] REVALIDATED ${typeLabel}: ${url.pathname}`);
283
356
  }
284
- });
285
- }
357
+ } catch (error) {
358
+ // Pass requestCtx explicitly: this runs in a detached waitUntil task
359
+ // where the ALS context is gone, so onError only fires if we hand it
360
+ // the captured context (reportCacheError falls back to _getRequestContext
361
+ // otherwise, which is null here).
362
+ reportCacheError(
363
+ error,
364
+ "cache-write",
365
+ "[DocumentCache] revalidation",
366
+ requestCtx,
367
+ );
368
+ }
369
+ });
286
370
 
287
- let response = addCacheStatusHeader(cached.response, "STALE");
288
- // Run onResponse callbacks even for stale cache hits
289
- if (requestCtx && requestCtx._onResponseCallbacks.length > 0) {
290
- response = runOnResponseCallbacks(
291
- response,
292
- requestCtx._onResponseCallbacks,
293
- );
294
- }
295
- return response;
371
+ return drainOnResponseCallbacks(
372
+ addCacheStatusHeader(cached.response, "STALE"),
373
+ requestCtx,
374
+ );
296
375
  }
297
376
 
298
377
  // 2. Cache miss - run handler
378
+ handlerCalled = true;
299
379
  const originalResponse = await next();
300
380
 
301
381
  // 3. Cache if response has appropriate headers
302
382
  const directives = shouldCacheResponse(originalResponse);
303
383
 
304
384
  if (directives) {
305
- log(`[DocumentCache] MISS ${typeLabel}: ${url.pathname} (caching with s-maxage=${directives.sMaxAge})`);
385
+ log(
386
+ `[DocumentCache] MISS ${typeLabel}: ${url.pathname} (caching with s-maxage=${directives.sMaxAge})`,
387
+ );
388
+
389
+ // If the response has no body (e.g., 200 with empty body), skip caching
390
+ if (!originalResponse.body) {
391
+ return originalResponse;
392
+ }
306
393
 
307
394
  // Tee the body so we can return one stream and cache the other
308
- const [returnStream, cacheStream] = originalResponse.body!.tee();
395
+ const [returnStream, cacheStream] = originalResponse.body.tee();
309
396
 
310
397
  // Clone response for caching (non-blocking)
311
- if (requestCtx) {
312
- requestCtx.waitUntil(async () => {
313
- try {
314
- await store.putResponse!(
315
- cacheKey,
316
- new Response(cacheStream, originalResponse),
317
- directives.sMaxAge!,
318
- directives.staleWhileRevalidate,
319
- );
320
- } catch (error) {
321
- console.error(`[DocumentCache] Cache write failed:`, error);
322
- }
323
- });
324
- }
398
+ runBackground(requestCtx, async () => {
399
+ try {
400
+ // Drain the cache copy fully BEFORE snapshotting tags. Tags from
401
+ // Suspense-streamed "use cache"/cacheTag and loaders are recorded as
402
+ // each value resolves during the RSC/HTML render, which completes
403
+ // only when the stream ends - the handler-settlement barrier is too
404
+ // early. Buffering the body (the client streams the other tee branch,
405
+ // unaffected) is the render-complete barrier that keeps the cached
406
+ // body and its tag set consistent.
407
+ const body = await new Response(cacheStream).arrayBuffer();
408
+ await store.putResponse!(
409
+ cacheKey,
410
+ new Response(body, originalResponse),
411
+ directives.sMaxAge!,
412
+ directives.staleWhileRevalidate,
413
+ collectRequestTags(requestCtx),
414
+ );
415
+ } catch (error) {
416
+ // Detached waitUntil task — pass the captured requestCtx so onError
417
+ // fires even though the ALS context is gone (see the revalidation
418
+ // catch above).
419
+ reportCacheError(
420
+ error,
421
+ "cache-write",
422
+ "[DocumentCache] cache write",
423
+ requestCtx,
424
+ );
425
+ }
426
+ });
325
427
 
326
428
  return addCacheStatusHeader(
327
429
  new Response(returnStream, originalResponse),
@@ -332,8 +434,13 @@ export function createDocumentCacheMiddleware<TEnv = any>(
332
434
  // No cache headers - pass through
333
435
  return originalResponse;
334
436
  } catch (error) {
335
- console.error(`[DocumentCache] Error:`, error);
336
- // On any cache error, fall through to handler
437
+ reportCacheError(error, "cache-read", "[DocumentCache] middleware");
438
+ if (handlerCalled) {
439
+ // Post-handler failure (e.g. body.tee()): do not call next() again
440
+ // as that would re-run handler side effects.
441
+ throw error;
442
+ }
443
+ // Pre-handler failure (cache lookup): degrade gracefully to origin
337
444
  return next();
338
445
  }
339
446
  };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Handle Capture
3
+ *
4
+ * Captures handle pushes during cached function execution.
5
+ * Extracted from cache-runtime.ts so tests can import without
6
+ * pulling in @vitejs/plugin-rsc/rsc dependencies.
7
+ */
8
+
9
+ import type { HandleStore } from "../server/handle-store.js";
10
+ import type { SegmentHandleData } from "./types.js";
11
+
12
+ export interface HandleCapture {
13
+ data: Record<string, SegmentHandleData>;
14
+ }
15
+
16
+ /**
17
+ * Active capture tokens per HandleStore.
18
+ *
19
+ * Instead of mutating handleStore.push (which breaks when overlapping
20
+ * captures finish out of order), we install a single interceptor on
21
+ * first use and manage a set of active capture tokens. Each push fans
22
+ * out to every active token. Stopping a capture simply removes the
23
+ * token — order does not matter.
24
+ */
25
+ const activeCapturesMap = new WeakMap<HandleStore, Set<HandleCapture>>();
26
+
27
+ /**
28
+ * One-time interceptor installation. Wraps the original push so every
29
+ * call fans out to all active capture tokens. Installed once per
30
+ * HandleStore instance; subsequent startHandleCapture calls on the
31
+ * same store just add tokens to the Set.
32
+ */
33
+ function ensureInterceptorInstalled(handleStore: HandleStore): void {
34
+ if (activeCapturesMap.has(handleStore)) return;
35
+
36
+ const captures = new Set<HandleCapture>();
37
+ activeCapturesMap.set(handleStore, captures);
38
+
39
+ const originalPush = handleStore.push.bind(handleStore);
40
+ handleStore.push = (
41
+ handleName: string,
42
+ segmentId: string,
43
+ value: unknown,
44
+ ) => {
45
+ for (const capture of captures) {
46
+ if (!capture.data[segmentId]) {
47
+ capture.data[segmentId] = {};
48
+ }
49
+ if (!capture.data[segmentId][handleName]) {
50
+ capture.data[segmentId][handleName] = [];
51
+ }
52
+ capture.data[segmentId][handleName].push(value);
53
+ }
54
+ originalPush(handleName, segmentId, value);
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Start capturing handle pushes for a cached function execution.
60
+ *
61
+ * Concurrency-safe: multiple overlapping captures on the same
62
+ * HandleStore are independent. Each capture registers a token in a
63
+ * Set; stopping removes it. No ordering requirement (LIFO not needed).
64
+ */
65
+ export function startHandleCapture(handleStore: HandleStore): {
66
+ capture: HandleCapture;
67
+ stop: () => void;
68
+ } {
69
+ ensureInterceptorInstalled(handleStore);
70
+
71
+ const capture: HandleCapture = { data: {} };
72
+ const captures = activeCapturesMap.get(handleStore)!;
73
+ captures.add(capture);
74
+
75
+ return {
76
+ capture,
77
+ stop() {
78
+ captures.delete(capture);
79
+ },
80
+ };
81
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Handle Snapshot
3
+ *
4
+ * Capture and restore handle data for cached segments.
5
+ * Handle data (breadcrumbs, metadata from ctx.use(Handle)) is collected
6
+ * during segment resolution and stored alongside cached segments.
7
+ */
8
+
9
+ import type { ResolvedSegment } from "../types.js";
10
+ import type { HandleStore } from "../server/handle-store.js";
11
+ import type { SegmentHandleData } from "./types.js";
12
+ // segment-codec eagerly pulls @vitejs/plugin-rsc (a virtual: module unresolvable
13
+ // in plain node/vitest). It is imported LAZILY inside the two async encode/decode
14
+ // helpers below so that modules which import handle-snapshot only for the
15
+ // plugin-rsc-free captureHandles/restoreHandles (e.g. cache-scope, on dispatch's
16
+ // lazy response-route cache path) do not pull plugin-rsc at module load. Behavior
17
+ // is unchanged: both helpers are async and already awaited the codec.
18
+
19
+ const HANDLE_ENCODE_TIMEOUT_MS = 5000;
20
+
21
+ type HandleRecord = Record<string, SegmentHandleData>;
22
+
23
+ function hasHandleData(handles: HandleRecord): boolean {
24
+ for (const segId in handles) {
25
+ for (const _ in handles[segId]) return true;
26
+ }
27
+ return false;
28
+ }
29
+
30
+ function withTimeout<T>(p: Promise<T>, ms: number, onTimeout: T): Promise<T> {
31
+ let timer: ReturnType<typeof setTimeout>;
32
+ const timeout = new Promise<T>((resolve) => {
33
+ timer = setTimeout(() => resolve(onTimeout), ms);
34
+ });
35
+ return Promise.race([
36
+ p.then(
37
+ (v) => {
38
+ clearTimeout(timer);
39
+ return v;
40
+ },
41
+ (e) => {
42
+ clearTimeout(timer);
43
+ throw e;
44
+ },
45
+ ),
46
+ timeout,
47
+ ]);
48
+ }
49
+
50
+ export async function encodeHandles(handles: HandleRecord): Promise<string> {
51
+ if (!hasHandleData(handles)) return "";
52
+ return encodeHandleValue(handles);
53
+ }
54
+
55
+ export function decodeHandles(encoded: string): Promise<HandleRecord | null> {
56
+ return decodeHandleValue<HandleRecord>(encoded);
57
+ }
58
+
59
+ export async function encodeHandleValue(value: unknown): Promise<string> {
60
+ const { serializeResult } = await import("./segment-codec.js");
61
+ const encoded = await withTimeout(
62
+ serializeResult(value),
63
+ HANDLE_ENCODE_TIMEOUT_MS,
64
+ null,
65
+ );
66
+ return encoded ?? "";
67
+ }
68
+
69
+ /**
70
+ * Decode a Flight-encoded handle-data string. Returns null on any decode
71
+ * failure so the caller can skip handle restore without discarding valid
72
+ * cached/prerendered segments.
73
+ */
74
+ export async function decodeHandleValue<T>(encoded: string): Promise<T | null> {
75
+ try {
76
+ const { deserializeResult } = await import("./segment-codec.js");
77
+ return await deserializeResult<T>(encoded);
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Capture handle data for a set of segments from the handle store.
85
+ * Used when caching segments to preserve their handle data.
86
+ */
87
+ export function captureHandles(
88
+ segments: ResolvedSegment[],
89
+ handleStore: HandleStore,
90
+ ): Record<string, SegmentHandleData> {
91
+ const handles: Record<string, SegmentHandleData> = {};
92
+ for (const seg of segments) {
93
+ handles[seg.id] = handleStore.getDataForSegment(seg.id);
94
+ }
95
+ return handles;
96
+ }
97
+
98
+ /**
99
+ * Restore handle data from a cached snapshot into the handle store.
100
+ * Used when serving cached segments to replay their handle data.
101
+ */
102
+ export function restoreHandles(
103
+ handles: Record<string, SegmentHandleData>,
104
+ handleStore: HandleStore,
105
+ ): void {
106
+ for (const [segId, segHandles] of Object.entries(handles)) {
107
+ if (Object.keys(segHandles).length > 0) {
108
+ handleStore.replaySegmentData(segId, segHandles);
109
+ }
110
+ }
111
+ }
@@ -1,58 +1,52 @@
1
- /**
2
- * Cache Store
3
- *
4
- * Server-side caching for RSC segments and loader data.
5
- *
6
- * Main exports for users:
7
- * - SegmentCacheStore - Interface for implementing custom cache stores
8
- * - MemorySegmentCacheStore - In-memory cache for development/testing
9
- * - CFCacheStore - Cloudflare edge cache store for production
10
- * - CacheScope / createCacheScope - Request-scoped cache provider
11
- */
12
-
13
- // Generic cache store types (reserved for future extensibility)
14
- // These types support caching arbitrary values like Response, Stream, etc.
15
- // Currently unused - segment caching uses SegmentCacheStore directly.
16
- export type {
17
- CacheStore,
18
- CacheEntry,
19
- CacheValue,
20
- CacheValueType,
21
- CachePutOptions,
22
- CacheMetadata,
23
- } from "./types.js";
24
-
25
- // Generic memory cache (reserved for future extensibility)
26
- export { MemoryCacheStore } from "./memory-store.js";
27
-
28
- // Segment cache store types and implementations
29
1
  export type {
30
2
  SegmentCacheStore,
31
- SegmentCacheProvider,
32
3
  CachedEntryData,
33
- CachedEntryResult,
34
4
  CacheGetResult,
5
+ CacheItemResult,
6
+ CacheItemOptions,
7
+ ShellCacheEntry,
35
8
  SerializedSegmentData,
36
9
  SegmentHandleData,
37
- CacheConfig,
38
- CacheConfigOrFactory,
39
10
  } from "./types.js";
40
11
 
41
12
  export { MemorySegmentCacheStore } from "./memory-segment-store.js";
42
13
 
43
- // Cloudflare cache store
44
14
  export {
45
15
  CFCacheStore,
46
16
  type CFCacheStoreOptions,
17
+ type CFCacheDebug,
18
+ type CFCacheReadDebugEvent,
19
+ type KVNamespace,
47
20
  CACHE_STALE_AT_HEADER,
48
21
  CACHE_STATUS_HEADER,
22
+ CACHE_REVALIDATING_AT_HEADER,
23
+ EDGE_LOOKUP_TIMEOUT_MS,
24
+ EDGE_READ_TIMEOUT_MS,
25
+ KV_READ_TIMEOUT_MS,
49
26
  } from "./cf/index.js";
50
27
 
51
- // Cache scope
28
+ export {
29
+ VercelCacheStore,
30
+ type VercelCacheStoreOptions,
31
+ type VercelRuntimeCache,
32
+ type VercelCacheDebug,
33
+ type VercelCacheReadDebugEvent,
34
+ type VercelCacheReadOutcome,
35
+ VERCEL_MAX_ITEM_BYTES,
36
+ VERCEL_MAX_TAGS_PER_ITEM,
37
+ VERCEL_MAX_TAG_BYTES,
38
+ } from "./vercel/index.js";
39
+
52
40
  export { CacheScope, createCacheScope } from "./cache-scope.js";
53
41
 
54
- // Document-level cache middleware
55
42
  export {
56
43
  createDocumentCacheMiddleware,
57
44
  type DocumentCacheOptions,
58
45
  } from "./document-cache.js";
46
+
47
+ export {
48
+ createShellCacheMiddleware,
49
+ type ShellCacheOptions,
50
+ } from "./shell-cache.js";
51
+
52
+ export type { CacheErrorCategory } from "./cache-error.js";