@rangojs/router 0.17.0 → 0.19.0

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 (293) hide show
  1. package/README.md +3 -2
  2. package/dist/types/browser/cookie-name.d.ts +6 -0
  3. package/dist/types/browser/event-controller.d.ts +3 -3
  4. package/dist/types/browser/history-state.d.ts +18 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +20 -2
  6. package/dist/types/browser/partial-update.d.ts +16 -1
  7. package/dist/types/browser/prefetch/cache.d.ts +6 -6
  8. package/dist/types/browser/react/Link.d.ts +19 -9
  9. package/dist/types/browser/react/context.d.ts +2 -2
  10. package/dist/types/browser/react/location-state-shared.d.ts +95 -56
  11. package/dist/types/browser/react/location-state.d.ts +1 -1
  12. package/dist/types/browser/transition-when.d.ts +80 -0
  13. package/dist/types/browser/types.d.ts +104 -9
  14. package/dist/types/build/generate-manifest.d.ts +8 -0
  15. package/dist/types/cache/background-task.d.ts +24 -2
  16. package/dist/types/cache/cache-exec-scope.d.ts +31 -0
  17. package/dist/types/cache/cache-key-utils.d.ts +48 -2
  18. package/dist/types/cache/cache-policy.d.ts +18 -1
  19. package/dist/types/cache/cache-runtime.d.ts +7 -0
  20. package/dist/types/cache/cache-scope.d.ts +192 -26
  21. package/dist/types/cache/cache-tag.d.ts +116 -11
  22. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  23. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  24. package/dist/types/cache/cf/cf-cache-store.d.ts +224 -72
  25. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  26. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  27. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +19 -0
  28. package/dist/types/cache/document-cache.d.ts +10 -0
  29. package/dist/types/cache/handle-snapshot.d.ts +41 -8
  30. package/dist/types/cache/index.d.ts +1 -0
  31. package/dist/types/cache/invalidation-order.d.ts +23 -0
  32. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  33. package/dist/types/cache/request-tag-mask.d.ts +54 -0
  34. package/dist/types/cache/shell-memo.d.ts +178 -0
  35. package/dist/types/cache/shell-snapshot.d.ts +141 -105
  36. package/dist/types/cache/tag-invalidation.d.ts +54 -3
  37. package/dist/types/cache/types.d.ts +267 -96
  38. package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
  39. package/dist/types/client-urls/navigation.d.ts +28 -2
  40. package/dist/types/client-urls/server-projection.d.ts +5 -2
  41. package/dist/types/client-urls/types.d.ts +5 -5
  42. package/dist/types/client.d.ts +1 -1
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.rsc.d.ts +1 -1
  45. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  46. package/dist/types/route-definition/helpers-types.d.ts +11 -11
  47. package/dist/types/route-name.d.ts +7 -0
  48. package/dist/types/router/error-handling.d.ts +1 -1
  49. package/dist/types/router/instrument.d.ts +8 -0
  50. package/dist/types/router/intercept-resolution.d.ts +2 -0
  51. package/dist/types/router/match-context.d.ts +5 -0
  52. package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
  53. package/dist/types/router/middleware-types.d.ts +6 -1
  54. package/dist/types/router/router-options.d.ts +4 -1
  55. package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
  56. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
  57. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
  58. package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
  59. package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
  60. package/dist/types/router/transition-when.d.ts +24 -10
  61. package/dist/types/rsc/attach-transition-when.d.ts +18 -0
  62. package/dist/types/rsc/full-payload.d.ts +21 -0
  63. package/dist/types/rsc/handler.d.ts +1 -1
  64. package/dist/types/rsc/response-cache-serve.d.ts +15 -12
  65. package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
  66. package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
  67. package/dist/types/rsc/shell-capture.d.ts +202 -74
  68. package/dist/types/rsc/shell-serve.d.ts +144 -50
  69. package/dist/types/rsc/types.d.ts +9 -0
  70. package/dist/types/segment-system.d.ts +7 -0
  71. package/dist/types/server/context.d.ts +155 -33
  72. package/dist/types/server/cookie-store.d.ts +33 -0
  73. package/dist/types/server/handle-store.d.ts +52 -1
  74. package/dist/types/server/request-context.d.ts +210 -63
  75. package/dist/types/server/request-headers.d.ts +44 -0
  76. package/dist/types/server.d.ts +1 -0
  77. package/dist/types/ssr/index.d.ts +9 -0
  78. package/dist/types/ssr/ssr-root.d.ts +9 -8
  79. package/dist/types/testing/e2e/index.d.ts +1 -1
  80. package/dist/types/testing/flight.entry.d.ts +7 -0
  81. package/dist/types/testing/index.d.ts +3 -2
  82. package/dist/types/testing/internal/action-id.d.ts +7 -0
  83. package/dist/types/testing/location-state-key.d.ts +24 -0
  84. package/dist/types/testing/render-route.d.ts +17 -1
  85. package/dist/types/testing/run-loader.d.ts +18 -3
  86. package/dist/types/testing/run-transition-when.d.ts +44 -69
  87. package/dist/types/testing/serve-shell-request.d.ts +133 -0
  88. package/dist/types/testing/shell-status.d.ts +44 -19
  89. package/dist/types/transition-when-ref.d.ts +79 -0
  90. package/dist/types/types/cache-types.d.ts +15 -3
  91. package/dist/types/types/handler-context.d.ts +14 -1
  92. package/dist/types/types/index.d.ts +1 -1
  93. package/dist/types/types/segments.d.ts +86 -71
  94. package/dist/types/urls/path-helper-types.d.ts +3 -4
  95. package/dist/types/urls/pattern-types.d.ts +21 -18
  96. package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
  97. package/dist/types/vite/router-discovery.d.ts +29 -2
  98. package/dist/vite/index.js +1005 -105
  99. package/package.json +1 -1
  100. package/skills/breadcrumbs/SKILL.md +17 -7
  101. package/skills/cache-guide/SKILL.md +175 -76
  102. package/skills/caching/SKILL.md +361 -33
  103. package/skills/catalog.json +1 -1
  104. package/skills/client-urls/SKILL.md +12 -7
  105. package/skills/cloudflare/SKILL.md +15 -0
  106. package/skills/comparison/references/framework-comparison.md +52 -37
  107. package/skills/defer-hydration/SKILL.md +50 -30
  108. package/skills/deployment-caching/SKILL.md +5 -2
  109. package/skills/document-cache/SKILL.md +32 -2
  110. package/skills/handler-use/SKILL.md +2 -0
  111. package/skills/hooks/SKILL.md +3 -1
  112. package/skills/hooks/handle-and-actions.md +3 -1
  113. package/skills/hooks/navigation.md +23 -2
  114. package/skills/hooks/state.md +101 -7
  115. package/skills/intercept/SKILL.md +29 -12
  116. package/skills/loader/SKILL.md +197 -44
  117. package/skills/middleware/SKILL.md +34 -9
  118. package/skills/migrate-nextjs/SKILL.md +68 -37
  119. package/skills/migrate-react-router/SKILL.md +2 -1
  120. package/skills/migrate-react-router/component-migration.md +3 -1
  121. package/skills/migrate-react-router/data-and-actions.md +3 -1
  122. package/skills/migrate-react-router/route-mapping.md +7 -4
  123. package/skills/observability/SKILL.md +65 -0
  124. package/skills/parallel/SKILL.md +13 -8
  125. package/skills/ppr/SKILL.md +715 -371
  126. package/skills/prerender/SKILL.md +30 -17
  127. package/skills/rango/SKILL.md +72 -34
  128. package/skills/route/SKILL.md +14 -7
  129. package/skills/router-setup/SKILL.md +4 -2
  130. package/skills/scripts/SKILL.md +8 -1
  131. package/skills/server-actions/SKILL.md +11 -0
  132. package/skills/shell-manifest/SKILL.md +21 -12
  133. package/skills/testing/SKILL.md +49 -43
  134. package/skills/testing/cache-prerender.md +15 -14
  135. package/skills/testing/client-components.md +45 -3
  136. package/skills/testing/loader.md +19 -1
  137. package/skills/testing/middleware.md +1 -0
  138. package/skills/testing/predicates.md +49 -49
  139. package/skills/testing/render-handler.md +1 -0
  140. package/skills/testing/serve-shell-request.md +202 -0
  141. package/skills/testing/server-actions.md +9 -3
  142. package/skills/theme/SKILL.md +56 -4
  143. package/skills/typesafety/env-and-bindings.md +18 -2
  144. package/skills/use-cache/SKILL.md +91 -23
  145. package/skills/vercel/SKILL.md +14 -2
  146. package/skills/view-transitions/SKILL.md +150 -29
  147. package/src/__augment-tests__/augmented.check.ts +23 -0
  148. package/src/browser/cookie-name.ts +23 -0
  149. package/src/browser/event-controller.ts +4 -4
  150. package/src/browser/history-state.ts +75 -1
  151. package/src/browser/link-interceptor.ts +4 -0
  152. package/src/browser/navigation-bridge.ts +77 -18
  153. package/src/browser/navigation-client.ts +4 -3
  154. package/src/browser/navigation-store.ts +43 -1
  155. package/src/browser/navigation-transaction.ts +31 -11
  156. package/src/browser/partial-update.ts +146 -35
  157. package/src/browser/prefetch/cache.ts +6 -6
  158. package/src/browser/prefetch/fetch.ts +2 -2
  159. package/src/browser/react/Link.tsx +38 -33
  160. package/src/browser/react/NavigationProvider.tsx +2 -2
  161. package/src/browser/react/context.ts +2 -2
  162. package/src/browser/react/location-state-shared.ts +241 -49
  163. package/src/browser/react/location-state.ts +5 -2
  164. package/src/browser/rsc-router.tsx +9 -0
  165. package/src/browser/server-action-bridge.ts +84 -15
  166. package/src/browser/transition-when.ts +205 -0
  167. package/src/browser/types.ts +124 -10
  168. package/src/build/generate-manifest.ts +77 -1
  169. package/src/cache/background-task.ts +55 -2
  170. package/src/cache/cache-exec-scope.ts +48 -1
  171. package/src/cache/cache-key-utils.ts +62 -2
  172. package/src/cache/cache-policy.ts +31 -4
  173. package/src/cache/cache-runtime.ts +209 -129
  174. package/src/cache/cache-scope.ts +573 -69
  175. package/src/cache/cache-tag.ts +475 -19
  176. package/src/cache/cf/cf-base64.ts +36 -4
  177. package/src/cache/cf/cf-cache-constants.ts +12 -0
  178. package/src/cache/cf/cf-cache-store.ts +1094 -376
  179. package/src/cache/cf/cf-cache-types.ts +32 -4
  180. package/src/cache/cf/cf-shell-frame.ts +258 -0
  181. package/src/cache/cf/cf-tag-marker-memo.ts +55 -40
  182. package/src/cache/document-cache.ts +53 -7
  183. package/src/cache/handle-snapshot.ts +53 -9
  184. package/src/cache/index.ts +2 -0
  185. package/src/cache/invalidation-order.ts +84 -0
  186. package/src/cache/isolate-tag-memo.ts +308 -0
  187. package/src/cache/request-tag-mask.ts +147 -0
  188. package/src/cache/shell-memo.ts +341 -0
  189. package/src/cache/shell-snapshot.ts +249 -277
  190. package/src/cache/tag-invalidation.ts +109 -18
  191. package/src/cache/types.ts +274 -102
  192. package/src/cache/vercel/vercel-cache-store.ts +561 -74
  193. package/src/client-urls/client-root.tsx +8 -4
  194. package/src/client-urls/client-urls.ts +8 -6
  195. package/src/client-urls/navigation.ts +55 -4
  196. package/src/client-urls/server-projection.ts +31 -10
  197. package/src/client-urls/types.ts +12 -5
  198. package/src/client.tsx +2 -0
  199. package/src/host/cookie-handler.ts +2 -1
  200. package/src/index.rsc.ts +3 -0
  201. package/src/index.ts +3 -0
  202. package/src/loader-redirect.tsx +7 -3
  203. package/src/prerender/build-shell-capture.ts +173 -110
  204. package/src/route-definition/dsl-helpers.ts +6 -3
  205. package/src/route-definition/helpers-types.ts +11 -11
  206. package/src/route-name.ts +12 -0
  207. package/src/router/content-negotiation.ts +4 -1
  208. package/src/router/error-handling.ts +5 -2
  209. package/src/router/handler-context.ts +42 -5
  210. package/src/router/instrument.ts +54 -2
  211. package/src/router/intercept-resolution.ts +30 -8
  212. package/src/router/loader-resolution.ts +89 -33
  213. package/src/router/logging.ts +5 -3
  214. package/src/router/match-api.ts +89 -42
  215. package/src/router/match-context.ts +5 -0
  216. package/src/router/match-handlers.ts +14 -29
  217. package/src/router/match-middleware/background-revalidation.ts +3 -5
  218. package/src/router/match-middleware/cache-lookup.ts +52 -19
  219. package/src/router/match-middleware/cache-store.ts +36 -10
  220. package/src/router/match-result.ts +1 -0
  221. package/src/router/middleware-types.ts +6 -1
  222. package/src/router/middleware.ts +20 -4
  223. package/src/router/navigation-snapshot.ts +6 -5
  224. package/src/router/prerender-match.ts +10 -0
  225. package/src/router/request-classification.ts +7 -4
  226. package/src/router/router-options.ts +4 -1
  227. package/src/router/segment-resolution/fresh.ts +18 -13
  228. package/src/router/segment-resolution/helpers.ts +4 -2
  229. package/src/router/segment-resolution/loader-cache.ts +366 -70
  230. package/src/router/segment-resolution/loader-mask.ts +3 -4
  231. package/src/router/segment-resolution/loader-snapshot.ts +215 -126
  232. package/src/router/segment-resolution/mask-nested.ts +161 -42
  233. package/src/router/segment-resolution/revalidation.ts +27 -13
  234. package/src/router/segment-resolution/view-transition-default.ts +6 -21
  235. package/src/router/telemetry.ts +6 -3
  236. package/src/router/transition-when.ts +34 -52
  237. package/src/router.ts +2 -1
  238. package/src/rsc/attach-transition-when.ts +47 -0
  239. package/src/rsc/full-payload.ts +47 -3
  240. package/src/rsc/handler.ts +24 -10
  241. package/src/rsc/loader-fetch.ts +2 -1
  242. package/src/rsc/manifest-init.ts +4 -0
  243. package/src/rsc/origin-guard.ts +8 -5
  244. package/src/rsc/progressive-enhancement.ts +10 -32
  245. package/src/rsc/response-cache-serve.ts +69 -78
  246. package/src/rsc/response-route-handler.ts +2 -2
  247. package/src/rsc/rsc-rendering.ts +712 -338
  248. package/src/rsc/server-action.ts +8 -20
  249. package/src/rsc/shell-build-manifest.ts +49 -29
  250. package/src/rsc/shell-capture-constants.ts +182 -12
  251. package/src/rsc/shell-capture.ts +1126 -612
  252. package/src/rsc/shell-serve.ts +331 -85
  253. package/src/rsc/ssr-setup.ts +3 -2
  254. package/src/rsc/types.ts +9 -0
  255. package/src/segment-system.tsx +40 -7
  256. package/src/server/context.ts +328 -72
  257. package/src/server/cookie-store.ts +184 -133
  258. package/src/server/handle-store.ts +245 -27
  259. package/src/server/request-context.ts +364 -100
  260. package/src/server/request-headers.ts +134 -0
  261. package/src/server.ts +4 -0
  262. package/src/ssr/index.tsx +96 -37
  263. package/src/ssr/ssr-root.tsx +9 -8
  264. package/src/testing/dispatch.ts +4 -7
  265. package/src/testing/e2e/index.ts +1 -0
  266. package/src/testing/flight.entry.ts +14 -0
  267. package/src/testing/index.ts +5 -0
  268. package/src/testing/internal/action-id.ts +25 -0
  269. package/src/testing/internal/context.ts +1 -1
  270. package/src/testing/location-state-key.ts +45 -0
  271. package/src/testing/render-handler.ts +1 -1
  272. package/src/testing/render-route.tsx +109 -16
  273. package/src/testing/run-client-revalidate.ts +3 -19
  274. package/src/testing/run-loader.ts +67 -5
  275. package/src/testing/run-transition-when.ts +109 -172
  276. package/src/testing/serve-shell-request.ts +381 -0
  277. package/src/testing/shell-status.ts +73 -47
  278. package/src/theme/ThemeProvider.tsx +7 -6
  279. package/src/transition-when-ref.ts +220 -0
  280. package/src/types/cache-types.ts +15 -3
  281. package/src/types/handler-context.ts +14 -1
  282. package/src/types/index.ts +3 -0
  283. package/src/types/segments.ts +94 -91
  284. package/src/urls/path-helper-types.ts +3 -4
  285. package/src/urls/pattern-types.ts +21 -18
  286. package/src/vite/discovery/discover-routers.ts +3 -0
  287. package/src/vite/discovery/shell-prerender-phase.ts +9 -2
  288. package/src/vite/discovery/virtual-module-codegen.ts +16 -6
  289. package/src/vite/plugins/transition-when-hoist.ts +1064 -0
  290. package/src/vite/rango.ts +2 -0
  291. package/src/vite/router-discovery.ts +89 -9
  292. package/dist/types/rsc/transition-gate.d.ts +0 -23
  293. package/src/rsc/transition-gate.ts +0 -86
package/src/vite/rango.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  exposeRouterId,
11
11
  } from "./plugins/expose-internal-ids.js";
12
12
  import { useCacheTransform } from "./plugins/use-cache-transform.js";
13
+ import { transitionWhenHoistPlugin } from "./plugins/transition-when-hoist.js";
13
14
  import { clientRefDedup } from "./plugins/client-ref-dedup.js";
14
15
  import { VIRTUAL_IDS } from "./plugins/virtual-entries.js";
15
16
  import {
@@ -563,6 +564,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
563
564
  });
564
565
 
565
566
  plugins.push(createLoaderDirectiveGuardPlugin());
567
+ plugins.push(transitionWhenHoistPlugin());
566
568
  plugins.push(createLoaderScanStubPlugin());
567
569
  plugins.push(exposeActionId());
568
570
  plugins.push(
@@ -6,7 +6,7 @@
6
6
  * generation, virtual module codegen, and bundle post-processing.
7
7
  */
8
8
 
9
- import type { Plugin } from "vite";
9
+ import type { Plugin, ViteDevServer } from "vite";
10
10
  import { createServer as createViteServer } from "vite";
11
11
  import { resolve } from "node:path";
12
12
  import { readFileSync } from "node:fs";
@@ -65,6 +65,8 @@ import {
65
65
  } from "./discovery/client-urls-projection.js";
66
66
  import { runShellPrerenderPhase } from "./discovery/shell-prerender-phase.js";
67
67
  import { describeDiscoveryFailure } from "./discovery/discovery-errors.js";
68
+ import { findTransitionWhenError } from "../transition-when-ref.js";
69
+ import { transitionWhenHoistPlugin } from "./plugins/transition-when-hoist.js";
68
70
  import {
69
71
  createDevPrerenderCache,
70
72
  devPrerenderCacheKey,
@@ -177,8 +179,9 @@ const injectedShellNotReadyPaths = new Set<string>();
177
179
  * - Build: hashed IDs (forceBuild), hashClientRefs for production bundles
178
180
  *
179
181
  * Returns the ViteDevServer instance. Callers access .environments.rsc as needed.
182
+ * @internal Exported for tests.
180
183
  */
181
- async function createTempRscServer(
184
+ export async function createTempRscServer(
182
185
  state: DiscoveryState,
183
186
  options: {
184
187
  forceBuild?: boolean;
@@ -195,7 +198,7 @@ async function createTempRscServer(
195
198
  */
196
199
  realSsrEntry?: boolean;
197
200
  } = {},
198
- ) {
201
+ ): Promise<ViteDevServer> {
199
202
  // Install the Node ESM loader hook before any module evaluation so
200
203
  // `cloudflare:*` specifiers in externalized/loader-delegated modules
201
204
  // (e.g. packages plugin-rsc marks as external) resolve to stubs
@@ -216,7 +219,16 @@ async function createTempRscServer(
216
219
  return createViteServer({
217
220
  root: state.projectRoot,
218
221
  configFile: false,
219
- server: { middlewareMode: true },
222
+ server: {
223
+ middlewareMode: true,
224
+ // Build mode: no file watching. buildStart installs the per-router tries
225
+ // into this realm and runShellPrerenderPhase reuses it after the bundles
226
+ // are written. A watched write in between (writeRouteTypesFiles' own
227
+ // <router>.named-routes.gen.ts, which every router file imports) can
228
+ // make Vite full-reload the RSC runner; the shell phase then matches in
229
+ // a fresh realm with no tries and a root path("/*") wins (#947).
230
+ ...(options.forceBuild ? { watch: null } : {}),
231
+ },
220
232
  appType: "custom",
221
233
  logLevel: "silent",
222
234
  resolve: resolveConfig,
@@ -276,6 +288,9 @@ async function createTempRscServer(
276
288
  : []),
277
289
  createVirtualStubPlugin(),
278
290
  createCloudflareProtocolStubPlugin(),
291
+ // Inline transition({ when }) literals become client references here
292
+ // too, or discovery would see (and reject) the plain function.
293
+ transitionWhenHoistPlugin(),
279
294
  // Dev prerender must use dev-mode IDs (path-based) to match the workerd
280
295
  // runtime. forceBuild produces hashed IDs for production bundle consistency.
281
296
  exposeInternalIds(options.forceBuild ? { forceBuild: true } : undefined),
@@ -433,6 +448,37 @@ export function createRouterDiscoveryPlugin(
433
448
  let viteCommand: "serve" | "build" = "build";
434
449
  let viteMode = "production";
435
450
 
451
+ // Dev: an invalid transition({ when }) is a definition error the user must
452
+ // see in the browser too, as the Vite error overlay. The overlay does not
453
+ // survive on its own: a reload clears it, and plugin-rsc closes every
454
+ // overlay on each "rsc:update" (the edit's own, the gen-file write's), each
455
+ // followed by the client's RSC refetch. So until a discovery succeeds the
456
+ // pending error is re-sent to every client that connects and after every
457
+ // request the dev server answers (configureServer).
458
+ let transitionWhenOverlay: {
459
+ message: string;
460
+ stack: string;
461
+ plugin: string;
462
+ } | null = null;
463
+ const sendTransitionWhenOverlay = (): void => {
464
+ if (!transitionWhenOverlay) return;
465
+ (s.devServer?.environments as any)?.client?.hot?.send({
466
+ type: "error",
467
+ err: transitionWhenOverlay,
468
+ });
469
+ };
470
+ const showTransitionWhenError = (err: unknown): Error | undefined => {
471
+ const whenError = findTransitionWhenError(err);
472
+ if (!whenError) return undefined;
473
+ transitionWhenOverlay = {
474
+ message: whenError.message,
475
+ stack: whenError.stack ?? "",
476
+ plugin: "@rangojs/router",
477
+ };
478
+ sendTransitionWhenOverlay();
479
+ return whenError;
480
+ };
481
+
436
482
  return {
437
483
  name: "@rangojs/router:discovery",
438
484
 
@@ -515,6 +561,32 @@ export function createRouterDiscoveryPlugin(
515
561
  if ((globalThis as any).__rscRouterDiscoveryActive) return;
516
562
  s.devServer = server;
517
563
 
564
+ (server.environments as any)?.client?.hot?.on?.(
565
+ "vite:client:connect",
566
+ (_payload: unknown, client: any) => {
567
+ if (transitionWhenOverlay) {
568
+ client?.send?.({ type: "error", err: transitionWhenOverlay });
569
+ }
570
+ },
571
+ );
572
+ // The http server's "request" event, not a middleware: plugin-rsc
573
+ // answers page and RSC requests before a middleware added here runs.
574
+ let overlayResendQueued = false;
575
+ server.httpServer?.on("request", (req, res) => {
576
+ // Documents and RSC fetches only (the refetch that follows each
577
+ // "rsc:update"), one send per burst.
578
+ const isPage =
579
+ req.url?.includes("_rsc") === true ||
580
+ req.headers.accept?.includes("text/html") === true;
581
+ if (transitionWhenOverlay && isPage && !overlayResendQueued) {
582
+ overlayResendQueued = true;
583
+ res.once("close", () => {
584
+ overlayResendQueued = false;
585
+ sendTransitionWhenOverlay();
586
+ });
587
+ }
588
+ });
589
+
518
590
  let workerReadyEpoch: number | undefined;
519
591
  const publishDevDiscoveryReady = (epoch: number) => {
520
592
  if (epoch <= (workerReadyEpoch ?? -1)) return;
@@ -860,6 +932,7 @@ export function createRouterDiscoveryPlugin(
860
932
  } else {
861
933
  console.error(report.message);
862
934
  }
935
+ showTransitionWhenError(err);
863
936
  };
864
937
 
865
938
  const discover = async () => {
@@ -1473,9 +1546,7 @@ export function createRouterDiscoveryPlugin(
1473
1546
  const body = JSON.stringify({
1474
1547
  entry: result.entry,
1475
1548
  ttl,
1476
- swr,
1477
1549
  tags: result.tags,
1478
- routeName,
1479
1550
  });
1480
1551
  devPrerenderCache.set(routerInstance, cacheKey, body);
1481
1552
  res.setHeader("content-type", "application/json");
@@ -1619,6 +1690,7 @@ export function createRouterDiscoveryPlugin(
1619
1690
  );
1620
1691
  s.lastDiscoveryError = null;
1621
1692
  }
1693
+ transitionWhenOverlay = null;
1622
1694
  // Cloudflare dev: on a successful cycle drop the workerd runner's
1623
1695
  // cached worker-entry chain so the next request re-evaluates
1624
1696
  // createRouter() with the new routes. Fired here in the work path
@@ -1646,9 +1718,17 @@ export function createRouterDiscoveryPlugin(
1646
1718
  message: err?.message ?? String(err),
1647
1719
  at: Date.now(),
1648
1720
  };
1649
- console.warn(
1650
- `[rango] Runtime re-discovery failed: ${err.message}`,
1651
- );
1721
+ // An invalid transition({ when }) is a definition error the
1722
+ // user must see: terminal error plus the browser's Vite overlay,
1723
+ // not a warning while the last-good route tree keeps serving.
1724
+ const whenError = showTransitionWhenError(err);
1725
+ if (whenError) {
1726
+ console.error(whenError.message);
1727
+ } else {
1728
+ console.warn(
1729
+ `[rango] Runtime re-discovery failed: ${err.message}`,
1730
+ );
1731
+ }
1652
1732
  debugDiscovery?.(
1653
1733
  "hmr: lastDiscoveryError set (%s) — manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
1654
1734
  err?.message,
@@ -1,23 +0,0 @@
1
- import type { MatchResult } from "../types.js";
2
- import type { getRequestContext } from "../server/request-context.js";
3
- import type { OnErrorCallback } from "../types/error-types.js";
4
- /**
5
- * Apply transition({ when }) gates to a payload's segments.
6
- *
7
- * PPR predicates were evaluated from the manifest before cache lookup and route
8
- * handlers; their request-specific decisions are projected onto a copy so they
9
- * never mutate reusable cache/prerender/shell records. Ordinary-route predicates
10
- * were collected during fresh resolution and are evaluated here after handlers.
11
- * Both paths drop the segment transition when the predicate does not hold.
12
- *
13
- * Mutating the segments here is safe: the segment cache stores a serialized copy
14
- * (segment-codec), written during match() BEFORE this gate runs, so dropping a
15
- * transition never corrupts a cache entry. On an ordinary route, a cache hit
16
- * skips resolution, collects no predicate, and replays the cached transition
17
- * as-is (it was serialized before the gate). PPR routes are the exception: their
18
- * manifest predicates were evaluated before lookup and apply to replayed data.
19
- *
20
- * Returns the same array for the ordinary post-handler path. A PPR drop returns a
21
- * copy containing only the request-specific transition changes.
22
- */
23
- export declare function gateTransitions(segments: MatchResult["segments"], ctx: ReturnType<typeof getRequestContext>, onError?: OnErrorCallback): MatchResult["segments"];
@@ -1,86 +0,0 @@
1
- import type { MatchResult } from "../types.js";
2
- import type { getRequestContext } from "../server/request-context.js";
3
- import { invokeOnError } from "../router/error-handling.js";
4
- import type { OnErrorCallback } from "../types/error-types.js";
5
- import { createTransitionWhenContext } from "../router/transition-when.js";
6
-
7
- /**
8
- * Apply transition({ when }) gates to a payload's segments.
9
- *
10
- * PPR predicates were evaluated from the manifest before cache lookup and route
11
- * handlers; their request-specific decisions are projected onto a copy so they
12
- * never mutate reusable cache/prerender/shell records. Ordinary-route predicates
13
- * were collected during fresh resolution and are evaluated here after handlers.
14
- * Both paths drop the segment transition when the predicate does not hold.
15
- *
16
- * Mutating the segments here is safe: the segment cache stores a serialized copy
17
- * (segment-codec), written during match() BEFORE this gate runs, so dropping a
18
- * transition never corrupts a cache entry. On an ordinary route, a cache hit
19
- * skips resolution, collects no predicate, and replays the cached transition
20
- * as-is (it was serialized before the gate). PPR routes are the exception: their
21
- * manifest predicates were evaluated before lookup and apply to replayed data.
22
- *
23
- * Returns the same array for the ordinary post-handler path. A PPR drop returns a
24
- * copy containing only the request-specific transition changes.
25
- */
26
- export function gateTransitions(
27
- segments: MatchResult["segments"],
28
- ctx: ReturnType<typeof getRequestContext>,
29
- onError?: OnErrorCallback,
30
- ): MatchResult["segments"] {
31
- const pprDecisions = ctx._pprTransitionDecisions;
32
- let gatedSegments = segments;
33
-
34
- const dropTransition = (id: string): void => {
35
- const index = gatedSegments.findIndex((segment) => segment.id === id);
36
- if (index === -1) return;
37
- if (!pprDecisions) {
38
- gatedSegments[index].transition = undefined;
39
- return;
40
- }
41
- if (gatedSegments === segments) gatedSegments = [...segments];
42
- gatedSegments[index] = {
43
- ...gatedSegments[index],
44
- transition: undefined,
45
- };
46
- };
47
-
48
- if (pprDecisions) {
49
- for (const [id, keep] of pprDecisions) {
50
- if (!keep) dropTransition(id);
51
- }
52
- }
53
- const predicates = ctx._transitionWhen;
54
- if (predicates) {
55
- for (const { id, when } of predicates) {
56
- try {
57
- // Assemble the ShouldRevalidateFn-shaped predicate context from the
58
- // request context. Source fields (currentUrl/currentParams/fromRouteName)
59
- // were stashed at match time from the navigation snapshot; action fields
60
- // at the action-bearing gate call sites. nextUrl/nextParams/toRouteName/
61
- // method/get/env come straight off ctx (setRequestContextParams ran
62
- // before the gate). Source/action fields are undefined when absent —
63
- // never fabricated (see TransitionWhenContext).
64
- if (when(createTransitionWhenContext(ctx)) !== false) continue;
65
- } catch (error) {
66
- // A throwing predicate must not fail the response: report it and treat
67
- // the transition as gated off (do not hold). invokeOnError no-ops when
68
- // onError is undefined.
69
- invokeOnError(
70
- onError,
71
- error,
72
- "rendering",
73
- {
74
- request: ctx.request,
75
- url: ctx.url,
76
- params: ctx.params,
77
- segmentId: id,
78
- },
79
- "RSC",
80
- );
81
- }
82
- dropTransition(id);
83
- }
84
- }
85
- return gatedSegments;
86
- }