@rangojs/router 0.24.4 → 0.25.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 (267) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/rango.js +363 -39
  3. package/dist/testing/vitest.js +37 -4
  4. package/dist/types/browser/event-controller.d.ts +24 -5
  5. package/dist/types/browser/intercept-utils.d.ts +5 -2
  6. package/dist/types/browser/merge-segment-loaders.d.ts +0 -23
  7. package/dist/types/browser/navigation-transaction.d.ts +5 -5
  8. package/dist/types/browser/partial-update.d.ts +21 -13
  9. package/dist/types/browser/prefetch/cache.d.ts +8 -0
  10. package/dist/types/browser/rango-marker.d.ts +7 -0
  11. package/dist/types/browser/react/filter-segment-order.d.ts +10 -0
  12. package/dist/types/browser/react/use-handle.d.ts +20 -0
  13. package/dist/types/browser/react/use-href.d.ts +6 -0
  14. package/dist/types/browser/react/use-router.d.ts +6 -1
  15. package/dist/types/browser/response-adapter.d.ts +5 -3
  16. package/dist/types/browser/scroll-restoration.d.ts +9 -3
  17. package/dist/types/browser/segment-reconciler.d.ts +10 -13
  18. package/dist/types/browser/types.d.ts +38 -8
  19. package/dist/types/build/route-types/per-module-writer.d.ts +12 -0
  20. package/dist/types/cache/cf/cf-shell-frame.d.ts +2 -0
  21. package/dist/types/cache/types.d.ts +8 -0
  22. package/dist/types/client-urls/client-urls.d.ts +6 -2
  23. package/dist/types/client-urls/revalidate-registry.d.ts +1 -1
  24. package/dist/types/client-urls/server-projection.d.ts +9 -5
  25. package/dist/types/client-urls/types.d.ts +29 -16
  26. package/dist/types/client.d.ts +2 -2
  27. package/dist/types/client.rsc.d.ts +2 -2
  28. package/dist/types/decode-loader-results.d.ts +28 -7
  29. package/dist/types/href-client.d.ts +3 -1
  30. package/dist/types/index.rsc.d.ts +1 -1
  31. package/dist/types/loader-redirect.d.ts +2 -3
  32. package/dist/types/outlet-context.d.ts +7 -6
  33. package/dist/types/prefetch-markers.d.ts +14 -5
  34. package/dist/types/route-content-wrapper.d.ts +17 -14
  35. package/dist/types/route-definition/helpers-types.d.ts +7 -2
  36. package/dist/types/route-definition/resolve-handler-use.d.ts +6 -1
  37. package/dist/types/route-definition/rewrite.d.ts +48 -5
  38. package/dist/types/route-types.d.ts +2 -2
  39. package/dist/types/router/handler-context.d.ts +14 -2
  40. package/dist/types/router/intercept-resolution.d.ts +19 -46
  41. package/dist/types/router/lazy-includes.d.ts +7 -0
  42. package/dist/types/router/match-middleware/intercept-resolution.d.ts +2 -2
  43. package/dist/types/router/middleware.d.ts +0 -16
  44. package/dist/types/router/navigation-snapshot.d.ts +2 -0
  45. package/dist/types/router/prefetch-cache-ttl.d.ts +8 -11
  46. package/dist/types/router/revalidation.d.ts +8 -1
  47. package/dist/types/router/router-context.d.ts +4 -16
  48. package/dist/types/router/router-interfaces.d.ts +0 -6
  49. package/dist/types/router/router-options.d.ts +4 -7
  50. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +31 -8
  51. package/dist/types/router/segment-resolution/revalidation.d.ts +38 -4
  52. package/dist/types/router/segment-resolution.d.ts +1 -1
  53. package/dist/types/router/segment-wrappers.d.ts +3 -5
  54. package/dist/types/router/substitute-pattern-params.d.ts +3 -2
  55. package/dist/types/router/tracing.d.ts +2 -2
  56. package/dist/types/rsc/full-payload.d.ts +14 -2
  57. package/dist/types/rsc/helpers.d.ts +8 -0
  58. package/dist/types/rsc/manifest-init.d.ts +20 -0
  59. package/dist/types/rsc/prefetch-render-error.d.ts +22 -0
  60. package/dist/types/rsc/progressive-enhancement.d.ts +20 -0
  61. package/dist/types/rsc/rewrite-passes.d.ts +12 -2
  62. package/dist/types/rsc/server-action.d.ts +6 -0
  63. package/dist/types/rsc/shell-capture-constants.d.ts +10 -1
  64. package/dist/types/rsc/shell-capture.d.ts +7 -0
  65. package/dist/types/rsc/types.d.ts +5 -0
  66. package/dist/types/segment-system.d.ts +15 -0
  67. package/dist/types/server/context.d.ts +64 -4
  68. package/dist/types/server/request-context.d.ts +41 -4
  69. package/dist/types/server/request-headers.d.ts +12 -0
  70. package/dist/types/server/rewrite-trail.d.ts +8 -1
  71. package/dist/types/testing/e2e/index.d.ts +1 -1
  72. package/dist/types/testing/flight.entry.d.ts +1 -1
  73. package/dist/types/testing/index.d.ts +1 -1
  74. package/dist/types/testing/internal/client-urls-projection.d.ts +4 -3
  75. package/dist/types/testing/render-route.d.ts +21 -11
  76. package/dist/types/testing/run-loader.d.ts +7 -0
  77. package/dist/types/testing/run-middleware.d.ts +7 -0
  78. package/dist/types/testing/run-revalidate.d.ts +5 -4
  79. package/dist/types/testing/serve-shell-request.d.ts +41 -4
  80. package/dist/types/testing/shell-status.d.ts +17 -0
  81. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  82. package/dist/types/testing/vitest.d.ts +10 -1
  83. package/dist/types/thenable-status.d.ts +0 -6
  84. package/dist/types/types/handler-context.d.ts +12 -1
  85. package/dist/types/types/loader-types.d.ts +4 -3
  86. package/dist/types/types/route-entry.d.ts +2 -1
  87. package/dist/types/urls/path-helper-types.d.ts +4 -2
  88. package/dist/types/vite/discovery/client-urls-projection.d.ts +55 -5
  89. package/dist/types/vite/discovery/state.d.ts +20 -0
  90. package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +28 -16
  91. package/dist/types/vite/plugins/hoist/source.d.ts +8 -7
  92. package/dist/types/vite/plugins/virtual-entries.d.ts +6 -0
  93. package/dist/types/vite/utils/prerender-utils.d.ts +7 -0
  94. package/dist/vite/index.js +6816 -6547
  95. package/package.json +1 -1
  96. package/skills/app-structure/SKILL.md +255 -0
  97. package/skills/app-structure/content-site.md +333 -0
  98. package/skills/app-structure/e-commerce.md +435 -0
  99. package/skills/app-structure/large-app.md +885 -0
  100. package/skills/app-structure/multi-app.md +280 -0
  101. package/skills/breadcrumbs/SKILL.md +6 -1
  102. package/skills/caching/SKILL.md +3 -1
  103. package/skills/catalog.json +12 -0
  104. package/skills/client-urls/SKILL.md +185 -32
  105. package/skills/composability/SKILL.md +10 -8
  106. package/skills/handler-use/SKILL.md +48 -9
  107. package/skills/hooks/handle-and-actions.md +104 -0
  108. package/skills/hooks/navigation.md +24 -10
  109. package/skills/hooks/urls.md +1 -1
  110. package/skills/i18n/SKILL.md +2 -1
  111. package/skills/intercept/SKILL.md +60 -29
  112. package/skills/layout/SKILL.md +6 -3
  113. package/skills/links/SKILL.md +151 -17
  114. package/skills/loader/SKILL.md +32 -10
  115. package/skills/middleware/SKILL.md +111 -15
  116. package/skills/observability/SKILL.md +11 -0
  117. package/skills/parallel/SKILL.md +5 -5
  118. package/skills/ppr/SKILL.md +43 -8
  119. package/skills/prerender/SKILL.md +1 -2
  120. package/skills/rango/SKILL.md +3 -0
  121. package/skills/response-routes/SKILL.md +4 -1
  122. package/skills/scripts/SKILL.md +12 -1
  123. package/skills/server-actions/SKILL.md +60 -20
  124. package/skills/testing/SKILL.md +1 -0
  125. package/skills/testing/client-components.md +13 -10
  126. package/skills/testing/loader.md +25 -24
  127. package/skills/testing/middleware.md +11 -11
  128. package/skills/testing/response-routes.md +4 -1
  129. package/skills/testing/serve-shell-request.md +85 -21
  130. package/skills/ux-architecture/SKILL.md +980 -0
  131. package/skills/view-transitions/SKILL.md +43 -10
  132. package/src/__augment-tests__/augmented.check.ts +28 -0
  133. package/src/browser/event-controller.ts +44 -18
  134. package/src/browser/intercept-utils.ts +3 -2
  135. package/src/browser/merge-segment-loaders.ts +0 -85
  136. package/src/browser/navigation-bridge.ts +112 -84
  137. package/src/browser/navigation-client.ts +20 -15
  138. package/src/browser/navigation-store.ts +4 -2
  139. package/src/browser/navigation-transaction.ts +9 -8
  140. package/src/browser/partial-update.ts +90 -32
  141. package/src/browser/prefetch/cache.ts +8 -0
  142. package/src/browser/prefetch/fetch.ts +13 -3
  143. package/src/browser/rango-marker.ts +13 -0
  144. package/src/browser/react/NavigationProvider.tsx +25 -7
  145. package/src/browser/react/filter-segment-order.ts +13 -0
  146. package/src/browser/react/use-action.ts +9 -15
  147. package/src/browser/react/use-handle.ts +63 -71
  148. package/src/browser/react/use-href.tsx +24 -5
  149. package/src/browser/react/use-link-status.ts +1 -1
  150. package/src/browser/react/use-navigation.ts +30 -40
  151. package/src/browser/react/use-router.ts +37 -6
  152. package/src/browser/react/use-segments.ts +8 -12
  153. package/src/browser/response-adapter.ts +11 -5
  154. package/src/browser/rsc-router.tsx +3 -1
  155. package/src/browser/scroll-restoration.ts +34 -20
  156. package/src/browser/segment-reconciler.ts +11 -29
  157. package/src/browser/server-action-bridge.ts +52 -16
  158. package/src/browser/types.ts +40 -8
  159. package/src/build/generate-manifest.ts +12 -1
  160. package/src/build/route-types/codegen.ts +6 -2
  161. package/src/build/route-types/per-module-writer.ts +94 -61
  162. package/src/cache/cache-runtime.ts +9 -0
  163. package/src/cache/cache-scope.ts +2 -1
  164. package/src/cache/cf/cf-cache-store.ts +2 -0
  165. package/src/cache/cf/cf-shell-frame.ts +3 -0
  166. package/src/cache/types.ts +8 -0
  167. package/src/cache/vercel/vercel-cache-store.ts +6 -1
  168. package/src/client-urls/client-urls.ts +202 -153
  169. package/src/client-urls/revalidate-registry.ts +12 -3
  170. package/src/client-urls/server-projection.ts +137 -66
  171. package/src/client-urls/types.ts +30 -15
  172. package/src/client.rsc.tsx +11 -1
  173. package/src/client.tsx +9 -1
  174. package/src/decode-loader-results.ts +64 -31
  175. package/src/href-client.ts +3 -1
  176. package/src/index.rsc.ts +1 -0
  177. package/src/index.ts +12 -4
  178. package/src/loader-redirect.tsx +2 -3
  179. package/src/outlet-context.ts +7 -6
  180. package/src/prefetch-markers.ts +15 -5
  181. package/src/reverse.ts +3 -3
  182. package/src/route-content-wrapper.tsx +19 -17
  183. package/src/route-definition/dsl-helpers.ts +27 -7
  184. package/src/route-definition/helpers-types.ts +7 -2
  185. package/src/route-definition/resolve-handler-use.ts +23 -10
  186. package/src/route-definition/rewrite.ts +86 -19
  187. package/src/route-types.ts +1 -2
  188. package/src/router/find-match.ts +37 -1
  189. package/src/router/handler-context.ts +85 -40
  190. package/src/router/intercept-resolution.ts +161 -307
  191. package/src/router/lazy-includes.ts +43 -27
  192. package/src/router/loader-resolution.ts +21 -1
  193. package/src/router/manifest.ts +6 -8
  194. package/src/router/match-api.ts +11 -1
  195. package/src/router/match-middleware/background-revalidation.ts +2 -4
  196. package/src/router/match-middleware/cache-lookup.ts +16 -20
  197. package/src/router/match-middleware/intercept-resolution.ts +41 -60
  198. package/src/router/match-result.ts +31 -2
  199. package/src/router/middleware.ts +6 -147
  200. package/src/router/navigation-snapshot.ts +38 -2
  201. package/src/router/prefetch-cache-ttl.ts +10 -18
  202. package/src/router/prerender-match.ts +2 -1
  203. package/src/router/revalidation.ts +24 -3
  204. package/src/router/router-context.ts +5 -18
  205. package/src/router/router-interfaces.ts +0 -7
  206. package/src/router/router-options.ts +4 -7
  207. package/src/router/segment-resolution/fresh.ts +6 -2
  208. package/src/router/segment-resolution/helpers.ts +7 -1
  209. package/src/router/segment-resolution/prefetch-deferral.ts +62 -12
  210. package/src/router/segment-resolution/revalidation.ts +75 -35
  211. package/src/router/segment-resolution.ts +0 -1
  212. package/src/router/segment-wrappers.ts +8 -13
  213. package/src/router/substitute-pattern-params.ts +3 -2
  214. package/src/router/tracing.ts +2 -2
  215. package/src/router.ts +2 -9
  216. package/src/rsc/full-payload.ts +26 -4
  217. package/src/rsc/handler.ts +83 -41
  218. package/src/rsc/helpers.ts +13 -0
  219. package/src/rsc/manifest-init.ts +56 -3
  220. package/src/rsc/prefetch-render-error.ts +38 -0
  221. package/src/rsc/progressive-enhancement.ts +161 -211
  222. package/src/rsc/rewrite-passes.ts +56 -9
  223. package/src/rsc/rsc-rendering.ts +79 -23
  224. package/src/rsc/server-action.ts +25 -2
  225. package/src/rsc/shell-capture-constants.ts +22 -0
  226. package/src/rsc/shell-capture.ts +11 -0
  227. package/src/rsc/types.ts +5 -0
  228. package/src/segment-system.tsx +125 -119
  229. package/src/server/context.ts +96 -5
  230. package/src/server/handle-store.ts +3 -2
  231. package/src/server/request-context.ts +42 -3
  232. package/src/server/request-headers.ts +32 -0
  233. package/src/server/rewrite-trail.ts +55 -9
  234. package/src/ssr/ssr-root.tsx +6 -10
  235. package/src/testing/dispatch.ts +4 -5
  236. package/src/testing/e2e/index.ts +1 -0
  237. package/src/testing/flight.entry.ts +1 -0
  238. package/src/testing/index.ts +1 -0
  239. package/src/testing/internal/client-urls-projection.ts +31 -11
  240. package/src/testing/render-route.tsx +83 -40
  241. package/src/testing/run-loader.ts +26 -2
  242. package/src/testing/run-middleware.ts +10 -0
  243. package/src/testing/run-revalidate.ts +13 -6
  244. package/src/testing/serve-shell-request.ts +77 -4
  245. package/src/testing/shell-status.ts +40 -0
  246. package/src/testing/vitest-stubs/version.ts +1 -0
  247. package/src/testing/vitest.ts +74 -7
  248. package/src/thenable-status.ts +0 -11
  249. package/src/types/handler-context.ts +12 -1
  250. package/src/types/loader-types.ts +4 -3
  251. package/src/types/route-entry.ts +2 -1
  252. package/src/urls/include-helper.ts +38 -11
  253. package/src/urls/path-helper-types.ts +4 -2
  254. package/src/vite/discovery/client-urls-projection.ts +205 -16
  255. package/src/vite/discovery/discover-routers.ts +2 -2
  256. package/src/vite/discovery/prerender-collection.ts +2 -6
  257. package/src/vite/discovery/state.ts +26 -0
  258. package/src/vite/plugins/client-urls-revalidate-hoist.ts +190 -77
  259. package/src/vite/plugins/expose-internal-ids.ts +46 -40
  260. package/src/vite/plugins/hoist/source.ts +8 -7
  261. package/src/vite/plugins/transition-when-hoist.ts +1 -0
  262. package/src/vite/plugins/version-plugin.ts +7 -0
  263. package/src/vite/plugins/version.d.ts +7 -0
  264. package/src/vite/plugins/virtual-entries.ts +20 -0
  265. package/src/vite/rango.ts +4 -1
  266. package/src/vite/router-discovery.ts +39 -7
  267. package/src/vite/utils/prerender-utils.ts +17 -0
@@ -8,7 +8,7 @@ import type { ResolveSegmentOptions } from "./segment-resolution.js";
8
8
  * Revalidation context passed to segment resolution
9
9
  */
10
10
  export interface RevalidationContext {
11
- clientSegmentIds: Set<string>;
11
+ clientSegmentIds: ReadonlySet<string>;
12
12
  prevParams: Record<string, string>;
13
13
  request: Request;
14
14
  prevUrl: URL;
@@ -20,7 +20,7 @@ export interface RevalidationContext {
20
20
  actionResult?: any;
21
21
  formData?: FormData;
22
22
  };
23
- stale: boolean;
23
+ stale?: boolean;
24
24
  }
25
25
  /**
26
26
  * Result from intercept lookup
@@ -61,7 +61,7 @@ export interface RouterContext<TEnv = any> {
61
61
  id: string;
62
62
  }>;
63
63
  resolveInterceptEntry: (intercept: InterceptEntry, entry: EntryData, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, belongsToRoute: boolean, revalidationContext?: RevalidationContext, options?: {
64
- skipMiddleware?: boolean;
64
+ background?: boolean;
65
65
  }) => Promise<ResolvedSegment[]>;
66
66
  collectWithMarkers?: <T>(gen: AsyncGenerator<T | {
67
67
  __type: "id";
@@ -111,19 +111,7 @@ export interface RouterContext<TEnv = any> {
111
111
  }>;
112
112
  telemetry?: TelemetrySink;
113
113
  requestId?: string;
114
- resolveInterceptLoadersOnly?: (intercept: InterceptEntry, entry: EntryData, params: Record<string, string>, handlerContext: HandlerContext<any, TEnv>, belongsToRoute: boolean, revalidationContext: {
115
- clientSegmentIds: Set<string>;
116
- prevParams: Record<string, string>;
117
- request: Request;
118
- prevUrl: URL;
119
- nextUrl: URL;
120
- routeKey: string;
121
- actionContext?: any;
122
- stale?: boolean;
123
- }) => Promise<{
124
- loaderDataPromise: Promise<any[]> | any[];
125
- loaderIds: string[];
126
- } | null>;
114
+ resolveInterceptLoadersOnly?: (intercept: InterceptEntry, entry: EntryData, handlerContext: HandlerContext<any, TEnv>, belongsToRoute: boolean, revalidationContext: RevalidationContext) => Promise<ResolvedSegment[]>;
127
115
  }
128
116
  /**
129
117
  * Get router dependencies from AsyncLocalStorage context
@@ -296,12 +296,6 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
296
296
  * Always includes at least the "default" profile.
297
297
  */
298
298
  readonly cacheProfiles: Record<string, import("../cache/profile-registry.js").CacheProfile>;
299
- /**
300
- * Cache-Control header value for prefetch responses.
301
- * False means no caching of prefetch responses.
302
- * Derived from prefetchCacheTTL.
303
- */
304
- readonly prefetchCacheControl: string | false;
305
299
  /**
306
300
  * TTL in milliseconds for the client-side in-memory prefetch cache.
307
301
  * 0 means caching is disabled.
@@ -510,15 +510,12 @@ export interface RangoOptions<TEnv = any> {
510
510
  */
511
511
  version?: string;
512
512
  /**
513
- * TTL (in seconds) for the in-memory prefetch cache and the
514
- * Cache-Control header on prefetch responses.
513
+ * TTL (in seconds) for the client-side in-memory prefetch cache.
515
514
  *
516
515
  * Controls how long prefetch responses are kept in the client-side
517
- * in-memory cache and sets `Cache-Control: private, max-age=<ttl>`
518
- * on prefetch responses, so the browser's HTTP cache may reuse them
519
- * (`private`: shared caches such as a CDN do not store them). A route an
520
- * intercept targets gets no prefetch `Cache-Control`: whether its
521
- * response is the modal or the full page depends on the source page.
516
+ * in-memory cache. Prefetch responses carry no `Cache-Control`, so the
517
+ * browser's HTTP cache does not keep them: a prefetch whose render failed
518
+ * after its 200 went out would otherwise answer later requests.
522
519
  *
523
520
  * The cache is automatically invalidated on server actions regardless
524
521
  * of TTL, so this is primarily a staleness safety net.
@@ -24,7 +24,7 @@
24
24
  * force a same-route render from an intercept source (match-api.ts), and a
25
25
  * unit deferred on that ground would be dropped from the response as held.
26
26
  */
27
- import { type EntryData, type LoaderEntry } from "../../server/context.js";
27
+ import { type EntryData, type InterceptEntry, type LoaderEntry } from "../../server/context.js";
28
28
  import type { HandlerContext } from "../../types.js";
29
29
  import type { CacheScope } from "../../cache/cache-scope.js";
30
30
  /**
@@ -148,33 +148,42 @@ export interface DeferredLoader {
148
148
  * in the tree declares `prefetch: false`.
149
149
  */
150
150
  export declare function resolveDeferralScope(entries: readonly EntryData[]): DeferralScope;
151
+ /**
152
+ * The deferral scope of a request that resolves `intercept`: its own flagged
153
+ * loaders, nothing of the target chain. The chain's layouts below the
154
+ * declaring entry render in that request and its `matched` leaves them out
155
+ * (match-result.ts), so a hole there would stand for a segment outside the
156
+ * page. A flagged loading() inside intercept() defers nothing: the slot is
157
+ * never a unit. Memoized on the entry (replaced with its manifest on HMR).
158
+ */
159
+ export declare function resolveInterceptDeferralScope(intercept: InterceptEntry): DeferralScope;
151
160
  /**
152
161
  * Which half of the feature a partial request is, if either (`fill` and
153
162
  * `prefetch` are requestKind's answer). Both halves are GETs: a request of
154
163
  * another method that carries either marker is a normal request. A prefetch
155
164
  * defers only on a plain GET navigation: an action re-renders what it
156
- * changed, an intercept resolves its loaders outside the shared funnel, and a
157
- * shell capture is never a prefetch whatever the request that scheduled it
158
- * sent. The four conditions overlap today (an action is a POST, a capture
159
- * runs the full match): each one states its own reason.
165
+ * changed, and a shell capture is never a prefetch whatever the request that
166
+ * scheduled it sent. The conditions overlap today (an action is a POST, a
167
+ * capture runs the full match): each one states its own reason.
160
168
  */
161
169
  export declare function partialDeferralMode(request: {
162
170
  fill: boolean;
163
171
  prefetch: boolean;
164
172
  method: string;
165
173
  isAction: boolean;
166
- isIntercept: boolean;
167
174
  isShellCapture: boolean;
168
175
  }): PrefetchDeferral["mode"];
176
+ export declare const NOTHING_HELD: ReadonlySet<string>;
169
177
  /**
170
178
  * The plan for one match, or undefined when the tree declares no flag and the
171
179
  * request is not a fill (the common case: nothing to carry). `held` is the
172
- * client's segment ids as the request listed them.
180
+ * client's segment ids as the request listed them. `scope` is the chain's
181
+ * unless the request resolves an intercept (resolveInterceptDeferralScope).
173
182
  */
174
183
  export declare function planPrefetchDeferral(entries: readonly EntryData[], mode: PrefetchDeferral["mode"], matched: {
175
184
  pr?: boolean;
176
185
  od?: boolean;
177
- }, cacheScope: CacheScope | null | undefined, held?: ReadonlySet<string>): PrefetchDeferral | undefined;
186
+ }, cacheScope: CacheScope | null | undefined, held?: ReadonlySet<string>, scope?: DeferralScope): PrefetchDeferral | undefined;
178
187
  export declare function getPrefetchDeferral(ctx: HandlerContext<any, any> | undefined): PrefetchDeferral | undefined;
179
188
  /** The request is a fill: a held segment is skipped without consulting anything. */
180
189
  export declare function isFillRequest(ctx: HandlerContext<any, any>): boolean;
@@ -186,6 +195,20 @@ export declare function isFillRequest(ctx: HandlerContext<any, any>): boolean;
186
195
  * deciding site resolves with.
187
196
  */
188
197
  export declare function fillSends(ctx: HandlerContext<any, any>, segmentId: string, held: ReadonlySet<string>): boolean | undefined;
198
+ /**
199
+ * A fill that resolves an intercept sends only what the client lacks of the
200
+ * intercept: a target-chain entry (by id) or stored segment it does not hold
201
+ * lies outside the intercept's `matched` (match-result.ts), so the fill skips
202
+ * it. The intercept's own segments are never skipped.
203
+ */
204
+ export declare function interceptFillSkips(match: {
205
+ handlerContext: HandlerContext<any, any>;
206
+ isIntercept: boolean;
207
+ clientSegmentSet: ReadonlySet<string>;
208
+ }, segment: string | {
209
+ id: string;
210
+ namespace?: string;
211
+ }): boolean;
189
212
  /** PrefetchDeferral.record, or all of it open when the match has no plan. */
190
213
  export declare function recordUse(ctx: HandlerContext<any, any> | undefined): RecordUse;
191
214
  /**
@@ -5,14 +5,48 @@
5
5
  * Mirrors the fresh path but adds revalidation awareness: only re-resolves
6
6
  * segments whose revalidate() predicate returns true.
7
7
  */
8
- import { type EntryData } from "../../server/context";
8
+ import { type EntryData, type LoaderEntry } from "../../server/context";
9
9
  import type { HandlerContext, ResolvedSegment, ShouldRevalidateFn } from "../../types";
10
10
  import type { SegmentResolutionDeps, SegmentRevalidationResult, ActionContext } from "../types.js";
11
11
  /**
12
- * Resolve loaders with revalidation awareness (for partial rendering).
13
- * Returns both segments to render AND all matched segment IDs.
12
+ * A deferred loader something started in this request (a handler that awaits
13
+ * it with ctx.use(), or another loader) ran in the prefetch whatever its flag
14
+ * says: deliver that run instead of having the fill run it a second time. A
15
+ * reader starts it through its registration (prefetch-deferral.ts
16
+ * startDeferredLoader), so the delivery's resolveLoaderData finds the same
17
+ * run or cache() binding. Called once resolution has awaited every handler it
18
+ * awaits; a streamed handler that reads the loader later is not seen, and
19
+ * that loader runs again in the fill.
14
20
  */
15
- export declare function resolveLoadersWithRevalidation<TEnv>(entry: EntryData, ctx: HandlerContext<any, TEnv>, belongsToRoute: boolean, clientSegmentIds: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, routeKey: string, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, shortCodeOverride?: string, stale?: boolean): Promise<{
21
+ export declare function deliverStartedLoaders<TEnv>(ctx: HandlerContext<any, TEnv>, segments: ResolvedSegment[]): void;
22
+ /**
23
+ * Whose loaders a resolveOwnerLoaders call resolves: a route entry's (or the
24
+ * entry its loaders are inherited into), or an intercept's, whose loaders are
25
+ * loader segments of its slot (`${parent}.${slot}D${i}.${$$id}`).
26
+ */
27
+ export interface LoaderOwner {
28
+ readonly loaders: readonly LoaderEntry[];
29
+ /** The segments' namespace: the entry id, or `intercept:${routeName}`. */
30
+ readonly namespace: string;
31
+ /** The segment id the loader ids extend and the handle pushes file under. */
32
+ readonly segmentPrefix: string;
33
+ /** Where a loader error renders (wrapLoaderPromise). */
34
+ readonly boundary: EntryData;
35
+ /**
36
+ * resolveLoaderData's PPR bake/seed key for every loader (loader-cache.ts).
37
+ * False for an intercept: never a document.
38
+ */
39
+ readonly bakeLane: boolean;
40
+ readonly traceSource: "loader" | "intercept-loader";
41
+ }
42
+ /** A route entry as a LoaderOwner, under `shortCodeOverride` when inherited. */
43
+ export declare function ownerOf(entry: EntryData, shortCodeOverride?: string): LoaderOwner;
44
+ /**
45
+ * The partial lane's one loader funnel: each loader is a segment, run when
46
+ * the client lacks it, asked its revalidate() when held, kept outright in a
47
+ * fill (fillSends), deferred in a prefetch that defers it (defersLoader).
48
+ */
49
+ export declare function resolveOwnerLoaders<TEnv>(owner: LoaderOwner, ctx: HandlerContext<any, TEnv>, belongsToRoute: boolean, clientSegmentIds: ReadonlySet<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, routeKey: string, deps: SegmentResolutionDeps<TEnv>, actionContext?: ActionContext, stale?: boolean): Promise<{
16
50
  segments: ResolvedSegment[];
17
51
  matchedIds: string[];
18
52
  }>;
@@ -1,3 +1,3 @@
1
1
  export { handleHandlerResult, warnOnStreamedResponse, buildLoaderErrorContext, } from "./segment-resolution/helpers.js";
2
2
  export { resolveLoaders, type ResolveSegmentOptions, resolveSegment, resolveOrphanLayout, resolveParallelEntry, resolveAllSegments, resolveLoadersOnly, } from "./segment-resolution/fresh.js";
3
- export { resolveLoadersWithRevalidation, resolveLoadersOnlyWithRevalidation, buildEntryRevalidateMap, resolveParallelSegmentsWithRevalidation, resolveEntryHandlerWithRevalidation, resolveSegmentWithRevalidation, resolveOrphanLayoutWithRevalidation, resolveAllSegmentsWithRevalidation, } from "./segment-resolution/revalidation.js";
3
+ export { resolveLoadersOnlyWithRevalidation, buildEntryRevalidateMap, resolveParallelSegmentsWithRevalidation, resolveEntryHandlerWithRevalidation, resolveSegmentWithRevalidation, resolveOrphanLayoutWithRevalidation, resolveAllSegmentsWithRevalidation, } from "./segment-resolution/revalidation.js";
@@ -2,6 +2,7 @@ import type { EntryData, InterceptEntry } from "../server/context";
2
2
  import type { HandlerContext, ResolvedSegment, ShouldRevalidateFn } from "../types";
3
3
  import type { SegmentResolutionDeps } from "./types.js";
4
4
  import type { ResolveSegmentOptions } from "./segment-resolution.js";
5
+ import type { RevalidationContext } from "./router-context.js";
5
6
  import type { InterceptSelectorContext } from "../server/context";
6
7
  export interface SegmentWrappers<TEnv = any> {
7
8
  resolveAllSegments: (entries: EntryData[], routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, loaderPromises: Map<string, Promise<any>>, options?: ResolveSegmentOptions) => Promise<ResolvedSegment[]>;
@@ -36,12 +37,9 @@ export interface SegmentWrappers<TEnv = any> {
36
37
  entry: EntryData;
37
38
  } | null;
38
39
  resolveInterceptEntry: (interceptEntry: InterceptEntry, parentEntry: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, belongsToRoute?: boolean, revalidationContext?: any, options?: {
39
- skipMiddleware?: boolean;
40
+ background?: boolean;
40
41
  }) => Promise<ResolvedSegment[]>;
41
- resolveInterceptLoadersOnly: (interceptEntry: InterceptEntry, parentEntry: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, belongsToRoute?: boolean, revalidationContext?: any) => Promise<{
42
- loaderDataPromise: Promise<any[]> | any[];
43
- loaderIds: string[];
44
- } | null>;
42
+ resolveInterceptLoadersOnly: (interceptEntry: InterceptEntry, parentEntry: EntryData, context: HandlerContext<any, TEnv>, belongsToRoute: boolean, revalidationContext: RevalidationContext) => Promise<ResolvedSegment[]>;
45
43
  }
46
44
  /**
47
45
  * Create thin wrapper functions that bind segmentDeps to extracted
@@ -17,8 +17,9 @@
17
17
  * omit when absent.
18
18
  *
19
19
  * Shared by `ctx.reverse()` (server), `createReverse()` (typed runtime
20
- * helper), and `useReverse()` (client hook). The behavior must stay
21
- * identical across all three call sites.
20
+ * helper), `useReverse()` (client hook), and the include() mount fill of
21
+ * `useHref()` and relative `useRouter().push`. The behavior must stay
22
+ * identical across all of them.
22
23
  */
23
24
  export declare function substitutePatternParams(pattern: string, params: Record<string, string | undefined>, routeName: string): string;
24
25
  /**
@@ -24,8 +24,8 @@
24
24
  * registry; do not call traceSpan directly from new code.
25
25
  *
26
26
  * Phase coverage (all via observePhase): rango.request (span-only; handler:total
27
- * metered directly), rango.middleware (span-only incl. intercept middleware;
28
- * pre/post metered directly), rango.action (action:<id>; server-action
27
+ * metered directly), rango.middleware (span-only; pre/post metered directly),
28
+ * rango.action (action:<id>; server-action
29
29
  * execution, JS + no-JS/PE), rango.loader (loader:<id>; single metering site at
30
30
  * useLoader, plus the fetchable path), rango.handler (span-only, one per segment
31
31
  * route/layout handler execution; the handler:<id> perf metric is owned by the
@@ -28,10 +28,22 @@ export declare function buildFullPayload(m: MatchResult, ctx: HandlerContext<any
28
28
  * bar) agree on `usePathname()` and `useSearchParams()`. A render other
29
29
  * visitors may be served shows `url`, the target, as a direct visit does: a
30
30
  * shell capture, and a render the document cache stores (its key is the
31
- * target). A render that shows the visitor's URL marks
31
+ * target), except a visitor-keyed shell capture, whose key covers the
32
+ * visitor's URL. Any other render that shows the visitor's URL marks
32
33
  * `_payloadVisitorLocation`, and the document cache does not store it.
33
34
  */
34
- export declare function renderedLocation(reqCtx: Pick<RequestContext<any>, "_variables" | "_shellCaptureRun" | "_documentCacheRender" | "_payloadVisitorLocation" | "res"> | undefined, url: URL): URL;
35
+ export declare function renderedLocation(reqCtx: Pick<RequestContext<any>, "_variables" | "_shellCaptureRun" | "_shellCaptureForVisitor" | "_documentCacheRender" | "_payloadVisitorLocation" | "res"> | undefined, url: URL): URL;
36
+ /**
37
+ * A payload's `pathname` (renderedLocation) and, when middleware rewrote the
38
+ * request, `rewriteTarget`: the path and search the route rendered (the
39
+ * trail's last URL). The browser keeps it per history entry and sends it
40
+ * back as `_rsc_rt`, so the next request from the page diffs against the
41
+ * route that rendered it (navigation-snapshot.ts resolveNavigation, #1144).
42
+ */
43
+ export declare function payloadLocation(reqCtx: Parameters<typeof renderedLocation>[0], url: URL): {
44
+ pathname: string;
45
+ rewriteTarget?: string;
46
+ };
35
47
  /**
36
48
  * The theme a document payload carries as `metadata.initialTheme` (the
37
49
  * ThemeProvider's first state), read with no identity guard: it is the
@@ -117,6 +117,14 @@ export declare function buildRouteMiddlewareEntries<TEnv>(routeMiddleware: Array
117
117
  entry: MiddlewareEntry<TEnv>;
118
118
  params: Record<string, string>;
119
119
  }>;
120
+ /**
121
+ * The request route middleware sees around the render after a server action
122
+ * or a no-JS form post: the page's GET (URL, headers without body framing or
123
+ * content-type, signal, workerd `cf`; no body). Route middleware never wraps the action,
124
+ * only that render, so it decides as for a GET of the page: a rewrite it
125
+ * skips for mutations still moves the render to its target (#1145).
126
+ */
127
+ export declare function actionRenderRequest(request: Request): Request;
120
128
  /**
121
129
  * Merge stub headers from the request context onto an existing Response in
122
130
  * place, then drain onResponse callbacks. Used when a Response cannot flow
@@ -4,6 +4,26 @@
4
4
  * Builds a fresh route trie from every registered URL-pattern mount for
5
5
  * dev/HMR scenarios where the manifest exists but the trie needs rebuilding.
6
6
  */
7
+ /** True when the trie installed for `router.id` was built from this router. */
8
+ export declare function isRouterTrieBuiltFrom(router: {
9
+ id?: string;
10
+ }): boolean;
11
+ /** The router fields ensureRouterTrie reads. */
12
+ export interface TrieSource {
13
+ id?: string;
14
+ urlpatterns?: unknown;
15
+ routeMap: Record<string, unknown>;
16
+ }
17
+ /**
18
+ * Install the trie `router` matches through, as a request finds it: the build
19
+ * manifest's trie when one is registered for its id, otherwise one built from
20
+ * its routes the way the dev handler builds it (rsc/handler.ts). Ids can repeat
21
+ * across router objects (tests), and another object's trie names other routes,
22
+ * so a trie this object did not build is rebuilt. Seeds the per-router manifest
23
+ * from `router.routeMap` when neither source set one, for reverse(). testing's
24
+ * dispatch matches through it, never the regex fallback alone (#1104, #1107).
25
+ */
26
+ export declare function ensureRouterTrie(router: TrieSource): Promise<void>;
7
27
  /**
8
28
  * Build a fresh route trie from the router's URL-pattern mounts and store it in
9
29
  * the per-router cache. Also sets the per-router manifest and merges into the
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A prefetch whose render reported an error is not kept (#1170).
3
+ *
4
+ * WHY: its 200 left with the headers before a streamed part failed, so the
5
+ * client stored the error boundary as a healthy prefetch, served it to a
6
+ * click and respawned it. The status cannot change any more, and the body
7
+ * cannot end with an error: workerd delivers an errored body as a clean end,
8
+ * and in Chromium the error drops the rows a click that adopted the prefetch
9
+ * has not decoded yet (a Flight "network error" in place of the page).
10
+ *
11
+ * So the body ends cleanly with one more row, PREFETCH_FAILED_ROW, which the
12
+ * Flight decoder skips and teeWithCompletion (browser/response-adapter.ts)
13
+ * reads as a stream that did not end cleanly: the client evicts the prefetch
14
+ * and never respawns it. Prefetch responses carry no Cache-Control, so the
15
+ * browser HTTP cache keeps none of it either.
16
+ *
17
+ * The errors are the render's `_renderErrors`: a Flight error row, a streamed
18
+ * handler recovered into its boundary, a loader that threw (redirect() and
19
+ * notFound() are not errors). Each is recorded before Flight writes the row
20
+ * that carries it, so the list is complete once Flight closes the stream.
21
+ */
22
+ export declare function markPrefetchOnRenderError(response: Response, renderErrors: readonly unknown[]): Response;
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { getRequestContext } from "../server/request-context.js";
9
9
  import type { MiddlewareFn } from "../router/middleware.js";
10
+ import type { ReactFormState } from "./types.js";
11
+ import type { MatchResult } from "../types.js";
10
12
  import type { HandlerContext } from "./handler-context.js";
11
13
  export interface PeRouteMiddlewareInfo {
12
14
  routeMiddleware?: Array<{
@@ -17,3 +19,21 @@ export interface PeRouteMiddlewareInfo {
17
19
  routeReverse?: (name: string, params?: Record<string, string>, search?: Record<string, unknown>) => string;
18
20
  }
19
21
  export declare function handleProgressiveEnhancement<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, isAction: boolean, handleStore: ReturnType<typeof getRequestContext>["_handleStore"], nonce: string | undefined, routeMwInfo?: PeRouteMiddlewareInfo): Promise<Response | null>;
22
+ /** What a no-JS form post's action left for the re-render (`_actionRan`). */
23
+ export interface FormActionOutcome {
24
+ reactFormState: ReactFormState | null;
25
+ directActionId: string | null;
26
+ /** The action threw, or the form body did not parse. */
27
+ failure?: PeFailure;
28
+ }
29
+ /**
30
+ * A failed no-JS form post and the error boundary matched for it. The boundary
31
+ * renders in place of the page, inside route middleware as the JS path renders
32
+ * its own (server-action.ts `errorBoundary`). With none, the page re-renders
33
+ * with 500, the JS path's status for the same boundaryless error.
34
+ */
35
+ export interface PeFailure {
36
+ error: unknown;
37
+ actionId: string | null | undefined;
38
+ boundary: MatchResult | null;
39
+ }
@@ -32,8 +32,18 @@ export interface RewritePass {
32
32
  /**
33
33
  * Move the request context to `rewrite`'s target for the next pass: check
34
34
  * that this request can be rewritten, resolve the target, count the hop,
35
- * then rebase the context. Throws the site error for a mutation or a loader
36
- * fetch, a resolution error, and RewriteLoopError.
35
+ * then rebase the context. Throws the site error for a loader fetch, a
36
+ * refused mutation or one whose body middleware read before its action ran,
37
+ * a resolution error, and RewriteLoopError.
38
+ *
39
+ * A mutation moves too (#1145). Before its action ran (a rewrite from global
40
+ * middleware) it moves with its body, and the target's pass runs the action
41
+ * after the target's global middleware, as a direct post there would. After
42
+ * it ran (route middleware wraps only the re-render), the target's pass
43
+ * re-renders from `reqCtx._actionRan`. `disallowMutations()` refuses the
44
+ * first, so a lock never runs a mutation; the second is already committed,
45
+ * and refusing it reports an error for a write that happened, so the caller
46
+ * retries it.
37
47
  */
38
48
  export declare function applyRewrite(rewrite: Rewrite, passRequest: Request, reqCtx: RequestContext<any>, routeMap: Record<string, string>, basename: string | undefined): RewritePass;
39
49
  /** The response to a rewrite loop. */
@@ -53,6 +53,12 @@ export interface ActionContinuation {
53
53
  * or an ActionContinuation for the revalidation phase.
54
54
  */
55
55
  export declare function executeServerAction<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, actionId: string, handleStore: ReturnType<typeof getRequestContext>["_handleStore"]): Promise<Response | ActionContinuation>;
56
+ /**
57
+ * The continuation for a rewrite pass after the action ran (#1145): a failed
58
+ * action's error boundary is re-matched on the target, since the one pass 1
59
+ * matched (or missed) is the rewriting route's.
60
+ */
61
+ export declare function continuationForRewritePass<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, continuation: ActionContinuation): Promise<ActionContinuation>;
56
62
  /**
57
63
  * Phase 2: Revalidate after action.
58
64
  *
@@ -41,7 +41,7 @@ export declare const PPR_REPLAY_STATUS_HEADER: string;
41
41
  * producer (rsc-rendering.ts) and the parser (testing/shell-status.ts): a
42
42
  * reason the parser does not list parses as null.
43
43
  */
44
- export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit"];
44
+ export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit", "rewritten"];
45
45
  /** One of {@link PPR_REPLAY_BYPASS_REASONS}. */
46
46
  export type PprReplayBypassReason = (typeof PPR_REPLAY_BYPASS_REASONS)[number];
47
47
  /**
@@ -84,6 +84,15 @@ export declare function buildShellKey(routerId: string, url: URL, filter?: Searc
84
84
  * replayed to gold's navigations. Encoded, it holds no `:` or `|`.
85
85
  */
86
86
  export declare function partitionShellKey(key: string, partition: string): string;
87
+ /**
88
+ * The shell key of a `rewrite(...).shell("visitor")` request: the visitor's
89
+ * URL, partitioned by `rw:` + the target's path and search (both searches
90
+ * filtered and sorted, shellSearchSeed). The visitor's URL keeps two public
91
+ * URLs of one target apart; the target keeps a conditional rewrite (an A/B
92
+ * arm, a lock) apart from the URL's own shell. The route's own partition
93
+ * composes after it.
94
+ */
95
+ export declare function visitorShellKey(routerId: string, visitor: URL, target: URL, filter?: SearchParamsFilter): string;
87
96
  /**
88
97
  * The navigation-only entry beside a document shell key (a cold partial
89
98
  * request's capture, rsc-rendering.ts). A suffix after the (encoded)
@@ -330,6 +330,13 @@ export interface ShellCaptureDescriptor {
330
330
  debugSink?: (event: ShellCaptureDebugEvent) => void;
331
331
  /** Store the snapshot for navigation replay, never the captured HTML prelude. */
332
332
  navigationOnly?: true;
333
+ /**
334
+ * Set for a shell keyed by the visitor's URL (`rewrite(...).shell("visitor")`,
335
+ * visitorShellKey): the capture renders the visitor's location
336
+ * (`RequestContext._shellCaptureForVisitor`) and stores it as
337
+ * ShellCacheEntry.pathname.
338
+ */
339
+ pathname?: string;
333
340
  /**
334
341
  * lastStoredCaptureSeq(key) when a document request read the store and
335
342
  * missed. The request schedules its capture only after rendering the MISS,
@@ -16,6 +16,11 @@ import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
16
16
  export interface RscPayload {
17
17
  metadata?: {
18
18
  pathname: string;
19
+ /**
20
+ * Path and search of the URL the route rendered for, when middleware
21
+ * rewrote the request there (full-payload.ts payloadLocation).
22
+ */
23
+ rewriteTarget?: string;
19
24
  segments: ResolvedSegment[];
20
25
  /** Router instance ID. When this changes between navigations, the client
21
26
  * discards cached segments and does a full tree replacement (app switch). */
@@ -1,6 +1,21 @@
1
1
  import { type ReactNode, type ComponentType } from "react";
2
2
  import type { ResolvedSegment, RootLayoutProps } from "./types.js";
3
3
  export declare function restoreParallelLoaderMarkers(segments: ResolvedSegment[]): ResolvedSegment[];
4
+ /**
5
+ * An intercept's loaders arrive as loader segments of its slot
6
+ * (`${slot.id}D${i}.${$$id}`, router/intercept-resolution.ts). Folded back
7
+ * onto the slot before the tree walk, as one aggregate the slot's
8
+ * LoaderBoundary reads (client.tsx renderSlotContent): walked as loaders they
9
+ * would attach to the slot's parent, whose subtree (the page under the modal)
10
+ * would change shape and remount. Any other loader segment passes through; a
11
+ * list with nothing to fold is returned as it is, synchronously.
12
+ * The slot is a new object (rule 6, suspense-contract.md); its aggregate is
13
+ * memoized on the loaders' data (rule 1). Settled before the commit when
14
+ * nothing in it is deferred and the slot has no loading() or the lane settles
15
+ * loaders (forceAwait, action): a modal with no loading() commits whole, as
16
+ * when the server awaited its loaders.
17
+ */
18
+ export declare function foldInterceptLoaders(segments: ResolvedSegment[], settleLoaders: boolean): ResolvedSegment[] | Promise<ResolvedSegment[]>;
4
19
  /**
5
20
  * Options for renderSegments
6
21
  */
@@ -61,6 +61,12 @@ export type EntryPropCommon = {
61
61
  cache?: EntryCacheConfig;
62
62
  /** URL prefix from include() scope, used for MountContext on client */
63
63
  mountPath?: string;
64
+ /**
65
+ * Include scope the entry's handler and loaders resolve `ctx.reverse(".name")`
66
+ * in. Structural entries only (layout, cache, parallel, wrapping
67
+ * middleware); a route resolves from its own name. See ReverseScope.
68
+ */
69
+ reverseScope?: ReverseScope;
64
70
  /** clientUrls() group key (PathOptions.clientGroup); route entries only. */
65
71
  clientGroup?: string;
66
72
  };
@@ -129,6 +135,13 @@ export type LoaderEntry = {
129
135
  * (router/segment-resolution/prefetch-deferral.ts).
130
136
  */
131
137
  prefetch?: false;
138
+ /**
139
+ * The declaring layout's / parallel's / cache()'s include scope, for the
140
+ * loader body's `ctx.reverse(".name")` (its DSL kickoff carries it,
141
+ * runInsideLoaderScope). Unset on a route's loaders: they resolve from the
142
+ * route's name.
143
+ */
144
+ reverseScope?: ReverseScope;
132
145
  };
133
146
  /**
134
147
  * Segments state for intercept context
@@ -192,7 +205,6 @@ export type InterceptEntry = {
192
205
  slotName: `@${string}`;
193
206
  routeName: string;
194
207
  handler: ReactNode | Handler<any, any, any>;
195
- middleware: MiddlewareFn<any, any>[];
196
208
  loader: LoaderEntry[];
197
209
  loading?: ReactNode | false;
198
210
  transition?: TransitionConfig;
@@ -267,10 +279,21 @@ export type EntryData = ({
267
279
  /** Cache entries create cache boundaries and render like layouts (with Outlet) */
268
280
  handler: ReactNode | Handler<any, any, any>;
269
281
  } & EntryPropCommon & EntryPropDatas & EntryPropSegments & EntryPropRender);
282
+ /**
283
+ * Where an include()'s handler runs in the route tree. Hidden include-scope
284
+ * names (`$prefix_*`) derive from it, never from counter state, so build
285
+ * discovery and runtime expansion name every include the same (#1104).
286
+ */
287
+ export interface IncludeScopePosition {
288
+ /** Sibling indexes of the enclosing includes, "_"-joined ("" at a mount root). */
289
+ scopePath?: string;
290
+ /** The scopePath tail since the nearest include that added a name segment. */
291
+ hiddenScopePath?: string;
292
+ }
270
293
  /**
271
294
  * Tracked include info for build-time manifest generation
272
295
  */
273
- export interface TrackedInclude {
296
+ export interface TrackedInclude extends IncludeScopePosition {
274
297
  prefix: string;
275
298
  fullPrefix: string;
276
299
  namePrefix?: string;
@@ -290,7 +313,7 @@ export type CachedHeaderScope = {
290
313
  /**
291
314
  * Context stored in AsyncLocalStorage
292
315
  */
293
- interface HelperContext {
316
+ interface HelperContext extends IncludeScopePosition {
294
317
  manifest: Map<string, EntryData>;
295
318
  namespace: string;
296
319
  parent: EntryData | null;
@@ -399,6 +422,37 @@ export declare function getNamePrefix(): string | undefined;
399
422
  * Returns true at root or inside { name: "" } includes, false inside named includes.
400
423
  */
401
424
  export declare function getRootScoped(): boolean;
425
+ /**
426
+ * The include scope a segment's dot-local `ctx.reverse(".name")` resolves in.
427
+ *
428
+ * One handler ctx serves every segment of a request and is built from the
429
+ * matched route's name (match-api.ts), so a parent module's layout resolved
430
+ * `.settings` from the matched CHILD module's prefix first: on
431
+ * `/acme/web/issues` the account layout's `.settings` hit the project
432
+ * module's route. Structural entries (layout, cache, parallel, wrapping
433
+ * middleware) and the loaders they declare capture the scope where the DSL
434
+ * defined them. Their handler gets a ctx whose `reverse` carries it
435
+ * (withReverseScope, router/handler-context.ts), and their loaders' DSL
436
+ * kickoff carries it in the loader scope (runInsideLoaderScope) for the
437
+ * loader ctx the executor builds. Global names and mount-param autofill do
438
+ * not change.
439
+ */
440
+ export interface ReverseScope {
441
+ /** Include name prefix ("account.project"); undefined outside named includes. */
442
+ readonly prefix: string | undefined;
443
+ /** getRootScoped() where the segment was defined: bare-name fallback allowed. */
444
+ readonly rootScoped: boolean;
445
+ }
446
+ /** The ReverseScope of the DSL position being evaluated. */
447
+ export declare function getReverseScope(): ReverseScope;
448
+ /**
449
+ * A createReverseFunction result (router/handler-context.ts). The internal
450
+ * 4th argument resolves dot names in a segment's ReverseScope instead of the
451
+ * route's name.
452
+ */
453
+ export type ScopableReverse = (name: string, hrefParams?: Record<string, string>, search?: Record<string, unknown>, segmentScope?: ReverseScope) => string;
454
+ /** `reverse` with dot names resolved in `scope`, if any. */
455
+ export declare function scopeReverse(reverse: ScopableReverse, scope: ReverseScope | undefined): ScopableReverse;
402
456
  /**
403
457
  * Stamp build-time scope identity onto a Static() definition at mount time.
404
458
  * The bake collector (prerender-collection.ts) renders defs OUTSIDE any
@@ -689,7 +743,13 @@ export declare function assertCachedHeaderWriteAllowed(surface: string, surfaceP
689
743
  * are bypassed because loaders are always fresh (never cached) and
690
744
  * their side effects (setCookie, header, etc.) are safe.
691
745
  */
692
- export declare function runInsideLoaderScope<T>(fn: () => T, loaderId?: string): T;
746
+ export declare function runInsideLoaderScope<T>(fn: () => T, loaderId?: string, reverseScope?: ReverseScope): T;
747
+ /**
748
+ * The ReverseScope of the DSL loader kickoff around this call: a loader the
749
+ * kickoff starts, and one its body starts with ctx.use(), resolve dot names
750
+ * in it. A handler's ctx.use(Loader) runs outside any kickoff: none.
751
+ */
752
+ export declare function getLoaderReverseScope(): ReverseScope | undefined;
693
753
  /**
694
754
  * The loader whose run a handle push here belongs to, for the browser's
695
755
  * merge of a partial response (handles/pushed-by.ts): the DSL loader