@rangojs/router 0.18.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 (244) hide show
  1. package/dist/types/browser/event-controller.d.ts +3 -3
  2. package/dist/types/browser/history-state.d.ts +2 -0
  3. package/dist/types/browser/navigation-transaction.d.ts +20 -2
  4. package/dist/types/browser/partial-update.d.ts +16 -1
  5. package/dist/types/browser/prefetch/cache.d.ts +6 -6
  6. package/dist/types/browser/react/Link.d.ts +19 -9
  7. package/dist/types/browser/react/context.d.ts +2 -2
  8. package/dist/types/browser/react/location-state-shared.d.ts +95 -56
  9. package/dist/types/browser/react/location-state.d.ts +1 -1
  10. package/dist/types/browser/transition-when.d.ts +80 -0
  11. package/dist/types/browser/types.d.ts +104 -9
  12. package/dist/types/build/generate-manifest.d.ts +8 -0
  13. package/dist/types/cache/background-task.d.ts +24 -2
  14. package/dist/types/cache/cache-exec-scope.d.ts +31 -0
  15. package/dist/types/cache/cache-key-utils.d.ts +44 -13
  16. package/dist/types/cache/cache-policy.d.ts +1 -1
  17. package/dist/types/cache/cache-runtime.d.ts +7 -0
  18. package/dist/types/cache/cache-scope.d.ts +117 -35
  19. package/dist/types/cache/cache-tag.d.ts +24 -4
  20. package/dist/types/cache/cf/cf-cache-store.d.ts +55 -44
  21. package/dist/types/cache/cf/cf-shell-frame.d.ts +1 -1
  22. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +0 -15
  23. package/dist/types/cache/document-cache.d.ts +10 -0
  24. package/dist/types/cache/handle-snapshot.d.ts +40 -8
  25. package/dist/types/cache/invalidation-order.d.ts +23 -0
  26. package/dist/types/cache/request-tag-mask.d.ts +54 -0
  27. package/dist/types/cache/shell-snapshot.d.ts +88 -141
  28. package/dist/types/cache/tag-invalidation.d.ts +38 -14
  29. package/dist/types/cache/types.d.ts +68 -61
  30. package/dist/types/cache/vercel/vercel-cache-store.d.ts +23 -16
  31. package/dist/types/client-urls/navigation.d.ts +28 -2
  32. package/dist/types/client-urls/server-projection.d.ts +5 -2
  33. package/dist/types/client-urls/types.d.ts +5 -5
  34. package/dist/types/client.d.ts +1 -1
  35. package/dist/types/index.d.ts +1 -1
  36. package/dist/types/index.rsc.d.ts +1 -1
  37. package/dist/types/route-definition/helpers-types.d.ts +11 -11
  38. package/dist/types/route-name.d.ts +7 -0
  39. package/dist/types/router/error-handling.d.ts +1 -1
  40. package/dist/types/router/intercept-resolution.d.ts +2 -0
  41. package/dist/types/router/match-context.d.ts +5 -0
  42. package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
  43. package/dist/types/router/router-options.d.ts +4 -1
  44. package/dist/types/router/segment-resolution/loader-cache.d.ts +18 -1
  45. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
  46. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +14 -40
  47. package/dist/types/router/segment-resolution/mask-nested.d.ts +11 -3
  48. package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
  49. package/dist/types/router/transition-when.d.ts +24 -10
  50. package/dist/types/rsc/attach-transition-when.d.ts +18 -0
  51. package/dist/types/rsc/full-payload.d.ts +14 -7
  52. package/dist/types/rsc/response-cache-serve.d.ts +15 -12
  53. package/dist/types/rsc/shell-build-manifest.d.ts +4 -3
  54. package/dist/types/rsc/shell-capture-constants.d.ts +77 -20
  55. package/dist/types/rsc/shell-capture.d.ts +78 -81
  56. package/dist/types/rsc/shell-serve.d.ts +19 -48
  57. package/dist/types/rsc/types.d.ts +2 -0
  58. package/dist/types/segment-system.d.ts +7 -0
  59. package/dist/types/server/context.d.ts +89 -61
  60. package/dist/types/server/cookie-store.d.ts +30 -18
  61. package/dist/types/server/handle-store.d.ts +52 -1
  62. package/dist/types/server/request-context.d.ts +66 -45
  63. package/dist/types/server/request-headers.d.ts +44 -0
  64. package/dist/types/server.d.ts +1 -0
  65. package/dist/types/testing/e2e/index.d.ts +1 -1
  66. package/dist/types/testing/index.d.ts +3 -2
  67. package/dist/types/testing/internal/action-id.d.ts +7 -0
  68. package/dist/types/testing/location-state-key.d.ts +24 -0
  69. package/dist/types/testing/render-route.d.ts +17 -1
  70. package/dist/types/testing/run-transition-when.d.ts +44 -69
  71. package/dist/types/testing/serve-shell-request.d.ts +7 -6
  72. package/dist/types/testing/shell-status.d.ts +34 -22
  73. package/dist/types/transition-when-ref.d.ts +79 -0
  74. package/dist/types/types/cache-types.d.ts +15 -3
  75. package/dist/types/types/index.d.ts +1 -1
  76. package/dist/types/types/segments.d.ts +86 -71
  77. package/dist/types/urls/path-helper-types.d.ts +3 -4
  78. package/dist/types/urls/pattern-types.d.ts +3 -4
  79. package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
  80. package/dist/vite/index.js +960 -97
  81. package/package.json +1 -1
  82. package/skills/cache-guide/SKILL.md +76 -49
  83. package/skills/caching/SKILL.md +167 -69
  84. package/skills/client-urls/SKILL.md +1 -1
  85. package/skills/comparison/references/framework-comparison.md +8 -5
  86. package/skills/document-cache/SKILL.md +24 -0
  87. package/skills/hooks/SKILL.md +3 -1
  88. package/skills/hooks/navigation.md +23 -2
  89. package/skills/hooks/state.md +98 -6
  90. package/skills/intercept/SKILL.md +29 -12
  91. package/skills/loader/SKILL.md +52 -21
  92. package/skills/middleware/SKILL.md +18 -0
  93. package/skills/migrate-nextjs/SKILL.md +3 -3
  94. package/skills/observability/SKILL.md +6 -5
  95. package/skills/parallel/SKILL.md +1 -1
  96. package/skills/ppr/SKILL.md +129 -77
  97. package/skills/prerender/SKILL.md +3 -3
  98. package/skills/rango/SKILL.md +25 -6
  99. package/skills/route/SKILL.md +2 -0
  100. package/skills/testing/SKILL.md +27 -25
  101. package/skills/testing/cache-prerender.md +9 -9
  102. package/skills/testing/client-components.md +45 -3
  103. package/skills/testing/loader.md +3 -2
  104. package/skills/testing/middleware.md +1 -0
  105. package/skills/testing/predicates.md +49 -49
  106. package/skills/testing/render-handler.md +1 -0
  107. package/skills/testing/serve-shell-request.md +14 -0
  108. package/skills/testing/server-actions.md +9 -3
  109. package/skills/theme/SKILL.md +8 -4
  110. package/skills/typesafety/env-and-bindings.md +8 -0
  111. package/skills/use-cache/SKILL.md +64 -19
  112. package/skills/view-transitions/SKILL.md +150 -29
  113. package/src/__augment-tests__/augmented.check.ts +23 -0
  114. package/src/browser/event-controller.ts +4 -4
  115. package/src/browser/history-state.ts +52 -1
  116. package/src/browser/link-interceptor.ts +4 -0
  117. package/src/browser/navigation-bridge.ts +77 -18
  118. package/src/browser/navigation-client.ts +4 -3
  119. package/src/browser/navigation-store.ts +43 -1
  120. package/src/browser/navigation-transaction.ts +31 -11
  121. package/src/browser/partial-update.ts +146 -35
  122. package/src/browser/prefetch/cache.ts +6 -6
  123. package/src/browser/prefetch/fetch.ts +2 -2
  124. package/src/browser/react/Link.tsx +38 -33
  125. package/src/browser/react/NavigationProvider.tsx +2 -2
  126. package/src/browser/react/context.ts +2 -2
  127. package/src/browser/react/location-state-shared.ts +241 -49
  128. package/src/browser/react/location-state.ts +5 -2
  129. package/src/browser/rsc-router.tsx +4 -0
  130. package/src/browser/server-action-bridge.ts +84 -15
  131. package/src/browser/transition-when.ts +205 -0
  132. package/src/browser/types.ts +124 -10
  133. package/src/build/generate-manifest.ts +77 -1
  134. package/src/cache/background-task.ts +55 -2
  135. package/src/cache/cache-exec-scope.ts +48 -1
  136. package/src/cache/cache-key-utils.ts +56 -16
  137. package/src/cache/cache-policy.ts +9 -4
  138. package/src/cache/cache-runtime.ts +197 -144
  139. package/src/cache/cache-scope.ts +304 -112
  140. package/src/cache/cache-tag.ts +105 -13
  141. package/src/cache/cf/cf-cache-store.ts +152 -76
  142. package/src/cache/cf/cf-shell-frame.ts +2 -2
  143. package/src/cache/cf/cf-tag-marker-memo.ts +11 -100
  144. package/src/cache/document-cache.ts +53 -7
  145. package/src/cache/handle-snapshot.ts +52 -9
  146. package/src/cache/invalidation-order.ts +84 -0
  147. package/src/cache/request-tag-mask.ts +147 -0
  148. package/src/cache/shell-snapshot.ts +130 -348
  149. package/src/cache/tag-invalidation.ts +57 -51
  150. package/src/cache/types.ts +71 -67
  151. package/src/cache/vercel/vercel-cache-store.ts +61 -58
  152. package/src/client-urls/client-root.tsx +8 -4
  153. package/src/client-urls/client-urls.ts +8 -6
  154. package/src/client-urls/navigation.ts +55 -4
  155. package/src/client-urls/server-projection.ts +31 -10
  156. package/src/client-urls/types.ts +12 -5
  157. package/src/client.tsx +2 -0
  158. package/src/host/cookie-handler.ts +2 -1
  159. package/src/index.rsc.ts +3 -0
  160. package/src/index.ts +3 -0
  161. package/src/loader-redirect.tsx +7 -3
  162. package/src/prerender/build-shell-capture.ts +155 -146
  163. package/src/route-definition/dsl-helpers.ts +2 -0
  164. package/src/route-definition/helpers-types.ts +11 -11
  165. package/src/route-name.ts +12 -0
  166. package/src/router/content-negotiation.ts +4 -1
  167. package/src/router/error-handling.ts +5 -2
  168. package/src/router/handler-context.ts +10 -7
  169. package/src/router/intercept-resolution.ts +11 -1
  170. package/src/router/loader-resolution.ts +28 -3
  171. package/src/router/logging.ts +5 -3
  172. package/src/router/match-api.ts +62 -34
  173. package/src/router/match-context.ts +5 -0
  174. package/src/router/match-handlers.ts +9 -29
  175. package/src/router/match-middleware/background-revalidation.ts +3 -5
  176. package/src/router/match-middleware/cache-lookup.ts +35 -19
  177. package/src/router/match-middleware/cache-store.ts +15 -9
  178. package/src/router/match-result.ts +1 -0
  179. package/src/router/middleware.ts +2 -5
  180. package/src/router/navigation-snapshot.ts +6 -5
  181. package/src/router/prerender-match.ts +4 -0
  182. package/src/router/request-classification.ts +7 -4
  183. package/src/router/router-options.ts +4 -1
  184. package/src/router/segment-resolution/fresh.ts +0 -4
  185. package/src/router/segment-resolution/loader-cache.ts +150 -25
  186. package/src/router/segment-resolution/loader-mask.ts +3 -4
  187. package/src/router/segment-resolution/loader-snapshot.ts +15 -78
  188. package/src/router/segment-resolution/mask-nested.ts +47 -22
  189. package/src/router/segment-resolution/revalidation.ts +0 -3
  190. package/src/router/segment-resolution/view-transition-default.ts +6 -21
  191. package/src/router/telemetry.ts +6 -3
  192. package/src/router/transition-when.ts +34 -52
  193. package/src/router.ts +2 -1
  194. package/src/rsc/attach-transition-when.ts +47 -0
  195. package/src/rsc/full-payload.ts +30 -10
  196. package/src/rsc/handler.ts +12 -10
  197. package/src/rsc/loader-fetch.ts +2 -1
  198. package/src/rsc/manifest-init.ts +4 -0
  199. package/src/rsc/origin-guard.ts +8 -5
  200. package/src/rsc/progressive-enhancement.ts +7 -30
  201. package/src/rsc/response-cache-serve.ts +68 -80
  202. package/src/rsc/response-route-handler.ts +2 -2
  203. package/src/rsc/rsc-rendering.ts +206 -252
  204. package/src/rsc/server-action.ts +8 -20
  205. package/src/rsc/shell-build-manifest.ts +22 -20
  206. package/src/rsc/shell-capture-constants.ts +136 -20
  207. package/src/rsc/shell-capture.ts +352 -589
  208. package/src/rsc/shell-serve.ts +73 -109
  209. package/src/rsc/ssr-setup.ts +3 -2
  210. package/src/rsc/types.ts +2 -0
  211. package/src/segment-system.tsx +40 -7
  212. package/src/server/context.ts +189 -124
  213. package/src/server/cookie-store.ts +153 -127
  214. package/src/server/handle-store.ts +245 -27
  215. package/src/server/request-context.ts +123 -84
  216. package/src/server/request-headers.ts +134 -0
  217. package/src/server.ts +4 -0
  218. package/src/testing/dispatch.ts +4 -7
  219. package/src/testing/e2e/index.ts +1 -0
  220. package/src/testing/index.ts +5 -0
  221. package/src/testing/internal/action-id.ts +25 -0
  222. package/src/testing/internal/context.ts +1 -1
  223. package/src/testing/location-state-key.ts +45 -0
  224. package/src/testing/render-handler.ts +1 -1
  225. package/src/testing/render-route.tsx +109 -16
  226. package/src/testing/run-client-revalidate.ts +3 -19
  227. package/src/testing/run-loader.ts +5 -1
  228. package/src/testing/run-transition-when.ts +109 -172
  229. package/src/testing/serve-shell-request.ts +10 -7
  230. package/src/testing/shell-status.ts +60 -56
  231. package/src/transition-when-ref.ts +220 -0
  232. package/src/types/cache-types.ts +15 -3
  233. package/src/types/index.ts +3 -0
  234. package/src/types/segments.ts +94 -91
  235. package/src/urls/path-helper-types.ts +3 -4
  236. package/src/urls/pattern-types.ts +3 -4
  237. package/src/vite/discovery/discover-routers.ts +3 -0
  238. package/src/vite/discovery/shell-prerender-phase.ts +0 -2
  239. package/src/vite/discovery/virtual-module-codegen.ts +16 -6
  240. package/src/vite/plugins/transition-when-hoist.ts +1064 -0
  241. package/src/vite/rango.ts +2 -0
  242. package/src/vite/router-discovery.ts +75 -5
  243. package/dist/types/rsc/transition-gate.d.ts +0 -23
  244. package/src/rsc/transition-gate.ts +0 -86
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { ErrorInfo, NotFoundInfo } from "./boundaries.js";
3
- import type { RevalidateParams, HandlerContext } from "./handler-context.js";
3
+ import type { IsActionFn } from "./handler-context.js";
4
+ import type { DefaultRouteName } from "./global-namespace.js";
4
5
 
5
6
  /**
6
7
  * CSS class(es) for a ViewTransition phase.
@@ -10,96 +11,97 @@ import type { RevalidateParams, HandlerContext } from "./handler-context.js";
10
11
  export type ViewTransitionClass = Record<string, string> | string;
11
12
 
12
13
  /**
13
- * The context a transition({ when }) predicate receives.
14
- *
15
- * It mirrors the {@link ShouldRevalidateFn} args a `revalidate()` predicate
16
- * gets — the same navigation/action metadata — so the two read the same shape,
17
- * plus `get`/`env` for request-context reads. There is no full `HandlerContext`
18
- * here: the gate runs at the RSC-payload layer with the request context, not a
19
- * handler context, so handler-only sugar (`search`/`build`/`dev`/`headers`) is
20
- * absent by design. On ordinary routes, `get` can read what handlers or
21
- * middleware set via `ctx.set(...)`. On `ppr` routes the gate runs before route
22
- * handlers, so only middleware-established values are available.
23
- *
24
- * Field availability (all source fields are optional — never fabricated):
25
- * - `currentUrl` / `currentParams` / `fromRouteName` (the navigation SOURCE) are
26
- * populated on soft navigations and action-success revalidations. They are
27
- * undefined on an initial full document load and on action-error / no-JS error
28
- * paths that skip the navigation snapshot — there is no prior page to name.
29
- * - `nextUrl` / `nextParams` / `get` / `env` / `method` are always present;
30
- * `toRouteName` is present only when the target route is named (undefined for
31
- * unnamed/auto-generated routes, like `fromRouteName`).
32
- * - `actionId` / `actionUrl` / `actionResult` / `formData` are populated only
33
- * when a server action triggered the render; `method` is "POST" then, "GET"
34
- * otherwise. On no-JS (progressive-enhancement) action paths `actionId` may be
35
- * undefined when React cannot surface the action's stable id: the success
36
- * re-render still sets `actionUrl`/`formData` for a recognized action, but the
37
- * error-boundary re-render exposes `actionUrl` only when `actionId` resolved.
38
- * Malformed form bodies that fail before action detection expose no action
39
- * fields. Treat `actionId` as "the action, if known", not as "was this an
40
- * action".
41
- *
42
- * PREFETCH / CACHE CAVEAT (read this before gating on the source): the gate runs
43
- * server-side during resolution. A PREFETCHED navigation renders at prefetch
44
- * time, so `currentUrl`/`currentParams`/`fromRouteName` reflect the page the
45
- * prefetch fired from, NOT necessarily the page the user actually navigates from
46
- * — the decision is baked into the stored Flight payload and replayed verbatim.
47
- * A non-PPR `cache()`/prerender hit replays the stored transition with the
48
- * predicate NOT re-run. A `ppr` route instead evaluates the predicate before
49
- * handlers on every match, including cache, prerender, and PPR replay. Prefetch
50
- * still freezes the server decision into its Flight payload. If the gate must
51
- * reflect the exact click-time source, source-scope the prefetch
52
- * (`<Link prefetchKey=":source">`).
14
+ * One side of a navigation as the browser knows it when a
15
+ * `transition({ when })` predicate runs.
16
+ */
17
+ export interface RouteLocation {
18
+ readonly url: URL;
19
+ /** Merged route params of the location. */
20
+ readonly params: Readonly<Record<string, string>>;
21
+ /**
22
+ * The matched route's name (include prefixes applied), typed from the
23
+ * generated route map; undefined for an unnamed route or when unknown.
24
+ * Internal names never appear here.
25
+ */
26
+ readonly routeName: DefaultRouteName | undefined;
27
+ /**
28
+ * `history.state` of this entry at decision time. Read a typed slot with
29
+ * `Def.read(location)` (a `createLocationState()` definition).
30
+ */
31
+ readonly state: unknown;
32
+ }
33
+
34
+ /**
35
+ * A navigation side as the server sees it, for intercept's `when` selector:
36
+ * a {@link RouteLocation} without `state` (history state never reaches the
37
+ * server).
53
38
  */
54
- export type TransitionWhenContext<
55
- TParams = Record<string, string>,
56
- TEnv = unknown,
57
- > = Partial<
58
- Pick<
59
- RevalidateParams<TParams, TEnv>,
60
- "currentUrl" | "currentParams" | "fromRouteName"
61
- >
62
- > &
63
- Pick<
64
- RevalidateParams<TParams, TEnv>,
65
- | "nextUrl"
66
- | "nextParams"
67
- | "toRouteName"
68
- | "actionId"
69
- | "actionUrl"
70
- | "actionResult"
71
- | "formData"
72
- | "method"
73
- > &
74
- Pick<HandlerContext<any, TEnv>, "get" | "env">;
39
+ export type ServerRouteLocation = Omit<RouteLocation, "state">;
75
40
 
76
41
  /**
77
- * Predicate that gates whether a transition() applies for the current request.
42
+ * How the navigation being decided was started.
78
43
  *
79
- * Evaluated server-side outside any cache scope. On ordinary routes it runs
80
- * AFTER the route's handler, so `get(...)` can read handler/middleware state. A
81
- * route with `ppr` automatically hoists it before route handlers and reevaluates
82
- * it on every cache/prerender/PPR replay; there `get(...)` can read middleware
83
- * state, but not values set by route handlers. Return false to drop this
84
- * segment's transition for the request; return true to apply it. The
85
- * context ({@link TransitionWhenContext}) carries the same navigation/action
86
- * metadata a `revalidate()` predicate sees plus `get`/`env`. If it throws, the
87
- * error is reported to the router's onError (phase "rendering") and the
88
- * transition is dropped (the navigation does not hold).
44
+ * - `"push"` / `"replace"`: a Link click, `router.push()` / `router.replace()`
45
+ * or `navigate()`.
46
+ * - `"pop"`: browser back/forward (restored from the history cache or
47
+ * refetched).
48
+ * - `"action"`: the commit that applies a server action's revalidation,
49
+ * including the error-boundary commit of a failed action.
50
+ * - `"revalidate"`: a re-render of the current URL: `router.refresh()`,
51
+ * cross-tab invalidation, or the background revalidation of a stale entry.
52
+ */
53
+ export type TransitionWhenKind =
54
+ | "push"
55
+ | "replace"
56
+ | "pop"
57
+ | "action"
58
+ | "revalidate";
59
+
60
+ /**
61
+ * The context a `transition({ when })` predicate receives. The predicate runs
62
+ * in the BROWSER, once per navigation, at the first commit that presents the
63
+ * destination. The server never calls it.
89
64
  *
90
- * Distinct from intercept()'s `when` config selector, which runs at MATCH time
91
- * over `{ from, to, params, segments, … }`.
65
+ * - `from`: the committed location being left.
66
+ * - `to`: the destination. The same object as `from` for `"action"` and
67
+ * `"revalidate"`.
68
+ * - `isAction`: the matcher `revalidate()` predicates get; `false` off an
69
+ * action.
70
+ * - `action`: present only for `kind: "action"`.
71
+ */
72
+ export interface TransitionWhenContext {
73
+ readonly kind: TransitionWhenKind;
74
+ readonly from: RouteLocation;
75
+ readonly to: RouteLocation;
76
+ readonly isAction: IsActionFn;
77
+ /** Present only for `kind: "action"`. */
78
+ readonly action?: {
79
+ /** The action's hashed `$$id` in the browser; match with `isAction(fn)` instead. */
80
+ readonly id: string | undefined;
81
+ /** The FormData argument the action received (the 2nd argument under `useActionState`). */
82
+ readonly formData: FormData | undefined;
83
+ /** The action's return value on success. */
84
+ readonly result: unknown;
85
+ /** What a failed action threw (its error-boundary commit); `result` is undefined then. */
86
+ readonly error: unknown;
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Browser-run predicate that gates whether a navigation holds and animates.
92
92
  *
93
- * Scope: dropping a transition removes only THIS segment's contribution to the
94
- * navigation's hold. The startTransition hold is navigation-wide — it engages if
95
- * any matched segment still has a transition — so `when: false` makes the
96
- * navigation stream its loading fallback only when no other matched segment
97
- * keeps a transition (the common case: a single transition on the route).
93
+ * In `urls()` write it inline (`transition({ when: (ctx) => ... })`, which
94
+ * the build hoists into a client module; it may reference only its own
95
+ * bindings, globals and client-safe imports) or export it from a
96
+ * `"use client"` module and import it; in `clientUrls()` it is an inline
97
+ * function. Anything else (a server function, a non-function) fails route
98
+ * discovery.
98
99
  *
99
- * On non-PPR routes it runs only during fresh resolution. On PPR routes it runs
100
- * before handlers for every match, including runtime cache, build-time
101
- * prerender, and PPR segment replay. A prefetched navigation still freezes the
102
- * result to prefetch time; see {@link TransitionWhenContext}.
100
+ * `false` makes the navigation an urgent commit: no hold, no view transition,
101
+ * and a same-route navigation streams its `loading()` fallback. The segment
102
+ * keeps its key and its `<ViewTransition>` element (every class "none"), so
103
+ * nothing remounts. One predicate returning false decides for the whole
104
+ * navigation. A throw is logged with `console.error` and counts as `false`.
103
105
  */
104
106
  export type TransitionWhenFn = (ctx: TransitionWhenContext) => boolean;
105
107
 
@@ -132,13 +134,8 @@ export interface TransitionConfig {
132
134
  */
133
135
  viewTransition?: "auto" | false;
134
136
  /**
135
- * Optional server-side predicate that gates this transition per request. When
136
- * present and it returns false, the router drops this segment's transition for
137
- * the request, so the navigation streams its loading fallback instead of
138
- * holding. PPR routes evaluate it before route handlers and on every replay;
139
- * other routes evaluate it after handlers on fresh resolution. The predicate
140
- * is server-only and never serialized to the client; only its resolved effect
141
- * crosses. See {@link TransitionWhenFn}.
137
+ * Optional browser-run predicate that gates this transition per
138
+ * navigation. See {@link TransitionWhenFn}.
142
139
  */
143
140
  when?: TransitionWhenFn;
144
141
  }
@@ -285,6 +282,12 @@ export interface MatchResult {
285
282
  * decline its optimistic presentation for targets an intercept would claim.
286
283
  */
287
284
  interceptTargets?: string[];
285
+ /**
286
+ * Set on a partial match when an intercept targets the matched route,
287
+ * whether or not it applied from this source. The response depends on the
288
+ * source, so the RSC handler scopes its prefetch entry to it (#1007).
289
+ */
290
+ interceptTargeted?: true;
288
291
  /**
289
292
  * Redirect URL for trailing slash normalization.
290
293
  * When set, the RSC handler should return a 308 redirect to this URL
@@ -417,10 +417,9 @@ export type PathHelpers<TEnv> = {
417
417
  * transition cannot fire without a startTransition. See
418
418
  * skills/view-transitions for the startTransition x ViewTransition matrix.
419
419
  *
420
- * Pass `when: (ctx) => boolean` to gate the transition per request. It normally
421
- * runs after the route handler; `ppr` routes automatically run it before route
422
- * handlers and on every replay, where `ctx.get(...)` sees middleware state but
423
- * not handler-set values.
420
+ * Pass `when` (inline, hoisted into a client module by the build, or a
421
+ * "use client" export) to gate the navigation's hold and view transition in
422
+ * the browser (never on the server); see TransitionWhenFn.
424
423
  */
425
424
  transition: {
426
425
  (): TransitionItem;
@@ -65,10 +65,9 @@ export interface PartialPrerenderProps {
65
65
  tags?: string[];
66
66
  /**
67
67
  * Upper bound (serialized UTF-8 bytes) on the loader pins in the capture
68
- * data snapshot: the loader records and the cache values loaders read,
69
- * duplicated into the shell entry. The doc record (the handler layer every
70
- * HIT replays) is exempt. Over the cap the pins are dropped: the shell is
71
- * still stored and every HIT still replays the handler layer, but the
68
+ * data snapshot: the bake-lane loader records. The doc record (the handler
69
+ * layer every HIT replays) is exempt. Over the cap the pins are dropped: the
70
+ * shell is still stored and every HIT still replays the handler layer, but the
72
71
  * pinned loaders read the live store, so drifted cached content can
73
72
  * hydration-mismatch and be repaired client-side. Reported once per key.
74
73
  * Defaults to 8 MiB. The whole entry is bounded separately by the store's
@@ -211,6 +211,9 @@ export async function discoverRouters(
211
211
  routerId: id,
212
212
  ...(router.__basename ? { urlPrefix: router.__basename } : {}),
213
213
  ...(collectClientFallbackRef ? { collectClientFallbackRef } : {}),
214
+ // Discovery evaluates the tree in the react-server graph, where a
215
+ // "use client" import is a client reference: reject server `when`s.
216
+ validateTransitionWhen: true,
214
217
  }),
215
218
  );
216
219
  routerMountIndex++;
@@ -290,9 +290,7 @@ export async function runShellPrerenderPhase(
290
290
  const value: BuildShellEntry = {
291
291
  entry: res.entry,
292
292
  ttl: policy.ttl,
293
- swr: policy.swr,
294
293
  tags: res.tags,
295
- routeName: cand.routeName,
296
294
  };
297
295
  staged.push({
298
296
  key: buildShellManifestKey(cand.urlPath),
@@ -24,6 +24,14 @@ import type { DiscoveryState } from "./state.js";
24
24
  */
25
25
  const MANIFEST_EXTERNALIZE_THRESHOLD = 512 * 1024;
26
26
 
27
+ /**
28
+ * Strict transition({ when }) validation for the app's RSC realm: under the
29
+ * plugin a "use client" import is a client reference, so the render-time
30
+ * backstop (rsc/attach-transition-when.ts) can reject a server function. Off
31
+ * by default in the router, where unit-test projects cannot tell them apart.
32
+ */
33
+ const TRANSITION_WHEN_VALIDATION = `enableTransitionWhenValidation();`;
34
+
27
35
  function devDiscoveryBootstrap(state: DiscoveryState): string[] {
28
36
  if (
29
37
  state.isBuildMode ||
@@ -80,6 +88,7 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
80
88
  }
81
89
 
82
90
  const serverImports = [
91
+ "enableTransitionWhenValidation",
83
92
  "setCachedManifest",
84
93
  "setRouterManifest",
85
94
  ...(state.isBuildMode ? ["registerRouterManifestLoader"] : []),
@@ -97,6 +106,7 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
97
106
  // because it's not in the HMR invalidation chain. Without this clear, the
98
107
  // handler finds stale trie data and never rebuilds from updated urlpatterns.
99
108
  `clearAllRouterData();`,
109
+ TRANSITION_WHEN_VALIDATION,
100
110
  ];
101
111
 
102
112
  if (hasClientUrlModules) {
@@ -182,12 +192,12 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
182
192
  return lines.join("\n");
183
193
  }
184
194
 
185
- const lines: string[] = [];
195
+ const lines: string[] = [
196
+ `import { ${hasClientUrlModules ? "clearClientUrlProjections, " : ""}enableTransitionWhenValidation } from "@rangojs/router/server";`,
197
+ TRANSITION_WHEN_VALIDATION,
198
+ ];
186
199
  if (hasClientUrlModules) {
187
- lines.push(
188
- `import { clearClientUrlProjections } from "@rangojs/router/server";`,
189
- `clearClientUrlProjections();`,
190
- );
200
+ lines.push(`clearClientUrlProjections();`);
191
201
  }
192
202
  if (!state.isBuildMode) {
193
203
  const origin =
@@ -201,7 +211,7 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
201
211
  }
202
212
  }
203
213
  lines.push(...devDiscoveryBootstrap(state));
204
- return lines.join("\n") || `// Route manifest will be populated at runtime`;
214
+ return lines.join("\n");
205
215
  }
206
216
 
207
217
  /**