@rangojs/router 0.27.0 → 0.29.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 (243) hide show
  1. package/dist/bin/rango.js +1 -1
  2. package/dist/types/__internal.d.ts +7 -1
  3. package/dist/types/browser/action-fence.d.ts +2 -1
  4. package/dist/types/browser/event-controller.d.ts +8 -2
  5. package/dist/types/browser/history-state.d.ts +3 -9
  6. package/dist/types/browser/navigation-store.d.ts +8 -6
  7. package/dist/types/browser/partial-update.d.ts +11 -0
  8. package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
  9. package/dist/types/browser/react/use-action.d.ts +7 -2
  10. package/dist/types/browser/react/use-handle.d.ts +19 -16
  11. package/dist/types/browser/react/use-link-status.d.ts +5 -2
  12. package/dist/types/browser/segment-reconciler.d.ts +32 -4
  13. package/dist/types/browser/types.d.ts +24 -5
  14. package/dist/types/browser/wire-protocol.d.ts +26 -0
  15. package/dist/types/cache/cache-key-utils.d.ts +11 -5
  16. package/dist/types/cache/cache-scope.d.ts +34 -22
  17. package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
  18. package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
  19. package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
  20. package/dist/types/cache/handle-snapshot.d.ts +9 -4
  21. package/dist/types/cache/segment-codec.d.ts +14 -0
  22. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  23. package/dist/types/cache/taint.d.ts +5 -3
  24. package/dist/types/cache/types.d.ts +7 -3
  25. package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
  26. package/dist/types/prefetch-markers.d.ts +5 -14
  27. package/dist/types/prerender/store.d.ts +31 -0
  28. package/dist/types/prerender/warm-request.d.ts +3 -3
  29. package/dist/types/prerender.d.ts +2 -2
  30. package/dist/types/route-name.d.ts +5 -0
  31. package/dist/types/router/error-handling.d.ts +11 -5
  32. package/dist/types/router/instrument.d.ts +4 -3
  33. package/dist/types/router/intercept-resolution.d.ts +25 -9
  34. package/dist/types/router/match-context.d.ts +6 -11
  35. package/dist/types/router/match-handlers.d.ts +2 -6
  36. package/dist/types/router/match-middleware/background-revalidation.d.ts +13 -22
  37. package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
  38. package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
  39. package/dist/types/router/navigation-snapshot.d.ts +7 -0
  40. package/dist/types/router/prerender-match.d.ts +21 -6
  41. package/dist/types/router/preview-match.d.ts +2 -7
  42. package/dist/types/router/request-classification.d.ts +5 -0
  43. package/dist/types/router/router-context.d.ts +7 -46
  44. package/dist/types/router/router-interfaces.d.ts +8 -14
  45. package/dist/types/router/segment-resolution/helpers.d.ts +19 -3
  46. package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
  47. package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
  48. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
  49. package/dist/types/router/segment-resolution/resolution-pass.d.ts +95 -0
  50. package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
  51. package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +2 -0
  52. package/dist/types/router/segment-resolution.d.ts +1 -2
  53. package/dist/types/router/segment-wrappers.d.ts +11 -48
  54. package/dist/types/router/telemetry.d.ts +2 -0
  55. package/dist/types/router/types.d.ts +11 -1
  56. package/dist/types/rsc/full-payload.d.ts +2 -2
  57. package/dist/types/rsc/handler-context.d.ts +6 -6
  58. package/dist/types/rsc/json-route-result.d.ts +5 -9
  59. package/dist/types/rsc/request-stages.d.ts +203 -0
  60. package/dist/types/rsc/response-cache-serve.d.ts +7 -12
  61. package/dist/types/rsc/response-route-handler.d.ts +2 -2
  62. package/dist/types/rsc/routine-plan.d.ts +1 -1
  63. package/dist/types/rsc/server-action.d.ts +2 -2
  64. package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
  65. package/dist/types/rsc/shell-capture.d.ts +132 -15
  66. package/dist/types/rsc/shell-serve.d.ts +37 -12
  67. package/dist/types/server/context.d.ts +9 -8
  68. package/dist/types/server/handle-store.d.ts +16 -0
  69. package/dist/types/server/render-pass.d.ts +72 -0
  70. package/dist/types/server/request-context.d.ts +53 -104
  71. package/dist/types/server/rewrite-trail.d.ts +2 -2
  72. package/dist/types/testing/dispatch.d.ts +35 -18
  73. package/dist/types/testing/render-route.d.ts +43 -8
  74. package/dist/types/testing/serve-shell-request.d.ts +8 -1
  75. package/dist/types/types/cache-types.d.ts +6 -3
  76. package/dist/types/types/error-types.d.ts +30 -3
  77. package/dist/types/types/handler-context.d.ts +9 -1
  78. package/dist/types/types/segments.d.ts +1 -1
  79. package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
  80. package/dist/types/vite/discovery/build-env.d.ts +22 -0
  81. package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
  82. package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
  83. package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
  84. package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
  85. package/dist/types/vite/discovery/state.d.ts +12 -0
  86. package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
  87. package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
  88. package/dist/types/vite/router-discovery.d.ts +8 -47
  89. package/dist/types/vite/temp-rsc-server.d.ts +39 -0
  90. package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
  91. package/dist/types/wire-params.d.ts +39 -0
  92. package/dist/vite/index.js +3822 -3727
  93. package/package.json +1 -1
  94. package/skills/cache-guide/SKILL.md +8 -5
  95. package/skills/caching/SKILL.md +37 -18
  96. package/skills/client-urls/SKILL.md +4 -2
  97. package/skills/document-cache/SKILL.md +13 -1
  98. package/skills/handler-use/SKILL.md +1 -1
  99. package/skills/hooks/SKILL.md +1 -1
  100. package/skills/hooks/data.md +8 -1
  101. package/skills/hooks/handle-and-actions.md +33 -2
  102. package/skills/hooks/navigation.md +121 -15
  103. package/skills/hooks/state.md +6 -4
  104. package/skills/hooks/urls.md +16 -5
  105. package/skills/intercept/SKILL.md +23 -7
  106. package/skills/middleware/SKILL.md +18 -0
  107. package/skills/observability/SKILL.md +30 -0
  108. package/skills/ppr/SKILL.md +18 -3
  109. package/skills/prerender/SKILL.md +39 -15
  110. package/skills/rango/SKILL.md +5 -1
  111. package/skills/server-actions/SKILL.md +15 -1
  112. package/skills/testing/client-components.md +25 -18
  113. package/skills/testing/response-routes.md +6 -4
  114. package/skills/testing/serve-shell-request.md +7 -7
  115. package/skills/use-cache/SKILL.md +46 -8
  116. package/skills/view-transitions/SKILL.md +1 -1
  117. package/src/__internal.ts +7 -1
  118. package/src/browser/action-fence.ts +2 -1
  119. package/src/browser/connection-warmup.ts +3 -1
  120. package/src/browser/event-controller.ts +37 -13
  121. package/src/browser/history-state.ts +6 -12
  122. package/src/browser/navigation-bridge.ts +59 -26
  123. package/src/browser/navigation-client.ts +20 -25
  124. package/src/browser/navigation-store.ts +25 -27
  125. package/src/browser/navigation-transaction.ts +4 -1
  126. package/src/browser/network-error-handler.ts +4 -0
  127. package/src/browser/partial-update.ts +33 -6
  128. package/src/browser/prefetch/cache.ts +2 -1
  129. package/src/browser/prefetch/fetch.ts +8 -16
  130. package/src/browser/prefetch/queue.ts +4 -4
  131. package/src/browser/react/NavigationProvider.tsx +2 -1
  132. package/src/browser/react/filter-segment-order.ts +2 -2
  133. package/src/browser/react/use-action.ts +24 -48
  134. package/src/browser/react/use-handle.ts +22 -18
  135. package/src/browser/react/use-link-status.ts +48 -60
  136. package/src/browser/react/use-navigation.ts +92 -41
  137. package/src/browser/rsc-router.tsx +1 -0
  138. package/src/browser/segment-reconciler.ts +109 -53
  139. package/src/browser/server-action-bridge.ts +81 -61
  140. package/src/browser/types.ts +25 -5
  141. package/src/browser/wire-protocol.ts +43 -0
  142. package/src/cache/cache-key-utils.ts +11 -5
  143. package/src/cache/cache-runtime.ts +132 -75
  144. package/src/cache/cache-scope.ts +110 -64
  145. package/src/cache/cf/cf-cache-constants.ts +2 -2
  146. package/src/cache/cf/cf-cache-store.ts +486 -874
  147. package/src/cache/cf/cf-kv-utils.ts +1 -1
  148. package/src/cache/document-cache.ts +64 -46
  149. package/src/cache/handle-snapshot.ts +19 -7
  150. package/src/cache/read-through-swr.ts +20 -18
  151. package/src/cache/segment-codec.ts +55 -0
  152. package/src/cache/shell-snapshot.ts +2 -2
  153. package/src/cache/tag-invalidation.ts +6 -2
  154. package/src/cache/taint.ts +5 -3
  155. package/src/cache/types.ts +7 -3
  156. package/src/cache/vercel/vercel-cache-store.ts +243 -310
  157. package/src/handles/pushed-by.ts +1 -1
  158. package/src/prefetch-markers.ts +5 -16
  159. package/src/prerender/store.ts +76 -0
  160. package/src/prerender/warm-request.ts +8 -4
  161. package/src/prerender.ts +2 -2
  162. package/src/route-name.ts +8 -0
  163. package/src/router/error-handling.ts +22 -10
  164. package/src/router/instrument.ts +4 -3
  165. package/src/router/intercept-resolution.ts +82 -75
  166. package/src/router/loader-resolution.ts +5 -4
  167. package/src/router/match-api.ts +5 -5
  168. package/src/router/match-context.ts +23 -12
  169. package/src/router/match-handlers.ts +8 -20
  170. package/src/router/match-middleware/background-revalidation.ts +46 -57
  171. package/src/router/match-middleware/cache-lookup.ts +677 -726
  172. package/src/router/match-middleware/cache-store.ts +4 -8
  173. package/src/router/match-middleware/intercept-resolution.ts +3 -23
  174. package/src/router/match-middleware/segment-resolution.ts +34 -61
  175. package/src/router/middleware.ts +69 -11
  176. package/src/router/navigation-snapshot.ts +14 -4
  177. package/src/router/prerender-match.ts +100 -44
  178. package/src/router/preview-match.ts +6 -41
  179. package/src/router/request-classification.ts +13 -7
  180. package/src/router/route-snapshot.ts +2 -5
  181. package/src/router/router-context.ts +10 -95
  182. package/src/router/router-interfaces.ts +8 -14
  183. package/src/router/segment-resolution/helpers.ts +49 -13
  184. package/src/router/segment-resolution/loader-cache.ts +15 -9
  185. package/src/router/segment-resolution/loader-mask.ts +5 -5
  186. package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
  187. package/src/router/segment-resolution/resolution-pass.ts +139 -0
  188. package/src/router/segment-resolution/revalidation.ts +939 -789
  189. package/src/router/segment-resolution/streamed-handler-boundary.ts +3 -0
  190. package/src/router/segment-resolution.ts +4 -13
  191. package/src/router/segment-wrappers.ts +51 -269
  192. package/src/router/telemetry.ts +5 -0
  193. package/src/router/types.ts +11 -1
  194. package/src/router.ts +19 -17
  195. package/src/rsc/full-payload.ts +6 -5
  196. package/src/rsc/handler-context.ts +8 -14
  197. package/src/rsc/handler.ts +126 -507
  198. package/src/rsc/json-route-result.ts +5 -9
  199. package/src/rsc/loader-fetch.ts +6 -5
  200. package/src/rsc/progressive-enhancement.ts +5 -0
  201. package/src/rsc/request-stages.ts +759 -0
  202. package/src/rsc/response-cache-serve.ts +10 -14
  203. package/src/rsc/response-route-handler.ts +13 -5
  204. package/src/rsc/rewrite-passes.ts +2 -1
  205. package/src/rsc/routine-plan.ts +1 -1
  206. package/src/rsc/rsc-rendering.ts +164 -349
  207. package/src/rsc/server-action.ts +87 -113
  208. package/src/rsc/shell-capture-constants.ts +1 -1
  209. package/src/rsc/shell-capture.ts +275 -227
  210. package/src/rsc/shell-serve.ts +121 -18
  211. package/src/rsc/ssr-setup.ts +5 -4
  212. package/src/segment-system.tsx +3 -3
  213. package/src/server/context.ts +22 -25
  214. package/src/server/handle-store.ts +55 -0
  215. package/src/server/render-pass.ts +291 -0
  216. package/src/server/request-context.ts +75 -115
  217. package/src/server/rewrite-trail.ts +6 -4
  218. package/src/ssr/index.tsx +1 -1
  219. package/src/testing/dispatch.ts +226 -710
  220. package/src/testing/e2e/page-helpers.ts +2 -2
  221. package/src/testing/render-route.tsx +199 -13
  222. package/src/testing/serve-shell-request.ts +36 -40
  223. package/src/types/cache-types.ts +6 -3
  224. package/src/types/error-types.ts +30 -3
  225. package/src/types/handler-context.ts +12 -1
  226. package/src/types/segments.ts +1 -1
  227. package/src/vite/discovery/build-discovery-phase.ts +204 -0
  228. package/src/vite/discovery/build-env.ts +148 -0
  229. package/src/vite/discovery/bundle-scan-phase.ts +128 -0
  230. package/src/vite/discovery/dev-prerender-cache.ts +8 -3
  231. package/src/vite/discovery/dev-server-phase.ts +1776 -0
  232. package/src/vite/discovery/discover-routers.ts +1 -1
  233. package/src/vite/discovery/discovery-errors.ts +1 -1
  234. package/src/vite/discovery/prerender-collection.ts +24 -39
  235. package/src/vite/discovery/state.ts +15 -0
  236. package/src/vite/plugins/version-plugin.ts +1 -1
  237. package/src/vite/plugins/virtual-entries.ts +1 -1
  238. package/src/vite/router-discovery.ts +29 -2428
  239. package/src/vite/temp-rsc-server.ts +223 -0
  240. package/src/vite/utils/prerender-utils.ts +47 -0
  241. package/src/wire-params.ts +40 -0
  242. package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
  243. package/src/router/segment-resolution/fresh.ts +0 -945
@@ -44,6 +44,8 @@ export interface StreamedHandlerOptions<TEnv> {
44
44
  context: HandlerContext<any, TEnv>;
45
45
  routeKey?: string;
46
46
  params: Record<string, string>;
47
+ /** onError's `isPartial`, as the walk reports a sync handler's error. */
48
+ isPartial: true | undefined;
47
49
  /** False where the rejection must reach the caller (prerender, intercept background re-render). */
48
50
  recover: boolean;
49
51
  }
@@ -64,6 +66,7 @@ export function trackStreamedHandler<TEnv>(
64
66
  const tracked = deps.trackHandler(result as Promise<ReactNode>, {
65
67
  segmentId,
66
68
  segmentType,
69
+ isPartial: options.isPartial,
67
70
  });
68
71
  observeStreamedHandler(
69
72
  tracked,
@@ -5,20 +5,11 @@ export {
5
5
  buildLoaderErrorContext,
6
6
  } from "./segment-resolution/helpers.js";
7
7
  export {
8
- resolveLoaders,
9
- type ResolveSegmentOptions,
8
+ resolveLoadersOnly,
9
+ buildEntryRevalidateMap,
10
+ resolveParallelSegments,
11
+ resolveEntryHandler,
10
12
  resolveSegment,
11
13
  resolveOrphanLayout,
12
- resolveParallelEntry,
13
14
  resolveAllSegments,
14
- resolveLoadersOnly,
15
- } from "./segment-resolution/fresh.js";
16
- export {
17
- resolveLoadersOnlyWithRevalidation,
18
- buildEntryRevalidateMap,
19
- resolveParallelSegmentsWithRevalidation,
20
- resolveEntryHandlerWithRevalidation,
21
- resolveSegmentWithRevalidation,
22
- resolveOrphanLayoutWithRevalidation,
23
- resolveAllSegmentsWithRevalidation,
24
15
  } from "./segment-resolution/revalidation.js";
@@ -1,19 +1,14 @@
1
- import type { EntryData, InterceptEntry } from "../server/context";
2
- import type {
3
- HandlerContext,
4
- ResolvedSegment,
5
- ShouldRevalidateFn,
6
- } from "../types";
7
1
  import type { SegmentResolutionDeps } from "./types.js";
8
- import type { ResolveSegmentOptions } from "./segment-resolution.js";
9
- import type { RevalidationContext } from "./router-context.js";
2
+ import type { RouterContext } from "./router-context.js";
3
+ import type {
4
+ ResolutionPass,
5
+ ResolutionPassInput,
6
+ } from "./segment-resolution/resolution-pass.js";
10
7
 
11
8
  import {
12
- resolveAllSegments as _resolveAllSegments,
13
9
  resolveLoadersOnly as _resolveLoadersOnly,
14
- resolveLoadersOnlyWithRevalidation as _resolveLoadersOnlyWithRevalidation,
15
10
  buildEntryRevalidateMap as _buildEntryRevalidateMap,
16
- resolveAllSegmentsWithRevalidation as _resolveAllSegmentsWithRevalidation,
11
+ resolveAllSegments as _resolveAllSegments,
17
12
  } from "./segment-resolution.js";
18
13
 
19
14
  import {
@@ -22,270 +17,57 @@ import {
22
17
  resolveInterceptLoadersOnly as _resolveInterceptLoadersOnly,
23
18
  } from "./intercept-resolution.js";
24
19
 
25
- import type { InterceptSelectorContext } from "../server/context";
26
-
27
- export interface SegmentWrappers<TEnv = any> {
28
- resolveAllSegments: (
29
- entries: EntryData[],
30
- routeKey: string,
31
- params: Record<string, string>,
32
- context: HandlerContext<any, TEnv>,
33
- loaderPromises: Map<string, Promise<any>>,
34
- options?: ResolveSegmentOptions,
35
- ) => Promise<ResolvedSegment[]>;
36
- resolveLoadersOnly: (
37
- entries: EntryData[],
38
- context: HandlerContext<any, TEnv>,
39
- ) => Promise<ResolvedSegment[]>;
40
- resolveLoadersOnlyWithRevalidation: (
41
- entries: EntryData[],
42
- context: HandlerContext<any, TEnv>,
43
- clientSegmentIds: Set<string>,
44
- prevParams: Record<string, string>,
45
- request: Request,
46
- prevUrl: URL,
47
- nextUrl: URL,
48
- routeKey: string,
49
- actionContext?: {
50
- actionId?: string;
51
- actionUrl?: URL;
52
- actionResult?: any;
53
- formData?: FormData;
54
- },
55
- stale?: boolean,
56
- ) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
57
- buildEntryRevalidateMap: (
58
- entries: EntryData[],
59
- ) => Map<
60
- string,
61
- { entry: EntryData; revalidate: ShouldRevalidateFn<any, any>[] }
62
- >;
63
- resolveAllSegmentsWithRevalidation: (
64
- entries: EntryData[],
65
- routeKey: string,
66
- params: Record<string, string>,
67
- context: HandlerContext<any, TEnv>,
68
- clientSegmentSet: Set<string>,
69
- prevParams: Record<string, string>,
70
- request: Request,
71
- prevUrl: URL,
72
- nextUrl: URL,
73
- actionContext:
74
- | {
75
- actionId?: string;
76
- actionUrl?: URL;
77
- actionResult?: any;
78
- formData?: FormData;
79
- }
80
- | undefined,
81
- interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
82
- localRouteName: string,
83
- pathname: string,
84
- stale?: boolean,
85
- chain?: readonly EntryData[],
86
- ) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
87
- findInterceptForRoute: (
88
- targetRouteKey: string,
89
- fromEntry: EntryData | null,
90
- selectorContext?: InterceptSelectorContext | null,
91
- isAction?: boolean,
92
- ) => { intercept: InterceptEntry; entry: EntryData } | null;
93
- resolveInterceptEntry: (
94
- interceptEntry: InterceptEntry,
95
- parentEntry: EntryData,
96
- params: Record<string, string>,
97
- context: HandlerContext<any, TEnv>,
98
- belongsToRoute?: boolean,
99
- revalidationContext?: any,
100
- options?: { background?: boolean },
101
- ) => Promise<ResolvedSegment[]>;
102
- resolveInterceptLoadersOnly: (
103
- interceptEntry: InterceptEntry,
104
- parentEntry: EntryData,
105
- context: HandlerContext<any, TEnv>,
106
- belongsToRoute: boolean,
107
- revalidationContext: RevalidationContext,
108
- ) => Promise<ResolvedSegment[]>;
109
- }
20
+ /** The resolvers RouterContext exposes, with the router's deps bound. */
21
+ export type SegmentWrappers<TEnv = any> = Pick<
22
+ RouterContext<TEnv>,
23
+ "resolveAllSegments" | "resolveInterceptEntry"
24
+ > &
25
+ Required<
26
+ Pick<
27
+ RouterContext<TEnv>,
28
+ | "resolveLoadersOnly"
29
+ | "buildEntryRevalidateMap"
30
+ | "resolveInterceptLoadersOnly"
31
+ >
32
+ > & {
33
+ /** Its own signature: a null selector context, isAction defaulting to false. */
34
+ findInterceptForRoute: typeof _findInterceptForRoute;
35
+ };
110
36
 
111
37
  /**
112
- * Create thin wrapper functions that bind segmentDeps to extracted
113
- * segment resolution and intercept resolution functions.
114
- *
115
- * These maintain the same signatures as the original inline functions
116
- * so that RouterContext and call sites don't need to change.
38
+ * Bind the router's segment deps into the extracted segment and intercept
39
+ * resolvers. Each gets a ResolutionPass: the caller's request-side input with
40
+ * the deps added here, once per call.
117
41
  */
118
42
  export function createSegmentWrappers<TEnv = any>(
119
- segmentDeps: SegmentResolutionDeps<TEnv>,
43
+ deps: SegmentResolutionDeps<TEnv>,
120
44
  ): SegmentWrappers<TEnv> {
121
- function resolveAllSegments(
122
- entries: EntryData[],
123
- routeKey: string,
124
- params: Record<string, string>,
125
- context: HandlerContext<any, TEnv>,
126
- loaderPromises: Map<string, Promise<any>>,
127
- options?: ResolveSegmentOptions,
128
- ): ReturnType<typeof _resolveAllSegments> {
129
- return _resolveAllSegments(
130
- entries,
131
- routeKey,
132
- params,
133
- context,
134
- loaderPromises,
135
- segmentDeps,
136
- options,
137
- );
138
- }
139
-
140
- function resolveLoadersOnly(
141
- entries: EntryData[],
142
- context: HandlerContext<any, TEnv>,
143
- ): ReturnType<typeof _resolveLoadersOnly> {
144
- return _resolveLoadersOnly(entries, context, segmentDeps);
145
- }
146
-
147
- function resolveLoadersOnlyWithRevalidation(
148
- entries: EntryData[],
149
- context: HandlerContext<any, TEnv>,
150
- clientSegmentIds: Set<string>,
151
- prevParams: Record<string, string>,
152
- request: Request,
153
- prevUrl: URL,
154
- nextUrl: URL,
155
- routeKey: string,
156
- actionContext?: {
157
- actionId?: string;
158
- actionUrl?: URL;
159
- actionResult?: any;
160
- formData?: FormData;
161
- },
162
- stale?: boolean,
163
- ): ReturnType<typeof _resolveLoadersOnlyWithRevalidation> {
164
- return _resolveLoadersOnlyWithRevalidation(
165
- entries,
166
- context,
167
- clientSegmentIds,
168
- prevParams,
169
- request,
170
- prevUrl,
171
- nextUrl,
172
- routeKey,
173
- segmentDeps,
174
- actionContext,
175
- stale,
176
- );
177
- }
178
-
179
- function buildEntryRevalidateMap(
180
- entries: EntryData[],
181
- ): ReturnType<typeof _buildEntryRevalidateMap> {
182
- return _buildEntryRevalidateMap(entries);
183
- }
184
-
185
- function resolveAllSegmentsWithRevalidation(
186
- entries: EntryData[],
187
- routeKey: string,
188
- params: Record<string, string>,
189
- context: HandlerContext<any, TEnv>,
190
- clientSegmentSet: Set<string>,
191
- prevParams: Record<string, string>,
192
- request: Request,
193
- prevUrl: URL,
194
- nextUrl: URL,
195
- actionContext:
196
- | {
197
- actionId?: string;
198
- actionUrl?: URL;
199
- actionResult?: any;
200
- formData?: FormData;
201
- }
202
- | undefined,
203
- interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
204
- localRouteName: string,
205
- pathname: string,
206
- stale?: boolean,
207
- chain?: readonly EntryData[],
208
- ): ReturnType<typeof _resolveAllSegmentsWithRevalidation> {
209
- return _resolveAllSegmentsWithRevalidation(
210
- entries,
211
- routeKey,
212
- params,
213
- context,
214
- clientSegmentSet,
215
- prevParams,
216
- request,
217
- prevUrl,
218
- nextUrl,
219
- actionContext,
220
- interceptResult,
221
- localRouteName,
222
- pathname,
223
- segmentDeps,
224
- stale,
225
- chain,
226
- );
227
- }
228
-
229
- function findInterceptForRoute(
230
- targetRouteKey: string,
231
- fromEntry: EntryData | null,
232
- selectorContext: InterceptSelectorContext | null = null,
233
- isAction: boolean = false,
234
- ): ReturnType<typeof _findInterceptForRoute> {
235
- return _findInterceptForRoute(
236
- targetRouteKey,
237
- fromEntry,
238
- selectorContext,
239
- isAction,
240
- );
241
- }
242
-
243
- function resolveInterceptEntry(
244
- interceptEntry: InterceptEntry,
245
- parentEntry: EntryData,
246
- params: Record<string, string>,
247
- context: HandlerContext<any, TEnv>,
248
- belongsToRoute: boolean = true,
249
- revalidationContext?: any,
250
- options?: { background?: boolean },
251
- ): ReturnType<typeof _resolveInterceptEntry> {
252
- return _resolveInterceptEntry(
253
- interceptEntry,
254
- parentEntry,
255
- params,
256
- context,
257
- belongsToRoute,
258
- segmentDeps,
259
- revalidationContext,
260
- options,
261
- );
262
- }
263
-
264
- function resolveInterceptLoadersOnly(
265
- interceptEntry: InterceptEntry,
266
- parentEntry: EntryData,
267
- context: HandlerContext<any, TEnv>,
268
- belongsToRoute: boolean,
269
- revalidationContext: RevalidationContext,
270
- ): ReturnType<typeof _resolveInterceptLoadersOnly> {
271
- return _resolveInterceptLoadersOnly(
272
- interceptEntry,
273
- parentEntry,
274
- context,
275
- belongsToRoute,
276
- segmentDeps,
277
- revalidationContext,
278
- );
279
- }
45
+ const pass = (input: ResolutionPassInput<TEnv>): ResolutionPass<TEnv> => ({
46
+ ...input,
47
+ deps,
48
+ });
280
49
 
281
50
  return {
282
- resolveAllSegments: resolveAllSegments,
283
- resolveLoadersOnly: resolveLoadersOnly,
284
- resolveLoadersOnlyWithRevalidation: resolveLoadersOnlyWithRevalidation,
285
- buildEntryRevalidateMap: buildEntryRevalidateMap,
286
- resolveAllSegmentsWithRevalidation: resolveAllSegmentsWithRevalidation,
287
- findInterceptForRoute: findInterceptForRoute,
288
- resolveInterceptEntry: resolveInterceptEntry,
289
- resolveInterceptLoadersOnly: resolveInterceptLoadersOnly,
51
+ resolveLoadersOnly: (input, entries, walk) =>
52
+ _resolveLoadersOnly(pass(input), entries, walk),
53
+ buildEntryRevalidateMap: _buildEntryRevalidateMap,
54
+ resolveAllSegments: (input, entries, walk) =>
55
+ _resolveAllSegments(pass(input), entries, walk),
56
+ findInterceptForRoute: _findInterceptForRoute,
57
+ resolveInterceptEntry: (input, intercept, entry, belongsToRoute, options) =>
58
+ _resolveInterceptEntry(
59
+ pass(input),
60
+ intercept,
61
+ entry,
62
+ belongsToRoute,
63
+ options,
64
+ ),
65
+ resolveInterceptLoadersOnly: (input, intercept, entry, belongsToRoute) =>
66
+ _resolveInterceptLoadersOnly(
67
+ pass(input),
68
+ intercept,
69
+ entry,
70
+ belongsToRoute,
71
+ ),
290
72
  };
291
73
  }
@@ -317,6 +317,11 @@ export function getRequestId(request: Request): string {
317
317
  return id;
318
318
  }
319
319
 
320
+ /** Make `id` the id getRequestId returns for `request`. */
321
+ export function setRequestId(request: Request, id: string): void {
322
+ requestIds.set(request, id);
323
+ }
324
+
320
325
  /**
321
326
  * Built-in console sink that logs events in a structured format.
322
327
  * Designed as the default sink for development / debugging.
@@ -32,6 +32,16 @@ export type ActionContext = {
32
32
  actionUrl?: URL;
33
33
  actionResult?: any;
34
34
  formData?: FormData;
35
+ /**
36
+ * A thrown action's error segment (matchError), set on the action's
37
+ * revalidation (rsc/server-action.ts matchBoundaryRevalidation). The walk
38
+ * (resolveAllSegments) resolves every entry above the segment's outlet as on
39
+ * a success, emits the segment in the outlet's place and stops, so nothing
40
+ * at or below the outlet runs. The pass skips the prerender store
41
+ * (cache-lookup.ts): the evicted handler is under the cut. No revalidate()
42
+ * predicate sees it.
43
+ */
44
+ boundary?: ResolvedSegment;
35
45
  };
36
46
 
37
47
  export interface SegmentResolutionDeps<TEnv = any> {
@@ -47,7 +57,6 @@ export interface SegmentResolutionDeps<TEnv = any> {
47
57
  params?: Record<string, string>;
48
58
  env?: TEnv;
49
59
  isPartial?: boolean;
50
- requestStartTime?: number;
51
60
  },
52
61
  /** An `ssr: false` loader on a document or capture render. */
53
62
  useDefaultErrorBoundary?: boolean,
@@ -57,6 +66,7 @@ export interface SegmentResolutionDeps<TEnv = any> {
57
66
  errorContext?: {
58
67
  segmentId?: string;
59
68
  segmentType?: string;
69
+ isPartial?: boolean;
60
70
  },
61
71
  ) => Promise<T>;
62
72
  findNearestErrorBoundary: (
package/src/router.ts CHANGED
@@ -44,6 +44,7 @@ import { createHandleStore, type HandleStore } from "./server/handle-store.js";
44
44
  import {
45
45
  getRequestContext,
46
46
  _getRequestContext,
47
+ reportedErrorsOf,
47
48
  } from "./server/request-context.js";
48
49
  import type {
49
50
  ErrorPhase,
@@ -315,7 +316,8 @@ export function createRouter<TEnv = any>(
315
316
  * Wrapper for invokeOnError that binds the router's onError callback.
316
317
  * Uses the shared utility from router/error-handling.ts for consistent behavior.
317
318
  *
318
- * Deduplicates via per-request WeakSet stored on the ALS request context.
319
+ * Deduplicates via per-request WeakSet stored on the ALS request context
320
+ * (background work keeps its own, reportedErrorsOf).
319
321
  * A closure-level WeakSet would silently swallow errors if the same object
320
322
  * instance is thrown across separate requests (e.g. a singleton error).
321
323
  */
@@ -325,7 +327,8 @@ export function createRouter<TEnv = any>(
325
327
  context: Parameters<typeof invokeOnError<TEnv>>[3],
326
328
  ): void {
327
329
  if (error != null && typeof error === "object") {
328
- const reportedErrors = _getRequestContext()?._reportedErrors;
330
+ const reqCtx = _getRequestContext();
331
+ const reportedErrors = reqCtx && reportedErrorsOf(reqCtx);
329
332
  if (reportedErrors) {
330
333
  if (reportedErrors.has(error)) return;
331
334
  reportedErrors.add(error);
@@ -488,6 +491,7 @@ export function createRouter<TEnv = any>(
488
491
  errorContext?: {
489
492
  segmentId?: string;
490
493
  segmentType?: string;
494
+ isPartial?: boolean;
491
495
  },
492
496
  ): Promise<T> => {
493
497
  // One ALS read serves both the store lookup and the onError closure.
@@ -520,6 +524,7 @@ export function createRouter<TEnv = any>(
520
524
  env: reqCtx.env as TEnv,
521
525
  segmentId: errorContext?.segmentId,
522
526
  segmentType: errorContext?.segmentType as any,
527
+ isPartial: errorContext?.isPartial,
523
528
  handledByBoundary: true,
524
529
  });
525
530
  });
@@ -542,22 +547,24 @@ export function createRouter<TEnv = any>(
542
547
  params?: Record<string, string>;
543
548
  env?: TEnv;
544
549
  isPartial?: boolean;
545
- requestStartTime?: number;
546
550
  },
547
551
  useDefaultErrorBoundary?: boolean,
548
552
  ): Promise<LoaderDataResult<T>> {
549
- const loaderStart = telemetrySink ? performance.now() : 0;
550
- const loaderRequestId = telemetrySink
553
+ // A PPR shell capture sends nothing to the sink: the same switch as match().
554
+ const emitTelemetry =
555
+ !!telemetrySink && !_getRequestContext()?._shellCaptureState?.run;
556
+ const loaderStart = emitTelemetry ? performance.now() : 0;
557
+ const loaderRequestId = emitTelemetry
551
558
  ? errorContext?.request
552
559
  ? getRequestId(errorContext.request)
553
560
  : undefined
554
561
  : undefined;
555
562
  // Derived once here for both the loader.start and loader.end emits (the
556
563
  // loader.error emit uses ctx.loaderName from wrapLoaderWithErrorHandling).
557
- const loaderName = telemetrySink
564
+ const loaderName = emitTelemetry
558
565
  ? segmentId.split(".").pop() || "unknown"
559
566
  : "";
560
- if (telemetrySink) {
567
+ if (emitTelemetry) {
561
568
  safeEmit(telemetry, {
562
569
  type: "loader.start",
563
570
  timestamp: loaderStart,
@@ -589,9 +596,8 @@ export function createRouter<TEnv = any>(
589
596
  env: errorContext.env,
590
597
  isPartial: errorContext.isPartial,
591
598
  handledByBoundary: ctx.handledByBoundary,
592
- requestStartTime: errorContext.requestStartTime,
593
599
  });
594
- if (telemetrySink) {
600
+ if (emitTelemetry) {
595
601
  const errorObj =
596
602
  error instanceof Error ? error : new Error(String(error));
597
603
  safeEmit(telemetry, {
@@ -618,7 +624,7 @@ export function createRouter<TEnv = any>(
618
624
  );
619
625
 
620
626
  // Emit loader.end after the promise settles (fire-and-forget)
621
- if (telemetrySink) {
627
+ if (emitTelemetry) {
622
628
  result.then((r) => {
623
629
  safeEmit(telemetry, {
624
630
  type: "loader.end",
@@ -663,11 +669,9 @@ export function createRouter<TEnv = any>(
663
669
 
664
670
  // Create segment resolution wrappers bound to segmentDeps
665
671
  const {
666
- resolveAllSegments,
667
672
  resolveLoadersOnly,
668
- resolveLoadersOnlyWithRevalidation,
669
673
  buildEntryRevalidateMap,
670
- resolveAllSegmentsWithRevalidation,
674
+ resolveAllSegments,
671
675
  findInterceptForRoute,
672
676
  resolveInterceptEntry,
673
677
  resolveInterceptLoadersOnly,
@@ -713,16 +717,14 @@ export function createRouter<TEnv = any>(
713
717
  getMetricsStore,
714
718
  createCacheScope,
715
719
  findInterceptForRoute,
716
- resolveAllSegmentsWithRevalidation,
720
+ resolveAllSegments,
717
721
  resolveInterceptEntry,
718
722
  evaluateRevalidation,
719
723
  getRequestContext,
720
- resolveAllSegments,
721
724
  createHandleStore,
722
725
  buildEntryRevalidateMap,
723
- resolveLoadersOnlyWithRevalidation,
724
- resolveInterceptLoadersOnly,
725
726
  resolveLoadersOnly,
727
+ resolveInterceptLoadersOnly,
726
728
  telemetry: telemetrySink,
727
729
  };
728
730
  }
@@ -61,7 +61,7 @@ export function buildFullPayload(
61
61
  // capture renders from what its record keeps (resolvedHandleStream).
62
62
  handles: resolvedHandleStream(
63
63
  handleStore,
64
- reqCtx._shellCaptureRun === true,
64
+ reqCtx._shellCaptureState?.run === true,
65
65
  ),
66
66
  // Post-handler-barrier pushes (streaming loader ctx.handle() writes)
67
67
  // stream here; the client applies them after hydration. Instantly
@@ -105,8 +105,7 @@ export function renderedLocation(
105
105
  | Pick<
106
106
  RequestContext<any>,
107
107
  | "_variables"
108
- | "_shellCaptureRun"
109
- | "_shellCaptureForVisitor"
108
+ | "_shellCaptureState"
110
109
  | "_documentCacheRender"
111
110
  | "_payloadVisitorLocation"
112
111
  | "res"
@@ -116,7 +115,9 @@ export function renderedLocation(
116
115
  ): URL {
117
116
  if (!reqCtx || !rewriteTrail(reqCtx)) return url;
118
117
  if (rendersForSharedAudience(reqCtx)) {
119
- return reqCtx._shellCaptureForVisitor ? visitorUrl(reqCtx, url) : url;
118
+ return reqCtx._shellCaptureState?.forVisitor
119
+ ? visitorUrl(reqCtx, url)
120
+ : url;
120
121
  }
121
122
  reqCtx._payloadVisitorLocation = true;
122
123
  return visitorUrl(reqCtx, url);
@@ -163,7 +164,7 @@ export function payloadInitialTheme(
163
164
  reqCtx: Pick<
164
165
  RequestContext<any>,
165
166
  | "_themeConfig"
166
- | "_shellCaptureRun"
167
+ | "_shellCaptureState"
167
168
  | "_readTheme"
168
169
  | "_documentCacheRender"
169
170
  | "_payloadVisitorTheme"
@@ -7,12 +7,17 @@
7
7
  */
8
8
 
9
9
  import type { RangoInternal } from "../router/router-interfaces.js";
10
- import type { ErrorPhase } from "../types.js";
11
- import type { InvokeOnErrorContext } from "../router/error-handling.js";
12
10
  import type { RSCDependencies, LoadSSRModule } from "./types.js";
13
11
  import type { SSRStreamMode } from "../router/router-options.js";
12
+ import type { RequestStageContext } from "./request-stages.js";
14
13
 
15
- export interface HandlerContext<TEnv = unknown> {
14
+ /**
15
+ * Extends what the request stages (rsc/request-stages.ts) call back into, so
16
+ * the handler hands this one bundle to them as well.
17
+ */
18
+ export interface HandlerContext<
19
+ TEnv = unknown,
20
+ > extends RequestStageContext<TEnv> {
16
21
  router: RangoInternal<TEnv, any>;
17
22
  /**
18
23
  * The router's DOCUMENT version (router-versions.ts): payload metadata, the
@@ -28,17 +33,6 @@ export interface HandlerContext<TEnv = unknown> {
28
33
  decodeAction: RSCDependencies["decodeAction"];
29
34
  decodeFormState: RSCDependencies["decodeFormState"];
30
35
  loadSSRModule: LoadSSRModule;
31
- callOnError: (
32
- error: unknown,
33
- phase: ErrorPhase,
34
- context: InvokeOnErrorContext<TEnv>,
35
- ) => void;
36
- getRequiredRouteMap: () => Record<string, string>;
37
- createRedirectFlightResponse: (
38
- redirectUrl: string,
39
- locationState?: Record<string, unknown>,
40
- external?: boolean,
41
- ) => Response;
42
36
 
43
37
  /**
44
38
  * Resolve the SSR stream mode for a given request.