@rangojs/router 0.31.0 → 0.33.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 (192) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/browser-7KIJ5HSV.js +15 -0
  3. package/dist/bin/chunk-3B7CKBRO.js +463 -0
  4. package/dist/bin/chunk-524VACCG.js +71 -0
  5. package/dist/bin/chunk-LD7UBHT4.js +196 -0
  6. package/dist/bin/chunk-TO6CRWLN.js +1429 -0
  7. package/dist/bin/chunk-TTXC2U3G.js +2477 -0
  8. package/dist/bin/client-urls-projection-DQLWPDAT.js +28 -0
  9. package/dist/bin/forward-user-plugins-URBZKJP4.js +62 -0
  10. package/dist/bin/rango.js +42 -10143
  11. package/dist/bin/runtime-EPUDEHO4.js +596 -0
  12. package/dist/bin/runtime-discovery-CZ2QHT4Q.js +352 -0
  13. package/dist/bin/state-ACD2MGKJ.js +16 -0
  14. package/dist/bin/temp-rsc-server-QRR6HD6T.js +3190 -0
  15. package/dist/types/bin/rango.d.ts +1 -0
  16. package/dist/types/browser/action-fence.d.ts +20 -0
  17. package/dist/types/browser/cookie-name.d.ts +51 -10
  18. package/dist/types/browser/history-state.d.ts +13 -2
  19. package/dist/types/browser/invalidate-client-cache.d.ts +8 -6
  20. package/dist/types/browser/navigation-bridge.d.ts +36 -1
  21. package/dist/types/browser/navigation-client.d.ts +19 -0
  22. package/dist/types/browser/navigation-store-handle.d.ts +37 -4
  23. package/dist/types/browser/navigation-store.d.ts +2 -2
  24. package/dist/types/browser/navigation-transaction.d.ts +0 -1
  25. package/dist/types/browser/partial-update.d.ts +13 -0
  26. package/dist/types/browser/prefetch/cache.d.ts +96 -8
  27. package/dist/types/browser/prefetch/fetch.d.ts +26 -2
  28. package/dist/types/browser/prefetch/queue.d.ts +3 -2
  29. package/dist/types/browser/rango-state.d.ts +34 -5
  30. package/dist/types/browser/react/Link.d.ts +19 -13
  31. package/dist/types/browser/react/location-state-shared.d.ts +2 -1
  32. package/dist/types/browser/types.d.ts +25 -0
  33. package/dist/types/build/generate-route-types.d.ts +1 -1
  34. package/dist/types/build/route-types/include-resolution.d.ts +9 -1
  35. package/dist/types/build/route-types/router-processing.d.ts +3 -1
  36. package/dist/types/cache/cache-key-utils.d.ts +12 -8
  37. package/dist/types/cache/cache-scope.d.ts +4 -2
  38. package/dist/types/cache/cf/cf-cache-types.d.ts +9 -5
  39. package/dist/types/cache/document-cache-policy.d.ts +9 -1
  40. package/dist/types/cache/memory-segment-store.d.ts +3 -2
  41. package/dist/types/cache/segment-codec.d.ts +2 -2
  42. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  43. package/dist/types/cache/types.d.ts +12 -7
  44. package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -1
  45. package/dist/types/client-urls/types.d.ts +7 -5
  46. package/dist/types/prefetch-markers.d.ts +9 -0
  47. package/dist/types/prefetch-source-scope.d.ts +66 -0
  48. package/dist/types/route-definition/helpers-types.d.ts +8 -5
  49. package/dist/types/route-definition/redirect.d.ts +5 -0
  50. package/dist/types/router/intercept-resolution.d.ts +25 -11
  51. package/dist/types/router/match-context.d.ts +1 -0
  52. package/dist/types/router/match-handlers.d.ts +1 -1
  53. package/dist/types/router/middleware-types.d.ts +6 -0
  54. package/dist/types/router/prefetch-cache-ttl.d.ts +11 -3
  55. package/dist/types/router/router-context.d.ts +1 -1
  56. package/dist/types/router/router-options.d.ts +6 -3
  57. package/dist/types/router/segment-resolution/loader-cache.d.ts +8 -0
  58. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +23 -7
  59. package/dist/types/router/segment-resolution/revalidation.d.ts +19 -0
  60. package/dist/types/router/source-reads.d.ts +53 -0
  61. package/dist/types/router/types.d.ts +1 -1
  62. package/dist/types/rsc/helpers.d.ts +8 -3
  63. package/dist/types/rsc/prefetch-render-error.d.ts +7 -2
  64. package/dist/types/rsc/request-stages.d.ts +4 -0
  65. package/dist/types/rsc/shell-serve.d.ts +6 -1
  66. package/dist/types/server/context.d.ts +23 -6
  67. package/dist/types/server/cookie-store.d.ts +15 -1
  68. package/dist/types/server/document-location-state.d.ts +59 -0
  69. package/dist/types/server/handle-store.d.ts +2 -0
  70. package/dist/types/server/request-context.d.ts +65 -12
  71. package/dist/types/testing/e2e/server.d.ts +16 -1
  72. package/dist/types/testing/render-route.d.ts +83 -2
  73. package/dist/types/testing/serve-shell-request.d.ts +15 -3
  74. package/dist/types/types/handler-context.d.ts +21 -4
  75. package/dist/types/types/loader-types.d.ts +7 -4
  76. package/dist/types/types/segments.d.ts +18 -1
  77. package/dist/types/urls/path-helper-types.d.ts +7 -5
  78. package/dist/types/vite/temp-rsc-server.d.ts +2 -2
  79. package/dist/types/vite/utils/forward-user-plugins.d.ts +32 -2
  80. package/dist/vite/index.js +451 -191
  81. package/package.json +2 -2
  82. package/skills/app-structure/SKILL.md +74 -0
  83. package/skills/app-structure/e-commerce.md +10 -9
  84. package/skills/app-structure/large-app.md +15 -2
  85. package/skills/caching/SKILL.md +10 -5
  86. package/skills/client-urls/SKILL.md +18 -11
  87. package/skills/comparison/references/framework-comparison.md +16 -10
  88. package/skills/document-cache/SKILL.md +13 -0
  89. package/skills/hooks/navigation.md +8 -8
  90. package/skills/hooks/state.md +132 -12
  91. package/skills/intercept/SKILL.md +33 -11
  92. package/skills/layout/SKILL.md +11 -0
  93. package/skills/links/SKILL.md +101 -4
  94. package/skills/loader/SKILL.md +49 -22
  95. package/skills/migrate-nextjs/SKILL.md +8 -2
  96. package/skills/migrate-react-router/data-and-actions.md +5 -0
  97. package/skills/ppr/SKILL.md +38 -5
  98. package/skills/prerender/SKILL.md +4 -1
  99. package/skills/route/SKILL.md +6 -6
  100. package/skills/router-setup/SKILL.md +2 -1
  101. package/skills/server-actions/SKILL.md +49 -8
  102. package/skills/testing/client-components.md +73 -32
  103. package/skills/testing/serve-shell-request.md +45 -20
  104. package/skills/testing/server-actions.md +8 -0
  105. package/skills/ux-architecture/SKILL.md +67 -15
  106. package/src/bin/rango.ts +39 -13
  107. package/src/browser/action-fence.ts +72 -0
  108. package/src/browser/cookie-name.ts +82 -14
  109. package/src/browser/history-state.ts +24 -2
  110. package/src/browser/invalidate-client-cache.ts +9 -7
  111. package/src/browser/navigation-bridge.ts +164 -32
  112. package/src/browser/navigation-client.ts +95 -20
  113. package/src/browser/navigation-store-handle.ts +67 -5
  114. package/src/browser/navigation-store.ts +86 -17
  115. package/src/browser/navigation-transaction.ts +0 -6
  116. package/src/browser/partial-update.ts +31 -12
  117. package/src/browser/prefetch/cache.ts +188 -11
  118. package/src/browser/prefetch/fetch.ts +211 -51
  119. package/src/browser/prefetch/queue.ts +3 -2
  120. package/src/browser/rango-state.ts +50 -8
  121. package/src/browser/react/Link.tsx +24 -16
  122. package/src/browser/react/location-state-shared.ts +8 -1
  123. package/src/browser/react/use-navigation.ts +1 -1
  124. package/src/browser/rsc-router.tsx +13 -3
  125. package/src/browser/server-action-bridge.ts +3 -3
  126. package/src/browser/types.ts +25 -0
  127. package/src/build/generate-route-types.ts +1 -0
  128. package/src/build/route-types/include-resolution.ts +40 -3
  129. package/src/build/route-types/router-processing.ts +170 -25
  130. package/src/build/route-types/scan-filter.ts +1 -0
  131. package/src/build/runtime-discovery.ts +46 -8
  132. package/src/cache/cache-key-utils.ts +12 -8
  133. package/src/cache/cache-runtime.ts +5 -1
  134. package/src/cache/cache-scope.ts +28 -7
  135. package/src/cache/cf/cf-cache-types.ts +9 -5
  136. package/src/cache/document-cache-policy.ts +37 -1
  137. package/src/cache/document-cache.ts +12 -0
  138. package/src/cache/memory-segment-store.ts +3 -2
  139. package/src/cache/segment-codec.ts +2 -2
  140. package/src/cache/shell-snapshot.ts +1 -1
  141. package/src/cache/types.ts +12 -7
  142. package/src/cache/vercel/vercel-cache-store.ts +2 -1
  143. package/src/client-urls/types.ts +7 -5
  144. package/src/prefetch-markers.ts +10 -0
  145. package/src/prefetch-source-scope.ts +137 -0
  146. package/src/route-definition/helpers-types.ts +8 -5
  147. package/src/route-definition/redirect.ts +5 -0
  148. package/src/router/intercept-resolution.ts +94 -50
  149. package/src/router/loader-resolution.ts +8 -6
  150. package/src/router/match-api.ts +33 -29
  151. package/src/router/match-context.ts +5 -0
  152. package/src/router/match-handlers.ts +2 -1
  153. package/src/router/match-middleware/cache-lookup.ts +39 -14
  154. package/src/router/match-result.ts +45 -85
  155. package/src/router/middleware-types.ts +6 -0
  156. package/src/router/navigation-snapshot.ts +18 -3
  157. package/src/router/prefetch-cache-ttl.ts +15 -3
  158. package/src/router/revalidation.ts +63 -13
  159. package/src/router/router-context.ts +2 -1
  160. package/src/router/router-options.ts +6 -3
  161. package/src/router/segment-resolution/loader-cache.ts +21 -3
  162. package/src/router/segment-resolution/prefetch-deferral.ts +38 -31
  163. package/src/router/segment-resolution/revalidation.ts +40 -12
  164. package/src/router/source-reads.ts +122 -0
  165. package/src/router/types.ts +2 -1
  166. package/src/router.ts +11 -12
  167. package/src/rsc/helpers.ts +20 -6
  168. package/src/rsc/prefetch-render-error.ts +7 -2
  169. package/src/rsc/progressive-enhancement.ts +8 -2
  170. package/src/rsc/request-stages.ts +87 -1
  171. package/src/rsc/rsc-rendering.ts +78 -32
  172. package/src/rsc/server-action.ts +2 -1
  173. package/src/rsc/shell-capture.ts +4 -5
  174. package/src/rsc/shell-serve.ts +12 -1
  175. package/src/segment-system.tsx +1 -1
  176. package/src/server/context.ts +37 -6
  177. package/src/server/cookie-store.ts +22 -1
  178. package/src/server/document-location-state.ts +334 -0
  179. package/src/server/handle-store.ts +2 -0
  180. package/src/server/request-context.ts +137 -33
  181. package/src/testing/dispatch.ts +6 -0
  182. package/src/testing/e2e/fixture.ts +4 -12
  183. package/src/testing/e2e/server.ts +91 -4
  184. package/src/testing/render-route.tsx +309 -10
  185. package/src/testing/run-revalidate.ts +11 -1
  186. package/src/testing/serve-shell-request.ts +22 -3
  187. package/src/types/handler-context.ts +21 -4
  188. package/src/types/loader-types.ts +7 -4
  189. package/src/types/segments.ts +18 -1
  190. package/src/urls/path-helper-types.ts +7 -5
  191. package/src/vite/temp-rsc-server.ts +2 -2
  192. package/src/vite/utils/forward-user-plugins.ts +13 -5
@@ -31,6 +31,7 @@ import type { RoutineTrace } from "../rsc/routine-plan.js";
31
31
  import type { ActionContinuation } from "../rsc/server-action.js";
32
32
  import type { ShellCaptureState } from "../rsc/shell-capture.js";
33
33
  import type { FormActionOutcome } from "../rsc/progressive-enhancement.js";
34
+ import { type RequestKind } from "../router/segment-resolution/prefetch-deferral.js";
34
35
  import { type ExecutionStart } from "../cache/invalidation-order.js";
35
36
  export interface RenderForegroundCursor {
36
37
  mode: RenderMode;
@@ -119,8 +120,12 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
119
120
  setStatus(status: number): void;
120
121
  /** @internal Set status bypassing cache-exec guard (for framework error handling) */
121
122
  _setStatus(status: number): void;
122
- /** @internal Rotate the rango state cookie (server seat of invalidateClientCache). */
123
- _rotateStateCookie(): void;
123
+ /**
124
+ * @internal Rotate the rango state cookie: its timestamp (the server seat of
125
+ * invalidateClientCache), or with `"write"` only its write part (a server
126
+ * action without a directive, cookie-store.ts runActionBody).
127
+ */
128
+ _rotateStateCookie(part?: "write"): void;
124
129
  /** @internal Set the keepClientCache() directive header on the response. */
125
130
  _setKeepCacheDirective(): void;
126
131
  /**
@@ -532,11 +537,28 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
532
537
  */
533
538
  _payloadDeferred?: boolean;
534
539
  /**
535
- * @internal What the request says it is: a `<Link>` prefetch or a fill
536
- * (`prefetch: false`), read once at creation
537
- * (segment-resolution/prefetch-deferral.ts requestKind).
540
+ * @internal Set by the RSC handler when a partial response carries an
541
+ * `x-rsc-prefetch-scope` (router/source-reads.ts prefetchScopeOf): its diff
542
+ * is right for its source page, or a group of them, only. The document
543
+ * cache keys a partial without its source, so it does not store that
544
+ * response, whatever Cache-Control it ends up with.
545
+ */
546
+ _payloadSourceScoped?: boolean;
547
+ /**
548
+ * @internal Set when the answer has nothing live in it, so nothing in it can
549
+ * fail after the 200's headers left: the document cache middleware on a
550
+ * fresh HIT, and the RSC handler when the partial match came from storage
551
+ * (MatchResult.fromStorage). finalizeRequestResponse (rsc/request-stages.ts)
552
+ * sends such a prefetch the router's prefetch Cache-Control.
553
+ */
554
+ _servedFromStorage?: boolean;
555
+ /**
556
+ * @internal What the request says it is: a speculative `<Link>` prefetch,
557
+ * an intent prefetch (hover, `prefetch()`) or a fill (`prefetch: false`),
558
+ * read once at creation (segment-resolution/prefetch-deferral.ts
559
+ * requestKind).
538
560
  */
539
- _requestKind?: "prefetch" | "fill";
561
+ _requestKind?: RequestKind;
540
562
  /**
541
563
  * @internal Set when a render shows the visitor's URL of a rewritten
542
564
  * request: the payload or SSR seed (renderedLocation, rsc/full-payload.ts)
@@ -547,12 +569,27 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
547
569
  /**
548
570
  * Attach location state entries to the current response.
549
571
  *
550
- * For partial (SPA) requests, the state is included in the RSC payload
551
- * metadata and merged into history.pushState on the client. For redirect
552
- * responses, the state travels through the redirect payload so the target
553
- * page can read it via useLocationState.
572
+ * For a client navigation or an action, the state is included in the RSC
573
+ * payload metadata and merged into the entry's history.state on the
574
+ * client. For a document request (a page load, a no-JS form post), it rides
575
+ * the document's bootstrap payload and is merged into the entry when the
576
+ * client starts; readers get it once the page has hydrated. For a redirect,
577
+ * the state travels with the redirect: in its Flight payload on a
578
+ * navigation or action, in a one-shot cookie the target's document request
579
+ * reads on a document request. A document that carries state is sent
580
+ * `Cache-Control: private, no-store` and never stored by the document cache
581
+ * or as a PPR shell.
554
582
  *
555
- * Multiple calls accumulate entries.
583
+ * Call it from middleware, a handler or an action. A loader's call
584
+ * (through `getRequestContext()`) is not supported: the payload takes the
585
+ * state before loaders settle, so the write may be dropped, and a PPR
586
+ * shell HIT never sends it.
587
+ *
588
+ * Multiple calls accumulate entries across definitions. For one definition
589
+ * the last write wins: two entries of the same definition share its slot
590
+ * in history.state, so a later call (or a later entry in one array)
591
+ * replaces an earlier one. To combine writes, make the state an array and
592
+ * write it once.
556
593
  *
557
594
  * @example
558
595
  * ```typescript
@@ -562,6 +599,22 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
562
599
  setLocationState(entries: LocationStateEntry | LocationStateEntry[]): void;
563
600
  /** @internal Accumulated location state entries */
564
601
  _locationState?: LocationStateEntry[];
602
+ /**
603
+ * @internal Set when a document's payload carries location state
604
+ * (rsc/rsc-rendering.ts, rsc/progressive-enhancement.ts), a shell HIT's
605
+ * included. The document is per visitor: the document cache refuses it,
606
+ * and it leaves `private, no-store` (server/document-location-state.ts).
607
+ */
608
+ _documentLocationState?: boolean;
609
+ /**
610
+ * @internal The `document.cookie` line that re-creates the location state
611
+ * cookie this request consumed (server/document-location-state.ts). The
612
+ * consuming response clears the cookie in its headers; a shell HIT that
613
+ * degrades into a reload after those headers left writes this line first
614
+ * (rsc/shell-serve.ts shellReloadScript), so the reload reads the state
615
+ * again.
616
+ */
617
+ _carriedLocationStateCookie?: string;
565
618
  /**
566
619
  * The matched route name, if the route has an explicit name.
567
620
  * Undefined before route matching or for unnamed routes.
@@ -795,7 +848,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
795
848
  * This is the type exported to library consumers. Internal code should
796
849
  * use the full RequestContext interface directly.
797
850
  */
798
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureState" | "_shellImplicitCache" | "_shellLoaderSeed" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_shellFragmentPayload" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_throwers" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_handlerTiming" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
851
+ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureState" | "_shellImplicitCache" | "_shellLoaderSeed" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_shellFragmentPayload" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_payloadSourceScoped" | "_servedFromStorage" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_documentLocationState" | "_carriedLocationStateCookie" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_throwers" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_handlerTiming" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
799
852
  /**
800
853
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
801
854
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -11,7 +11,13 @@ export interface RunCliHandle {
11
11
  */
12
12
  exitCode: Promise<number | null>;
13
13
  findPort: (timeoutMs?: number) => Promise<number>;
14
- kill: () => void;
14
+ /**
15
+ * Stop the process and what it spawned (the whole process group). SIGTERM by
16
+ * default; `stopServer` escalates to SIGKILL for a process that outlives the
17
+ * wait.
18
+ */
19
+ kill: (signal?: NodeJS.Signals) => void;
20
+ readonly pid: number | undefined;
15
21
  stdout: () => string;
16
22
  stderr: () => string;
17
23
  }
@@ -19,6 +25,15 @@ export declare function runCli(options: {
19
25
  command: string;
20
26
  label?: string;
21
27
  } & SpawnOptions): RunCliHandle;
28
+ /**
29
+ * Stop a server started by `runCli` and wait for its whole process group to
30
+ * exit: SIGTERM to the group, then SIGKILL (and a log naming the pid) for a
31
+ * process that outlives the wait, so a leaked server is visible rather than
32
+ * left holding its port.
33
+ */
34
+ export declare function stopServer(server: RunCliHandle, options?: {
35
+ exitWaitMs?: number;
36
+ }): Promise<void>;
22
37
  export declare function tailOutput(text: string, maxChars?: number): string;
23
38
  export declare function createIsolatedViteCacheDir(cwd: string, projectName: string, mode: "dev" | "build" | undefined): string;
24
39
  export declare function waitForReady(url: string, getOutput?: () => {
@@ -35,6 +35,16 @@
35
35
  * not modeled). navigate(url, { streamUntil }) gives the navigation a
36
36
  * response stream that stays open past the commit (isStreaming).
37
37
  * useAction().state stays idle: no action runs.
38
+ * - prefetch(url) keeps a page as a prefetch made now carries it, and
39
+ * action() lands a server action's response: the page on screen
40
+ * re-renders with its post-write loader data, and, without
41
+ * `keepClientCache`, production's store marks every history entry and
42
+ * prefetch stale (browser/navigation-store.ts). A navigate(url) to a
43
+ * prefetched page commits the prefetch's data; when an action made it
44
+ * stale, the page then revalidates once the navigation settled, in the
45
+ * lane production's Back uses (useNavigation() idle), with the loader
46
+ * data current then. The prefetch request, its decode and the HTTP cache
47
+ * are e2e territory.
38
48
  * - A spec's transition({ when }) decides every commit with production's
39
49
  * browser decision: navigate() and useRouter().push model kind "push",
40
50
  * useRouter().replace kind "replace", refresh() kind "revalidate", and a
@@ -49,8 +59,8 @@
49
59
  * written there, and another page is on screen, its page is restored
50
60
  * from the history cache, with the handle values it had, as production's
51
61
  * restore is; otherwise the tree keeps its location. A stale entry's
52
- * revalidation, a restore that fetches, a server action's state, a
53
- * redirect's and an intercept's are e2e territory.
62
+ * revalidation on Back, a restore that fetches, a server action's
63
+ * location state, a redirect's and an intercept's are e2e territory.
54
64
  * What it DOES cover: client hooks that read NavigationProvider /
55
65
  * OutletContext — useParams, useReverse, useHref, useMount, useNavigation,
56
66
  * useRouter, usePathname, useSearchParams, Outlet/useOutlet nesting and seeded
@@ -185,6 +195,23 @@ export interface RenderRouteOptions {
185
195
  * });
186
196
  */
187
197
  locationState?: ReadonlyArray<readonly [LocationStateDefinition<any, any>, unknown]>;
198
+ /**
199
+ * Location state the document response carries, as `[def, value]` pairs:
200
+ * what a handler, middleware or no-JS form action set with
201
+ * `ctx.setLocationState()` (or a document redirect carried) for this page
202
+ * load. Merged into the entry at start-up as initBrowserApp merges the
203
+ * bootstrap payload's: after `locationState` and, with `hydrate: true`,
204
+ * after the `clearOnReload` pass, so a `clearOnReload` slot given here is
205
+ * applied. With `hydrate: true` a reader hydrates as `undefined` and gets
206
+ * the value once the root has hydrated.
207
+ *
208
+ * @example
209
+ * await renderRoute([{ path: "/", Component: FlashBanner }], {
210
+ * hydrate: true,
211
+ * documentLocationState: [[FlashMessage, { text: "Payment declined" }]],
212
+ * });
213
+ */
214
+ documentLocationState?: ReadonlyArray<readonly [LocationStateDefinition<any, any>, unknown]>;
188
215
  /**
189
216
  * Handles to seed by REFERENCE, for components that read handle output via
190
217
  * `useHandle(SomeHandle)` (e.g. a client `Breadcrumbs` trail). Each entry is
@@ -403,6 +430,60 @@ export interface TestRouterHandle {
403
430
  * transition({ when }) decides it with kind "revalidate" (`to` is `from`).
404
431
  */
405
432
  refresh(): Promise<void>;
433
+ /**
434
+ * Prefetch `url`, as a `<Link>` hover or viewport trigger does: the page is
435
+ * kept with the loader data its response would carry now (the render-time
436
+ * seeds, `options.loaders` merged over). A later `navigate(url)` without
437
+ * `loaders` commits that data, whatever the seeds are by then.
438
+ *
439
+ * The prefetch is stamped with production's stale epoch
440
+ * (browser/prefetch/cache.ts): an `action()` without `keepClientCache`
441
+ * makes it stale. A click on a stale prefetch commits it at once, then the
442
+ * page revalidates once the navigation settled (its `streamUntil` ended),
443
+ * in Back's stale-revalidation lane: `useNavigation().state` stays "idle"
444
+ * and `isNavigating` reads true while its request is open, `useLinkStatus`
445
+ * shows no pending state, and the commit runs through commitInTransition
446
+ * with kind "revalidate", reading the loader data current then. A newer
447
+ * navigation aborts it.
448
+ *
449
+ * @example
450
+ * router.prefetch("/cart"); // carries count 2
451
+ * await router.action({ loaders: [[BasketLoader, { count: 3 }]] });
452
+ * await router.navigate("/cart"); // count 2, at once
453
+ * await waitFor(() => expect(count()).toBe("3")); // revalidated
454
+ */
455
+ prefetch(url: string, options?: Pick<RenderRouteOptions, "loaders">): void;
456
+ /**
457
+ * Land a server action's response on the page on screen. `loaders` are the
458
+ * loader values after the action's write: they become the data every
459
+ * later response carries, and the page on screen re-renders with them in
460
+ * the action lane (commitInTransition, kind "action", unless
461
+ * transition({ when }) gates it off). Without `keepClientCache`,
462
+ * production's store then marks every history entry and every prefetch
463
+ * stale (`markCacheAsStaleAndBroadcast()`), as the action bridge does:
464
+ * nothing is flushed and the state cookie is not rotated.
465
+ * `keepClientCache: true` is the `keepClientCache()` directive: caches stay
466
+ * fresh. The action's own lifecycle (`useAction()`), its follow-up and its
467
+ * redirect are e2e territory.
468
+ */
469
+ action(options?: Pick<RenderRouteOptions, "loaders"> & {
470
+ keepClientCache?: boolean;
471
+ }): Promise<void>;
472
+ /**
473
+ * The background revalidations a click on a stale prefetch started, in
474
+ * order: the page's pathname and search, and the segment ids the request
475
+ * holds, as production's bridge plans them
476
+ * (navigation-bridge.ts scheduleStalePrefetchRevalidation). A click on a
477
+ * fresh prefetch, or after a `keepClientCache` action, starts none.
478
+ *
479
+ * @example
480
+ * await router.navigate("/cart"); // a stale prefetch
481
+ * await waitFor(() => expect(router.revalidations()).toHaveLength(1));
482
+ */
483
+ revalidations(): ReadonlyArray<{
484
+ url: string;
485
+ segmentIds: string[];
486
+ }>;
406
487
  /** The current committed pathname. */
407
488
  pathname(): string;
408
489
  /** The current committed params. */
@@ -65,9 +65,12 @@ export interface ServeShellRequestOptions<TEnv = any> {
65
65
  * (default none), advertising fragment passthrough. The replay decision is
66
66
  * `result.replayStatus`.
67
67
  *
68
- * `prefetch: true` sends it as a `<Link>` prefetch does (the
69
- * `X-Rango-Prefetch` header), so `prefetch: false` loaders and `loading()`
70
- * entries are deferred: `result.readDeferred()` lists them. `fill: true`
68
+ * `prefetch: true` sends the speculative kind a viewport or render
69
+ * `<Link>` prefetch sends (`X-Rango-Prefetch: 1`), so `prefetch: false`
70
+ * loaders and `loading()` entries are deferred: `result.readDeferred()`
71
+ * lists them. A hover's or `prefetch()`'s intent prefetch defers nothing;
72
+ * serve it with `prefetch: true` and `headers: { "X-Rango-Prefetch":
73
+ * "intent" }`, which `prefetch: true` leaves as given. `fill: true`
71
74
  * sends the request the browser follows an adopted prefetch with
72
75
  * (`_rsc_fill`): pass the ids the prefetch delivered, without the deferred
73
76
  * ones, as `segments`, and the same URL as `from`. `interceptSource` sends
@@ -229,6 +232,15 @@ export interface ServeShellRequestResult {
229
232
  * hydrates without it.
230
233
  */
231
234
  readPayloadFormState(): Promise<unknown>;
235
+ /**
236
+ * The payload's location state as the browser reads it: the slots
237
+ * (`Def.__rsc_ls_key` to value) a document's start-up merges into its
238
+ * entry (or a navigation's commit, for a `partial` request). Undefined when
239
+ * the payload carries none (or no Flight was rendered). A redirect carries
240
+ * a document request's state in a `Set-Cookie` instead: pass that cookie
241
+ * on the request of its target to read what the target's payload carries.
242
+ */
243
+ readLocationState(): Promise<Record<string, unknown> | undefined>;
232
244
  /**
233
245
  * For an `action` request, the call's answer as the browser reads it: its
234
246
  * result and the `revalidationError` its loaders' reruns report.
@@ -274,9 +274,16 @@ export type HandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch extends Sear
274
274
  */
275
275
  setTheme?: (theme: Theme) => void;
276
276
  /**
277
- * Attach location state entries to this response.
278
- * State is delivered to the client via history.pushState and accessible
279
- * through the useLocationState() hook.
277
+ * Attach location state entries to this response, for the useLocationState()
278
+ * hook to read on the entry this response renders. A client navigation
279
+ * delivers it with its payload; a document load (a link from outside the
280
+ * app, a no-JS form post) with its bootstrap payload, once the page has
281
+ * hydrated; a redirect carries it to its target (in a one-shot cookie on a
282
+ * document request). A document carrying it is sent
283
+ * `Cache-Control: private, no-store`.
284
+ *
285
+ * Entries accumulate across definitions; for one definition the last write
286
+ * wins (an earlier entry of it is replaced, not merged).
280
287
  *
281
288
  * @example
282
289
  * ```typescript
@@ -390,6 +397,16 @@ export type InternalHandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch exte
390
397
  * request is a fill. See router/segment-resolution/prefetch-deferral.ts.
391
398
  */
392
399
  _prefetchDeferral?: import("../router/segment-resolution/prefetch-deferral.js").PrefetchDeferral;
400
+ /**
401
+ * @internal A revalidate() predicate that read the source page
402
+ * (`currentParams`, `currentUrl`, `fromRouteName`) kept a held segment, so
403
+ * this match's diff is right only for pages with equal values of what the
404
+ * kept decisions read (#1331). Set by evaluateRevalidation
405
+ * (router/revalidation.ts) and the stored-entry keep
406
+ * (match-middleware/cache-lookup.ts); match-result.ts turns it into
407
+ * `sourceHeld`, which scopes a prefetch of the response to that group.
408
+ */
409
+ _sourceHeld?: import("../router/source-reads.js").SourceHeld;
393
410
  /**
394
411
  * @internal DSL loaders registered and not started, by `$$id`: a prefetch
395
412
  * deferred them, or a pass that skips loaders (`skipLoaders`) did not run
@@ -534,7 +551,7 @@ export type IsActionFn = (...actions: ActionRef[]) => boolean;
534
551
  export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
535
552
  /** Route params from the page being navigated away from. */
536
553
  currentParams: TParams;
537
- /** Full URL of the page being navigated away from. */
554
+ /** Full URL of the page being navigated away from, without its #fragment. */
538
555
  currentUrl: URL;
539
556
  /** Route params for the navigation target. */
540
557
  nextParams: TParams;
@@ -182,10 +182,13 @@ export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = Def
182
182
  export type LoaderOptions = {
183
183
  ssr?: boolean;
184
184
  /**
185
- * `prefetch: false` keeps this loader out of prefetches. A `<Link>`
186
- * prefetch (a partial request with `X-Rango-Prefetch`) does not execute it;
187
- * the payload marks it deferred. A document request and a navigation with
188
- * no prefetch to adopt run it as usual.
185
+ * `prefetch: false` keeps this loader out of speculative prefetches. A
186
+ * viewport or render `<Link>` prefetch (a partial request with
187
+ * `X-Rango-Prefetch: 1`) does not execute it; the payload marks it
188
+ * deferred. A hover prefetch and `useRouter().prefetch()`
189
+ * (`X-Rango-Prefetch: intent`) count as intent to click and run it, so a
190
+ * click after a hover needs no follow-up request. A document request and a
191
+ * navigation with no prefetch to adopt run it as usual.
189
192
  *
190
193
  * A deferred loader never blocks the navigation that adopts the prefetch:
191
194
  * it behaves like a loader that is still streaming. Its own `<Suspense>`
@@ -147,7 +147,6 @@ export interface ResolvedSegment {
147
147
  layoutName?: string;
148
148
  parallelName?: string;
149
149
  loaderId?: string;
150
- _inherited?: boolean;
151
150
  loaderData?: any;
152
151
  /**
153
152
  * True when this loader was awaited before first flush
@@ -274,6 +273,24 @@ export interface MatchResult {
274
273
  * source, so the RSC handler scopes its prefetch entry to it (#1007).
275
274
  */
276
275
  interceptTargeted?: true;
276
+ /**
277
+ * Set on a partial match when a revalidate() predicate read the source page
278
+ * and kept a held segment: the diff is right for the pages with equal values
279
+ * of what it read. The RSC handler scopes its prefetch entry to that group,
280
+ * or to the source page when the predicate read `currentUrl` (#1331).
281
+ */
282
+ sourceHeld?: import("../router/source-reads.js").SourceHeld;
283
+ /**
284
+ * Set on a partial match whose answer has nothing live in it: the cache
285
+ * lookup served it (a cache() record, a Prerender entry, a shell replay's
286
+ * record, not a stale cache() record or stale overlay entry), it sends a
287
+ * segment, every segment it
288
+ * sends is one that lookup decoded, and no loader ran. A stored segment
289
+ * cannot fail after the headers left, since every writer refuses a failed
290
+ * render; a live segment or a loader can. The RSC handler marks the request
291
+ * `_servedFromStorage` from it.
292
+ */
293
+ fromStorage?: true;
277
294
  /**
278
295
  * Redirect URL for trailing slash normalization.
279
296
  * When set, the RSC handler should return a 308 redirect to this URL
@@ -161,9 +161,10 @@ export type PathHelpers<TEnv> = {
161
161
  * freezes into the shell (nested promises stay live holes) — the pre-flush
162
162
  * promise applied to the prelude.
163
163
  *
164
- * Pass `{ prefetch: false }` to keep the loader out of prefetches: a
165
- * prefetch skips it and the click that adopts the prefetch fetches it in
166
- * one follow-up request (see {@link LoaderOptions}). Only on a segment the
164
+ * Pass `{ prefetch: false }` to keep the loader out of speculative
165
+ * prefetches (viewport, render): such a prefetch skips it and the click
166
+ * that adopts it fetches it in one follow-up request; a hover prefetch runs
167
+ * it (see {@link LoaderOptions}). Only on a segment the
167
168
  * client does not have yet: a loader the client already holds runs in the
168
169
  * prefetch when it revalidates.
169
170
  */
@@ -172,8 +173,9 @@ export type PathHelpers<TEnv> = {
172
173
  * Attach a loading component to the current route/layout.
173
174
  *
174
175
  * `{ ssr: false }` skips the fallback on document requests. `{ prefetch:
175
- * false }` keeps what the fallback covers out of prefetches, when this
176
- * entry's segment is new to the client: the entry's handler, its loaders,
176
+ * false }` keeps what the fallback covers out of viewport and render
177
+ * prefetches (a hover prefetch runs it), when this entry's segment is new
178
+ * to the client: the entry's handler, its loaders,
177
179
  * its orphan layouts and parallel slots and, for a layout, every deeper
178
180
  * entry. The click that adopts the prefetch shows the fallback and fetches
179
181
  * them in one follow-up request, which reads cache() and "use cache" as
@@ -7,8 +7,8 @@
7
7
  *
8
8
  * Sits in src/vite/, not src/vite/discovery/: the loader hook URL below
9
9
  * resolves against this module's import.meta.url, and the published bundles
10
- * (dist/vite/index.js, dist/bin/rango.js) ship the hook at the same relative
11
- * path.
10
+ * (dist/vite/index.js, and the CLI's code-split chunks in dist/bin/) ship the
11
+ * hook at the same relative path.
12
12
  */
13
13
  import type { ViteDevServer } from "vite";
14
14
  import type { DiscoveryState } from "./discovery/state.js";
@@ -1,4 +1,34 @@
1
1
  import type { Plugin, ResolvedConfig, UserConfig } from "vite";
2
+ /**
3
+ * Whether a user plugin must NOT be forwarded into the discovery temp server.
4
+ *
5
+ * Framework-owned plugins are matched precisely -- by exact name or a
6
+ * namespaced prefix -- rather than by a loose substring/word prefix, so an
7
+ * unrelated user resolver named e.g. `rsc-paths` or `cloudflare-kv-alias` is
8
+ * still forwarded (it would otherwise reproduce issue #500).
9
+ *
10
+ * - `vite:*` Vite core + official plugins (incl.
11
+ * @vitejs/plugin-react's `vite:react-*`). The temp
12
+ * server already provides its own core; forwarding
13
+ * these would duplicate or conflict with it.
14
+ * - `rsc` / `rsc:*` @vitejs/plugin-rsc. createTempRscServer instantiates
15
+ * its own rsc() plugin; forwarding would duplicate it.
16
+ * Matched exactly (`rsc`) or by the `rsc:` namespace --
17
+ * NOT every `rsc`-prefixed name.
18
+ * - `@rangojs/router*` Our own plugins. The discovery plugin spawns the
19
+ * temp server, so forwarding would recurse infinitely.
20
+ * - `@cloudflare/vite-plugin*` / @cloudflare/vite-plugin (emits the scoped
21
+ * `vite-plugin-cloudflare*` `@cloudflare/vite-plugin` and unscoped
22
+ * `vite-plugin-cloudflare` / `vite-plugin-cloudflare:*`).
23
+ * Forwarding re-inits workerd, defeating the Node temp
24
+ * server. Matched specifically so a scoped user resolver
25
+ * like `@cloudflare/kv-alias` is still forwarded.
26
+ *
27
+ * `rango generate --runtime` drops these before it resolves the user's config,
28
+ * so rango()'s configResolved (which writes the static gen files) and the
29
+ * Cloudflare plugin's config hooks never run there.
30
+ */
31
+ export declare function isFrameworkPlugin(name: string): boolean;
2
32
  /**
3
33
  * Pick the user's resolution plugins from the resolved plugin list, denylist
4
34
  * framework-owned plugins, keep only those with resolution hooks, and strip
@@ -20,8 +50,8 @@ export interface ForwardedRunnerConfig {
20
50
  /**
21
51
  * Extract the data-only config slice to mirror into the discovery temp server.
22
52
  * `alias` is included here so callers no longer need to thread it separately.
23
- * Accepts the unresolved config too: `rango generate --runtime` must not
24
- * resolve it (that runs rango()'s configResolved, which writes gen files).
53
+ * Accepts the unresolved config too: `rango generate --runtime` passes the
54
+ * config file's own values, without what plugin `config` hooks add.
25
55
  *
26
56
  * `tsconfigPaths` is forwarded so Vite 8's native tsconfig `paths` resolution
27
57
  * (a top-level `resolve` flag, off by default) reaches the temp server. The