@rangojs/router 0.22.0 → 0.23.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 (180) hide show
  1. package/dist/bin/rango.js +8 -3
  2. package/dist/testing/vitest.js +31 -1
  3. package/dist/types/browser/defer.d.ts +48 -0
  4. package/dist/types/browser/document-revealed.d.ts +17 -0
  5. package/dist/types/browser/event-controller.d.ts +7 -1
  6. package/dist/types/browser/navigation-transaction.d.ts +21 -7
  7. package/dist/types/browser/partial-update.d.ts +34 -5
  8. package/dist/types/browser/react/NavigationProvider.d.ts +13 -3
  9. package/dist/types/browser/react/filter-segment-order.d.ts +7 -0
  10. package/dist/types/browser/response-adapter.d.ts +7 -0
  11. package/dist/types/browser/types.d.ts +19 -9
  12. package/dist/types/browser/validate-redirect-origin.d.ts +11 -0
  13. package/dist/types/build/generate-route-types.d.ts +1 -1
  14. package/dist/types/build/route-types/router-processing.d.ts +1 -1
  15. package/dist/types/build/route-types/scan-filter.d.ts +16 -2
  16. package/dist/types/cache/cf/cf-cache-store.d.ts +16 -1
  17. package/dist/types/cache/cf/cf-cache-types.d.ts +23 -2
  18. package/dist/types/client-urls/client-urls.d.ts +1 -1
  19. package/dist/types/client-urls/hoisted-revalidate.d.ts +13 -0
  20. package/dist/types/client-urls/navigation.d.ts +0 -37
  21. package/dist/types/client-urls/revalidate-registry.d.ts +4 -0
  22. package/dist/types/client-urls/server-projection.d.ts +29 -1
  23. package/dist/types/client-urls/types.d.ts +34 -69
  24. package/dist/types/client.d.ts +0 -1
  25. package/dist/types/errors.d.ts +5 -0
  26. package/dist/types/handles/deferred-resolution.d.ts +2 -1
  27. package/dist/types/handles/pushed-by.d.ts +23 -0
  28. package/dist/types/loader-store.d.ts +8 -0
  29. package/dist/types/prefetch-markers.d.ts +11 -0
  30. package/dist/types/route-definition/helpers-types.d.ts +27 -0
  31. package/dist/types/router/is-action.d.ts +2 -1
  32. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -2
  33. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +241 -0
  34. package/dist/types/server/context.d.ts +21 -1
  35. package/dist/types/server/handle-store.d.ts +9 -1
  36. package/dist/types/server/request-context.d.ts +14 -1
  37. package/dist/types/server.d.ts +1 -0
  38. package/dist/types/testing/flight.entry.d.ts +1 -1
  39. package/dist/types/testing/index.d.ts +3 -3
  40. package/dist/types/testing/internal/action-id.d.ts +10 -1
  41. package/dist/types/testing/internal/client-urls-projection.d.ts +16 -0
  42. package/dist/types/testing/internal/test-action.d.ts +8 -0
  43. package/dist/types/testing/run-loader.d.ts +2 -1
  44. package/dist/types/testing/run-revalidate.d.ts +74 -0
  45. package/dist/types/testing/run-transition-when.d.ts +2 -3
  46. package/dist/types/testing/serve-shell-request.d.ts +38 -0
  47. package/dist/types/testing/vitest.d.ts +11 -0
  48. package/dist/types/types/boundaries.d.ts +9 -0
  49. package/dist/types/types/handler-context.d.ts +14 -0
  50. package/dist/types/types/loader-types.d.ts +30 -0
  51. package/dist/types/types/segments.d.ts +21 -4
  52. package/dist/types/urls/path-helper-types.d.ts +25 -4
  53. package/dist/types/urls/type-extraction.d.ts +6 -2
  54. package/dist/types/vite/discovery/discover-routers.d.ts +9 -0
  55. package/dist/types/vite/discovery/state.d.ts +11 -4
  56. package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +54 -0
  57. package/dist/types/vite/plugins/hoist/literal.d.ts +83 -0
  58. package/dist/types/vite/plugins/hoist/scope.d.ts +40 -0
  59. package/dist/types/vite/plugins/hoist/source.d.ts +41 -0
  60. package/dist/types/vite/plugins/transition-when-hoist.d.ts +8 -11
  61. package/dist/types/vite/router-discovery.d.ts +10 -0
  62. package/dist/vite/index.js +843 -309
  63. package/package.json +2 -2
  64. package/skills/caching/SKILL.md +42 -5
  65. package/skills/catalog.json +2 -2
  66. package/skills/client-urls/SKILL.md +113 -24
  67. package/skills/cloudflare/SKILL.md +14 -9
  68. package/skills/hooks/SKILL.md +11 -3
  69. package/skills/links/SKILL.md +24 -0
  70. package/skills/loader/SKILL.md +192 -1
  71. package/skills/migrate-nextjs/SKILL.md +2 -2
  72. package/skills/migrate-react-router/SKILL.md +10 -7
  73. package/skills/migrate-react-router/data-and-actions.md +1 -1
  74. package/skills/ppr/SKILL.md +13 -0
  75. package/skills/prerender/SKILL.md +22 -8
  76. package/skills/rango/SKILL.md +12 -6
  77. package/skills/route/SKILL.md +139 -0
  78. package/skills/testing/SKILL.md +3 -2
  79. package/skills/testing/client-components.md +1 -1
  80. package/skills/testing/predicates.md +67 -32
  81. package/skills/testing/serve-shell-request.md +88 -18
  82. package/skills/testing/setup.md +2 -2
  83. package/skills/typesafety/route-types.md +2 -2
  84. package/skills/view-transitions/SKILL.md +26 -0
  85. package/src/browser/defer.ts +82 -0
  86. package/src/browser/document-revealed.ts +52 -0
  87. package/src/browser/event-controller.ts +43 -32
  88. package/src/browser/navigation-bridge.ts +64 -14
  89. package/src/browser/navigation-client.ts +48 -36
  90. package/src/browser/navigation-store.ts +13 -0
  91. package/src/browser/navigation-transaction.ts +25 -8
  92. package/src/browser/partial-update.ts +528 -135
  93. package/src/browser/prefetch/fetch.ts +2 -1
  94. package/src/browser/react/NavigationProvider.tsx +47 -28
  95. package/src/browser/react/filter-segment-order.ts +13 -2
  96. package/src/browser/response-adapter.ts +20 -0
  97. package/src/browser/rsc-router.tsx +17 -45
  98. package/src/browser/server-action-bridge.ts +19 -63
  99. package/src/browser/types.ts +19 -9
  100. package/src/browser/validate-redirect-origin.ts +16 -0
  101. package/src/build/generate-route-types.ts +1 -0
  102. package/src/build/route-types/router-processing.ts +3 -6
  103. package/src/build/route-types/scan-filter.ts +37 -10
  104. package/src/cache/cf/cf-cache-store.ts +59 -21
  105. package/src/cache/cf/cf-cache-types.ts +24 -2
  106. package/src/cache/document-cache.ts +22 -1
  107. package/src/client-urls/client-urls.ts +22 -6
  108. package/src/client-urls/hoisted-revalidate.ts +25 -0
  109. package/src/client-urls/navigation.ts +0 -96
  110. package/src/client-urls/revalidate-registry.ts +30 -0
  111. package/src/client-urls/server-projection.ts +151 -65
  112. package/src/client-urls/types.ts +39 -71
  113. package/src/client.tsx +9 -5
  114. package/src/errors.ts +15 -0
  115. package/src/handles/deferred-resolution.ts +28 -5
  116. package/src/handles/pushed-by.ts +122 -0
  117. package/src/loader-store.ts +18 -7
  118. package/src/prefetch-markers.ts +13 -0
  119. package/src/route-content-wrapper.tsx +18 -4
  120. package/src/route-definition/dsl-helpers.ts +27 -4
  121. package/src/route-definition/helpers-types.ts +27 -1
  122. package/src/router/intercept-resolution.ts +6 -4
  123. package/src/router/is-action.ts +2 -1
  124. package/src/router/loader-resolution.ts +83 -4
  125. package/src/router/match-api.ts +36 -1
  126. package/src/router/match-middleware/background-revalidation.ts +11 -1
  127. package/src/router/match-middleware/cache-lookup.ts +29 -6
  128. package/src/router/match-middleware/cache-store.ts +17 -1
  129. package/src/router/match-result.ts +14 -2
  130. package/src/router/navigation-snapshot.ts +2 -1
  131. package/src/router/segment-resolution/fresh.ts +22 -18
  132. package/src/router/segment-resolution/loader-cache.ts +2 -1
  133. package/src/router/segment-resolution/loader-mask.ts +5 -3
  134. package/src/router/segment-resolution/prefetch-deferral.ts +543 -0
  135. package/src/router/segment-resolution/revalidation.ts +169 -60
  136. package/src/rsc/rsc-rendering.ts +50 -7
  137. package/src/rsc/shell-capture.ts +2 -1
  138. package/src/segment-loader-promise.ts +23 -20
  139. package/src/segment-system.tsx +60 -26
  140. package/src/server/context.ts +39 -5
  141. package/src/server/handle-store.ts +104 -8
  142. package/src/server/loader-registry.ts +6 -1
  143. package/src/server/request-context.ts +21 -1
  144. package/src/server.ts +4 -0
  145. package/src/testing/action-form.ts +2 -11
  146. package/src/testing/e2e/page-helpers.ts +3 -1
  147. package/src/testing/flight.entry.ts +1 -0
  148. package/src/testing/index.ts +6 -3
  149. package/src/testing/internal/action-id.ts +16 -1
  150. package/src/testing/internal/client-urls-projection.ts +70 -0
  151. package/src/testing/internal/test-action.ts +25 -0
  152. package/src/testing/run-loader.ts +2 -1
  153. package/src/testing/run-revalidate.ts +142 -0
  154. package/src/testing/run-transition-when.ts +7 -8
  155. package/src/testing/serve-shell-request.ts +116 -6
  156. package/src/testing/vitest.ts +67 -1
  157. package/src/types/boundaries.ts +12 -0
  158. package/src/types/handler-context.ts +14 -0
  159. package/src/types/loader-types.ts +30 -0
  160. package/src/types/segments.ts +26 -4
  161. package/src/urls/path-helper-types.ts +27 -5
  162. package/src/urls/type-extraction.ts +30 -10
  163. package/src/use-loader.tsx +18 -13
  164. package/src/vite/discovery/client-urls-projection.ts +20 -21
  165. package/src/vite/discovery/discover-routers.ts +94 -26
  166. package/src/vite/discovery/state.ts +20 -4
  167. package/src/vite/discovery/virtual-module-codegen.ts +22 -17
  168. package/src/vite/plugins/client-urls-revalidate-hoist.ts +564 -0
  169. package/src/vite/plugins/hoist/literal.ts +417 -0
  170. package/src/vite/plugins/hoist/scope.ts +370 -0
  171. package/src/vite/plugins/hoist/source.ts +84 -0
  172. package/src/vite/plugins/transition-when-hoist.ts +113 -779
  173. package/src/vite/rango.ts +2 -0
  174. package/src/vite/router-discovery.ts +93 -32
  175. package/dist/types/client-urls/revalidate-chain.d.ts +0 -33
  176. package/dist/types/client-urls/revalidation-protocol.d.ts +0 -25
  177. package/dist/types/testing/run-client-revalidate.d.ts +0 -43
  178. package/src/client-urls/revalidate-chain.ts +0 -83
  179. package/src/client-urls/revalidation-protocol.ts +0 -56
  180. package/src/testing/run-client-revalidate.ts +0 -92
@@ -587,6 +587,19 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
587
587
  * document cache does not store that response (#978).
588
588
  */
589
589
  _payloadVisitorTheme?: boolean;
590
+ /**
591
+ * @internal Set by the partial render when its payload carries deferred
592
+ * units (`prefetch: false`): what one page's prefetch left for the fill.
593
+ * The document cache does not store that response, whatever Cache-Control
594
+ * it ends up with (docs/design/prefetch-false.md, R7).
595
+ */
596
+ _payloadDeferred?: boolean;
597
+ /**
598
+ * @internal What the request says it is: a `<Link>` prefetch or a fill
599
+ * (`prefetch: false`), read once at creation
600
+ * (segment-resolution/prefetch-deferral.ts requestKind).
601
+ */
602
+ _requestKind?: "prefetch" | "fill";
590
603
  /**
591
604
  * Attach location state entries to the current response.
592
605
  *
@@ -803,7 +816,7 @@ export interface RouteRecordWindow {
803
816
  * This is the type exported to library consumers. Internal code should
804
817
  * use the full RequestContext interface directly.
805
818
  */
806
- 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" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
819
+ 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" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
807
820
  /**
808
821
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
809
822
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -15,3 +15,4 @@ export { createRequestContext, type CreateRequestContextOptions, } from "./serve
15
15
  export { isClientComponent, assertClientComponent } from "./component-utils.js";
16
16
  export { enableTransitionWhenValidation } from "./transition-when-ref.js";
17
17
  export { clearClientUrlProjections, setClientUrlProjection, type ClientUrlProjection, } from "./client-urls/server-projection.js";
18
+ export { registerClientUrlRevalidators } from "./client-urls/revalidate-registry.js";
@@ -33,4 +33,4 @@ export type { TestableHandler, RenderHandlerOptions, RenderHandlerResult, StateC
33
33
  export { createActionForm } from "./action-form.js";
34
34
  export type { CreateActionFormOptions } from "./action-form.js";
35
35
  export { serveShellRequest, resetShellTestState, } from "./serve-shell-request.js";
36
- export type { ServeShellRequestOptions, ServeShellRequestResult, ShellRequestHandles, } from "./serve-shell-request.js";
36
+ export type { ServeShellRequestAction, ServeShellRequestOptions, ServeShellRequestResult, ShellRequestHandles, } from "./serve-shell-request.js";
@@ -26,7 +26,7 @@
26
26
  * condition and would throw if pulled into this barrel.
27
27
  *
28
28
  * Layers:
29
- * - Unit: runMiddleware, runLoader, runClientRevalidate
29
+ * - Unit: runMiddleware, runLoader, runRevalidate, runTransitionWhen
30
30
  * - Integration: dispatch (request -> Response)
31
31
  * - Cross-cut: assertCacheStatus, assertShellStatus, assertGeneratedRoutesMatch
32
32
  * - Component: see @rangojs/router/testing/dom (renderRoute)
@@ -39,8 +39,8 @@ export { runLoader, runLoaderResult } from "./run-loader.js";
39
39
  export type { RunLoaderOptions, RunLoaderResult, UseResolver, TestLoaderContext, } from "./run-loader.js";
40
40
  export { runTransitionWhen } from "./run-transition-when.js";
41
41
  export type { RunTransitionWhenAction, RunTransitionWhenLocation, RunTransitionWhenOptions, RunTransitionWhenResult, } from "./run-transition-when.js";
42
- export { runClientRevalidate } from "./run-client-revalidate.js";
43
- export type { RunClientRevalidateOptions } from "./run-client-revalidate.js";
42
+ export { runRevalidate } from "./run-revalidate.js";
43
+ export type { RunRevalidateAction, RunRevalidateOptions, } from "./run-revalidate.js";
44
44
  export { dispatch } from "./dispatch.js";
45
45
  export type { DispatchOptions } from "./dispatch.js";
46
46
  export { createMemoryPrerenderStore } from "../prerender/memory-prerender-store.js";
@@ -1,7 +1,16 @@
1
+ /** An imported server action, as a testing primitive's `action` option takes it. */
2
+ export type ImportedAction = (...args: never[]) => unknown;
3
+ /**
4
+ * Normalizes a testing primitive's `action` option: a bare imported action or
5
+ * actionId string becomes `{ ref }`; the object form passes through.
6
+ */
7
+ export declare function normalizeTestAction<T extends {
8
+ ref?: ImportedAction | string;
9
+ }>(action: ImportedAction | string | T | undefined): T | undefined;
1
10
  /**
2
11
  * The id a testing primitive's `action` option names: a single imported
3
12
  * server action (its `$id ?? $$id`, as the action boundary derives it) or a
4
13
  * raw actionId string. A function without either id throws, naming the
5
14
  * primitive.
6
15
  */
7
- export declare function resolveTestActionId(action: ((...args: never[]) => unknown) | string | undefined, primitive: string): string | undefined;
16
+ export declare function resolveTestActionId(action: ImportedAction | string | undefined, primitive: string): string | undefined;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Install the projection of a `"use client"` clientUrls() module under its
3
+ * client reference id, as discovery installs it for an app
4
+ * (discoverClientUrlProjections in vite/discovery/client-urls-projection.ts):
5
+ * the same projection step, into the same registry include() materializes
6
+ * from. rangoUseClientTransform (testing/vitest.ts) appends a call to every
7
+ * such module, passing the module's own source evaluated without the
8
+ * transform, so a router under test mounts the group with no setup.
9
+ *
10
+ * A Vitest project runs no hoist plugin, so the source's revalidate()
11
+ * predicates are plain functions. Each is registered under a key named for
12
+ * its reference, route and loader, as the plugin's generated module registers
13
+ * its own, and the projection carries the keys: materialization attaches them
14
+ * and the server runs them, as in an app.
15
+ */
16
+ export declare function installClientUrlsProjection(referenceId: string, source: Readonly<Record<string, unknown>>): void;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Register `action` under its reference id, `<module id>#<export name>`,
3
+ * tagged as a server reference like a built "use server" export so it keeps
4
+ * its `$$id`, where the plugin-rsc stub's decodeAction / loadServerAction
5
+ * resolve it. `primitive` names the caller in the error for a malformed id.
6
+ * Loads the react-server build: callers run under the react-server condition.
7
+ */
8
+ export declare function registerTestAction(action: (...args: any[]) => unknown, id: string, primitive: string): void;
@@ -20,8 +20,9 @@
20
20
  * - `ctx.reverse()` throws unless `routeMap` is provided (it does NOT fall back
21
21
  * to the global route map — that would leak whichever routes another test
22
22
  * registered).
23
- * - `ctx.use(handle)` follows the production rule: reading a handle before
23
+ * - `ctx.get(handle)` follows the production rule: reading a handle before
24
24
  * `await ctx.rendered()` throws (pass `rendered` to mock the barrier).
25
+ * `ctx.use(handle)` is the push and needs no barrier.
25
26
  * - `use cache` functions only cache (and only fire their taint/profile guards)
26
27
  * when a `cacheStore` is provided — without one, registerCachedFunction
27
28
  * bypasses (it checks for a store first). Pass `cacheStore`/`cacheProfiles`
@@ -0,0 +1,74 @@
1
+ /**
2
+ * runRevalidate — unit-test revalidate() predicates: a urls() segment's, or a
3
+ * clientUrls() loader's (which the build moves to the server, where it runs
4
+ * the same way).
5
+ *
6
+ * Evaluates the predicate(s) through the router's own evaluateRevalidation
7
+ * (router/revalidation.ts) inside a seeded request context: the default
8
+ * decision, the argument object, boolean short-circuit, soft-verdict
9
+ * threading and the fail-open on a throw are the production code paths, not
10
+ * a re-implementation. Pass an array to test a chain in declaration order.
11
+ */
12
+ import type { ShouldRevalidateFn } from "../types.js";
13
+ import { type ImportedAction } from "./internal/action-id.js";
14
+ import type { VarsInit } from "./internal/seed-vars.js";
15
+ type RevalidateArgs = Parameters<ShouldRevalidateFn<any, any>>[0];
16
+ /** The action fields a predicate receives on an action request. */
17
+ export interface RunRevalidateAction {
18
+ /** The triggering action: an imported server action or its actionId. */
19
+ ref?: ImportedAction | string;
20
+ /** `actionResult`: the action's return value. */
21
+ result?: unknown;
22
+ /** `formData`: the action's FormData argument. */
23
+ formData?: FormData;
24
+ /** `actionUrl`. Defaults to `currentUrl`. */
25
+ url?: string | URL;
26
+ }
27
+ /**
28
+ * Options for {@link runRevalidate}. Defaults model a same-URL navigation
29
+ * with no action, for a route-owned loader segment.
30
+ */
31
+ export interface RunRevalidateOptions<TEnv = any> {
32
+ /** The page being left. Defaults to `http://localhost/`. */
33
+ currentUrl?: string | URL;
34
+ /** The destination. Defaults to `currentUrl`. */
35
+ nextUrl?: string | URL;
36
+ currentParams?: Record<string, string>;
37
+ /** Defaults to `currentParams`. */
38
+ nextParams?: Record<string, string>;
39
+ /**
40
+ * The triggering action: an imported server action (id via
41
+ * `$id ?? $$id`), an actionId string, or `{ ref, result, formData, url }`.
42
+ * Makes the request a POST, as an action request is.
43
+ */
44
+ action?: ImportedAction | string | RunRevalidateAction;
45
+ /** Overrides the request method (`POST` with `action`, else `GET`). */
46
+ method?: string;
47
+ /** The segment the predicate is attached to. Defaults to `"loader"`. */
48
+ segmentType?: RevalidateArgs["segmentType"];
49
+ /**
50
+ * The segment belongs to the matched route (a route's own loaders, a
51
+ * clientUrls() group loader). Defaults to true; false models a layout's
52
+ * loader, which a navigation keeps by default.
53
+ */
54
+ belongsToRoute?: boolean;
55
+ /** `stale`: a history-entry background revalidation. */
56
+ stale?: boolean;
57
+ /** `toRouteName` (and `routeName`). */
58
+ routeName?: string;
59
+ /** `fromRouteName`. */
60
+ fromRouteName?: string;
61
+ /** Environment bindings of the seeded context. */
62
+ env?: TEnv;
63
+ /** Variables a middleware would have set, readable with `context.get()`. */
64
+ vars?: VarsInit;
65
+ /** `context`, in place of the seeded request context. */
66
+ context?: RevalidateArgs["context"];
67
+ }
68
+ /**
69
+ * Run one revalidate() predicate, or a chain in declaration order, the way
70
+ * the router does for a request. Resolves to the final decision: true
71
+ * re-runs the segment, false keeps the client's copy.
72
+ */
73
+ export declare function runRevalidate<TEnv = any>(fn: ShouldRevalidateFn<any, TEnv> | readonly ShouldRevalidateFn<any, TEnv>[], opts?: RunRevalidateOptions<TEnv>): Promise<boolean>;
74
+ export {};
@@ -11,8 +11,8 @@
11
11
  *
12
12
  * Synchronous: a transition predicate returns a boolean and has no I/O.
13
13
  */
14
+ import { type ImportedAction } from "./internal/action-id.js";
14
15
  import type { RouteLocation, TransitionConfig, TransitionWhenContext, TransitionWhenFn, TransitionWhenKind } from "../types/segments.js";
15
- type ImportedAction = (...args: never[]) => unknown;
16
16
  /** A navigation side: a URL, or a partial RouteLocation. */
17
17
  export type RunTransitionWhenLocation = string | URL | (Partial<Omit<RouteLocation, "url">> & {
18
18
  url?: string | URL;
@@ -35,7 +35,7 @@ export interface RunTransitionWhenOptions {
35
35
  /** The destination. Defaults to `from`; always `from` for "action" and "revalidate". */
36
36
  to?: RunTransitionWhenLocation;
37
37
  /**
38
- * The triggering action (like runClientRevalidate's): an imported server
38
+ * The triggering action (like runRevalidate's): an imported server
39
39
  * action (id via `$id ?? $$id`), an actionId string, or
40
40
  * `{ ref, formData, result, error }`.
41
41
  */
@@ -50,4 +50,3 @@ export interface RunTransitionWhenResult {
50
50
  context: TransitionWhenContext;
51
51
  }
52
52
  export declare function runTransitionWhen(whenOrConfig: TransitionWhenFn | TransitionConfig, opts?: RunTransitionWhenOptions): RunTransitionWhenResult;
53
- export {};
@@ -63,10 +63,19 @@ export interface ServeShellRequestOptions<TEnv = any> {
63
63
  * of a document GET: from `from` (default `/`) with `segments` mounted
64
64
  * (default none), advertising fragment passthrough. The replay decision is
65
65
  * `result.replayStatus`.
66
+ *
67
+ * `prefetch: true` sends it as a `<Link>` prefetch does (the
68
+ * `X-Rango-Prefetch` header), so `prefetch: false` loaders and `loading()`
69
+ * entries are deferred: `result.readDeferred()` lists them. `fill: true`
70
+ * sends the request the browser follows an adopted prefetch with
71
+ * (`_rsc_fill`): pass the ids the prefetch delivered, without the deferred
72
+ * ones, as `segments`, and the same URL as `from`.
66
73
  */
67
74
  partial?: true | {
68
75
  from?: string;
69
76
  segments?: readonly string[];
77
+ prefetch?: boolean;
78
+ fill?: boolean;
70
79
  };
71
80
  /**
72
81
  * POST this form as a submit before hydration: the no-JS request the
@@ -76,6 +85,29 @@ export interface ServeShellRequestOptions<TEnv = any> {
76
85
  * Not with `partial`.
77
86
  */
78
87
  form?: FormData;
88
+ /**
89
+ * Send the request a JS server action call makes from the page at `url`:
90
+ * a POST of `args` (encoded as the browser encodes them) for `ref`, with
91
+ * the page's mounted `segments` (default none), as
92
+ * browser/server-action-bridge.ts sends it. The response is the action's
93
+ * Flight payload (its return value and the re-rendered segments).
94
+ * Not with `partial` or `form`.
95
+ */
96
+ action?: ServeShellRequestAction;
97
+ }
98
+ /** The JS server action call of {@link ServeShellRequestOptions.action}. */
99
+ export interface ServeShellRequestAction {
100
+ /** The server action. */
101
+ ref: (...args: any[]) => unknown;
102
+ /**
103
+ * Its reference id, `<module id>#<export name>`, as the build gives a
104
+ * "use server" export; registered so the handler loads `ref` by it.
105
+ */
106
+ id: string;
107
+ /** The arguments the page calls it with. */
108
+ args?: readonly unknown[];
109
+ /** The segment ids the page holds (`_rsc_segments`). */
110
+ segments?: readonly string[];
79
111
  }
80
112
  /** A response's handle data, as the browser consumes it. */
81
113
  export interface ShellRequestHandles {
@@ -133,6 +165,12 @@ export interface ServeShellRequestResult {
133
165
  * values resolved. Undefined when no Flight was rendered.
134
166
  */
135
167
  readHandles(): Promise<ShellRequestHandles | undefined>;
168
+ /**
169
+ * The ids of the segments `flight` marks deferred (a prefetch skipped
170
+ * them; the fill request renders them), in payload order. Empty when
171
+ * nothing was deferred, undefined when no Flight was rendered.
172
+ */
173
+ readDeferred(): Promise<string[] | undefined>;
136
174
  /**
137
175
  * The form state the SSR render received (the `formState` render option),
138
176
  * or undefined when it received none.
@@ -146,6 +146,10 @@ export declare function rangoTestConfig(opts?: RangoTestAliasOptions): RangoTest
146
146
  /** A minimal Vite plugin shape (avoids a hard dependency on Vite's types). */
147
147
  interface FlightTransformPlugin {
148
148
  name: string;
149
+ resolveId: {
150
+ order: "pre";
151
+ handler(source: string, importer: string | undefined): string | undefined;
152
+ };
149
153
  transform(code: string, id: string): Promise<{
150
154
  code: string;
151
155
  map: unknown;
@@ -202,6 +206,13 @@ interface FlightTransformPlugin {
202
206
  * by the module's absolute path (the boundary id), the export name becoming the
203
207
  * boundary name. Modules without the directive (server components) are untouched,
204
208
  * so `renderToFlightString` of pure leaf trees is unaffected.
209
+ *
210
+ * A `"use client"` module whose default export is a `clientUrls()` definition
211
+ * also installs its server projection, as the rango plugin's discovery does for
212
+ * an app: the module imports its own source without this transform and projects
213
+ * it under its client reference. A router that mounts the group
214
+ * (`include("/shop", shopUrls)` or `.routes(shopUrls)`) then serves its routes
215
+ * through `serveShellRequest` and `dispatch` with no setup.
205
216
  */
206
217
  export declare function rangoUseClientTransform(): FlightTransformPlugin;
207
218
  /** The Vite plugin shape {@link rangoUseCacheTransform} returns. */
@@ -87,6 +87,15 @@ export type LoaderDataResult<T = unknown> = {
87
87
  };
88
88
  };
89
89
  export declare function isLoaderDataResult(value: unknown): value is LoaderDataResult;
90
+ /**
91
+ * A loading skeleton is renderable only when it is a real ReactNode value;
92
+ * `false` counts as "not renderable". This is the three-term gate. The
93
+ * distinct two-term gate at the LoaderBoundary site (segment-system.tsx)
94
+ * deliberately treats `false` as "create a boundary without a
95
+ * RouteContentWrapper" (tree-structure.md), so it must NOT use this helper.
96
+ * Leaf module: shared by client (segment-system) and server (DSL, resolution).
97
+ */
98
+ export declare function isRenderableLoading(loading: unknown): boolean;
90
99
  export interface NotFoundInfo {
91
100
  message: string;
92
101
  segmentId: string;
@@ -372,6 +372,20 @@ export type InternalHandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch exte
372
372
  * setupLoaderAccess.
373
373
  */
374
374
  _bindLoaderCacheTags?: (loaderId: string, tags: Set<string>) => void;
375
+ /**
376
+ * @internal This match's `prefetch: false` plan: what a prefetch defers,
377
+ * whether the request is a fill, and the loaders that cannot call
378
+ * ctx.rendered(). Set by match-api.ts when the tree declares a flag or the
379
+ * request is a fill. See router/segment-resolution/prefetch-deferral.ts.
380
+ */
381
+ _prefetchDeferral?: import("../router/segment-resolution/prefetch-deferral.js").PrefetchDeferral;
382
+ /**
383
+ * @internal Whether a loader was started in this request: a run of it (a
384
+ * handler's or another loader's ctx.use()) or its cache() binding. A
385
+ * prefetch delivers such a loader instead of deferring it. See
386
+ * setupLoaderAccess.
387
+ */
388
+ _loaderStarted?: (loaderId: string) => boolean;
375
389
  };
376
390
  /**
377
391
  * Generic params type - flexible object with string keys
@@ -175,6 +175,36 @@ export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = Def
175
175
  */
176
176
  export type LoaderOptions = {
177
177
  ssr?: boolean;
178
+ /**
179
+ * `prefetch: false` keeps this loader out of prefetches. A `<Link>`
180
+ * prefetch (a partial request with `X-Rango-Prefetch`) does not execute it;
181
+ * the payload marks it deferred. A document request and a navigation with
182
+ * no prefetch to adopt run it as usual.
183
+ *
184
+ * A deferred loader never blocks the navigation that adopts the prefetch:
185
+ * it behaves like a loader that is still streaming. Its own `<Suspense>`
186
+ * shows at once; if the nearest boundary is the route's `loading()`, that
187
+ * shows; with no boundary React holds the page until the fill returns. The
188
+ * fill is the one follow-up request that runs the loader.
189
+ *
190
+ * The fill reads through the loader's own `cache()` and any `"use cache"`
191
+ * function it calls. A prefetch reads neither, by intent: looking would
192
+ * mean running the loader on a miss.
193
+ *
194
+ * The flag applies only to a segment the client does not have yet. A
195
+ * loader the client already holds (the same route with new params, say)
196
+ * runs in the prefetch when it revalidates, exactly as without the flag:
197
+ * a click that adopts a prefetch is never worse than the same click with
198
+ * no prefetch at all.
199
+ *
200
+ * Limits: a handler that awaits the loader with `ctx.use()` makes it run in
201
+ * the prefetch anyway; the loader cannot call `ctx.rendered()` (it throws
202
+ * on every request); on a `ppr` route the flag is ignored for an
203
+ * `ssr: false` loader (the bake lane), with a dev warning. In the fill
204
+ * request only deferred work and middleware run, so values a held handler
205
+ * would have set with `ctx.set()` are not visible.
206
+ */
207
+ prefetch?: boolean;
178
208
  };
179
209
  /**
180
210
  * Options for fetchable loaders
@@ -158,6 +158,15 @@ export interface ResolvedSegment {
158
158
  */
159
159
  awaitBeforeFlush?: true;
160
160
  parallelLoading?: ReactNode;
161
+ /**
162
+ * A prefetch skipped this segment's work (`prefetch: false`): a loader
163
+ * carries no `loaderData`, a layout/route/parallel unit carries
164
+ * `component: null` and its fallback. The browser shows the fallback and
165
+ * sends a fill request for it (browser/partial-update.ts); until that
166
+ * lands the segment is a placeholder, never a held copy. Only ever on a
167
+ * prefetch response: see docs/design/prefetch-false.md.
168
+ */
169
+ deferred?: true;
161
170
  loaderDataPromise?: Promise<any[]> | any[];
162
171
  loaderIds?: string[];
163
172
  /**
@@ -228,10 +237,12 @@ export interface MatchResult {
228
237
  /**
229
238
  * Every segment id whose handler actually ran on the server this request,
230
239
  * including ones with `component === null` that get filtered out of
231
- * `segments`/`diff` to avoid wasted bytes. Drives the client's handle-
232
- * cleanup pass — a slot that re-resolves and pushes nothing must clear
233
- * its previous handle bucket, but `diff` doesn't carry it because the
234
- * segment payload doesn't either. A superset of `diff`.
240
+ * `segments`/`diff` to avoid wasted bytes, and every loader segment that
241
+ * ran. Drives the client's handle merge (handles/pushed-by.ts) — a slot
242
+ * that re-resolves and pushes nothing must clear its previous handle
243
+ * bucket, but `diff` doesn't carry it because the segment payload doesn't
244
+ * either; a loader that ran replaces its pushes, one that did not keeps
245
+ * them. A superset of `diff`.
235
246
  */
236
247
  resolvedIds: string[];
237
248
  /**
@@ -279,3 +290,9 @@ export interface MatchResult {
279
290
  params: Record<string, string>;
280
291
  }>;
281
292
  }
293
+ /**
294
+ * A `prefetch: false` placeholder (ResolvedSegment.deferred): a segment whose
295
+ * work a prefetch skipped, waiting for its fill. Never a held copy of the
296
+ * segment it stands for.
297
+ */
298
+ export declare function isPlaceholder(segment: Pick<ResolvedSegment, "deferred">): boolean;
@@ -1,6 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { ErrorBoundaryHandler, ExtractParams, Handler, HandlerContext, LoaderDefinition, LoaderOptions, MiddlewareFn, NotFoundBoundaryHandler, PartialCacheOptions, ShouldRevalidateFn, TransitionConfig } from "../types.js";
3
- import type { AllUseItems, TypedLayoutItem, ParallelItem, InterceptItem, MiddlewareItem, RevalidateItem, LoaderItem, LoadingItem, ErrorBoundaryItem, NotFoundBoundaryItem, LayoutUseItem, RouteUseItem, ResponseRouteUseItem, ParallelUseItem, InterceptUseItem, LoaderUseItem, TypedCacheItem, TransitionItem, TypedTransitionItem, TypedRouteItem, TypedIncludeItem, UseItems } from "../route-types.js";
3
+ import type { AllUseItems, TypedLayoutItem, ParallelItem, InterceptItem, MiddlewareItem, RevalidateItem, LoaderItem, LoadingItem, ErrorBoundaryItem, NotFoundBoundaryItem, LayoutUseItem, RouteUseItem, ResponseRouteUseItem, ParallelUseItem, InterceptUseItem, LoaderUseItem, TypedCacheItem, TypedTransitionItem, TypedRouteItem, TypedIncludeItem, UseItems } from "../route-types.js";
4
4
  import type { SearchSchema } from "../search-params.js";
5
5
  import type { PrerenderHandlerDefinition, PassthroughHandlerDefinition } from "../prerender.js";
6
6
  import type { StaticHandlerDefinition, StaticHandlerRef } from "../static-handler.js";
@@ -158,13 +158,34 @@ export type PathHelpers<TEnv> = {
158
158
  * flag BAKES: the loader executes at shell capture and its settled return
159
159
  * freezes into the shell (nested promises stay live holes) — the pre-flush
160
160
  * promise applied to the prelude.
161
+ *
162
+ * Pass `{ prefetch: false }` to keep the loader out of prefetches: a
163
+ * prefetch skips it and the click that adopts the prefetch fetches it in
164
+ * one follow-up request (see {@link LoaderOptions}). Only on a segment the
165
+ * client does not have yet: a loader the client already holds runs in the
166
+ * prefetch when it revalidates.
161
167
  */
162
168
  loader: <TData>(loaderDef: LoaderDefinition<TData>, optionsOrUse?: LoaderOptions | (() => LoaderUseItem[]), use?: () => LoaderUseItem[]) => LoaderItem;
163
169
  /**
164
- * Attach a loading component to the current route/layout
170
+ * Attach a loading component to the current route/layout.
171
+ *
172
+ * `{ ssr: false }` skips the fallback on document requests. `{ prefetch:
173
+ * false }` keeps what the fallback covers out of prefetches, when this
174
+ * entry's segment is new to the client: the entry's handler, its loaders,
175
+ * its orphan layouts and parallel slots and, for a layout, every deeper
176
+ * entry. The click that adopts the prefetch shows the fallback and fetches
177
+ * them in one follow-up request, which reads cache() and "use cache" as
178
+ * any request does (a prefetch reads neither for skipped work). A segment
179
+ * the client already holds is never deferred: a prefetch renders it as
180
+ * usual when it revalidates, and what is below it follows its own flags.
181
+ * To keep a child out of prefetches while moving inside a section, flag
182
+ * the child's own loading(). An entry whose handler output is stored
183
+ * (cache(), ppr, Prerender/Static) is served as usual and only its loaders
184
+ * are skipped.
165
185
  */
166
186
  loading: (component: ReactNode | (() => ReactNode), options?: {
167
187
  ssr?: boolean;
188
+ prefetch?: boolean;
168
189
  }) => LoadingItem;
169
190
  /**
170
191
  * Attach an error boundary to catch errors in this segment
@@ -199,8 +220,8 @@ export type PathHelpers<TEnv> = {
199
220
  * the browser (never on the server); see TransitionWhenFn.
200
221
  */
201
222
  transition: {
202
- (): TransitionItem;
203
- (config: TransitionConfig): TransitionItem;
223
+ (): TypedTransitionItem<{}, {}>;
224
+ (config: TransitionConfig): TypedTransitionItem<{}, {}>;
204
225
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(children: () => TChildren): TypedTransitionItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
205
226
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(config: TransitionConfig, children: () => TChildren): TypedTransitionItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
206
227
  };
@@ -1,6 +1,10 @@
1
1
  import type { JsonSerialize } from "../serialize.js";
2
2
  import type { TypedRouteItem, TypedIncludeItem, TypedLayoutItem, TypedCacheItem, TypedTransitionItem } from "../route-types.js";
3
3
  import type { LocalOnlyInclude, UnnamedRoute } from "./pattern-types.js";
4
+ /** Drops string index signatures, keeping literal and template keys. */
5
+ type StripStringIndex<T> = {
6
+ [K in keyof T as string extends K ? never : K]: T[K];
7
+ };
4
8
  /**
5
9
  * Prefix route names with a given prefix (e.g., "blog" + "post" = "blog.post")
6
10
  *
@@ -52,7 +56,7 @@ type ExtractRoutesFromItem<T> = T extends TypedRouteItem<infer TName, infer TPat
52
56
  readonly path: TPattern;
53
57
  readonly search: TSearch;
54
58
  };
55
- } : {} : T extends TypedIncludeItem<infer TRoutes, infer TNamePrefix, infer TUrlPrefix> ? TNamePrefix extends LocalOnlyInclude ? {} : TNamePrefix extends string ? TUrlPrefix extends string ? PrefixRoutes<PrefixPatterns<TRoutes, TUrlPrefix>, TNamePrefix> : PrefixRoutes<TRoutes, TNamePrefix> : TUrlPrefix extends string ? PrefixPatterns<TRoutes, TUrlPrefix> : TRoutes : T extends TypedLayoutItem<infer TChildRoutes> ? TChildRoutes : T extends TypedCacheItem<infer TChildRoutes> ? TChildRoutes : T extends TypedTransitionItem<infer TChildRoutes> ? TChildRoutes : {};
59
+ } : {} : T extends TypedIncludeItem<infer TRoutes, infer TNamePrefix, infer TUrlPrefix> ? TNamePrefix extends LocalOnlyInclude ? {} : TNamePrefix extends string ? TUrlPrefix extends string ? PrefixRoutes<PrefixPatterns<TRoutes, TUrlPrefix>, TNamePrefix> : PrefixRoutes<TRoutes, TNamePrefix> : TUrlPrefix extends string ? PrefixPatterns<TRoutes, TUrlPrefix> : TRoutes : T extends TypedLayoutItem<infer TChildRoutes> ? StripStringIndex<TChildRoutes> : T extends TypedCacheItem<infer TChildRoutes> ? StripStringIndex<TChildRoutes> : T extends TypedTransitionItem<infer TChildRoutes> ? StripStringIndex<TChildRoutes> : {};
56
60
  /**
57
61
  * Extract routes from an array of items using mapped types.
58
62
  * Uses UnionToIntersection to combine routes without recursive tuple processing,
@@ -82,7 +86,7 @@ type PrefixKeys<T extends Record<string, unknown>, TPrefix extends string> = TPr
82
86
  */
83
87
  type ExtractResponsesFromItem<T> = T extends TypedRouteItem<infer TName, any, infer TData> ? TName extends string ? string extends TName ? {} : TName extends UnnamedRoute ? {} : {
84
88
  [K in TName]: TData;
85
- } : {} : T extends TypedIncludeItem<any, infer TNamePrefix, any, infer TResponses> ? TNamePrefix extends LocalOnlyInclude ? {} : TNamePrefix extends string ? TResponses extends Record<string, unknown> ? PrefixKeys<TResponses, TNamePrefix> : {} : TResponses extends Record<string, unknown> ? TResponses : {} : T extends TypedLayoutItem<any, infer TChildResponses> ? TChildResponses extends Record<string, unknown> ? TChildResponses : {} : T extends TypedCacheItem<any, infer TChildResponses> ? TChildResponses extends Record<string, unknown> ? TChildResponses : {} : T extends TypedTransitionItem<any, infer TChildResponses> ? TChildResponses extends Record<string, unknown> ? TChildResponses : {} : {};
89
+ } : {} : T extends TypedIncludeItem<any, infer TNamePrefix, any, infer TResponses> ? TNamePrefix extends LocalOnlyInclude ? {} : TNamePrefix extends string ? TResponses extends Record<string, unknown> ? PrefixKeys<TResponses, TNamePrefix> : {} : TResponses extends Record<string, unknown> ? TResponses : {} : T extends TypedLayoutItem<any, infer TChildResponses> ? StripStringIndex<TChildResponses> extends infer R extends Record<string, unknown> ? R : {} : T extends TypedCacheItem<any, infer TChildResponses> ? StripStringIndex<TChildResponses> extends infer R extends Record<string, unknown> ? R : {} : T extends TypedTransitionItem<any, infer TChildResponses> ? StripStringIndex<TChildResponses> extends infer R extends Record<string, unknown> ? R : {} : {};
86
90
  /**
87
91
  * Extract responses from an array of items using mapped types.
88
92
  * Parallel to ExtractRoutesFromItems.
@@ -13,5 +13,14 @@ import type { DiscoveryState } from "./state.js";
13
13
  *
14
14
  * Returns the imported `@rangojs/router/server` module so the caller
15
15
  * can access the RouterRegistry and manifest setters.
16
+ *
17
+ * A pass reads the router registry and installs clientUrls projections on ONE
18
+ * `@rangojs/router/server` instance, and checks that the runner still serves
19
+ * it. A runner full reload during the pass (a watched-file change at boot)
20
+ * splits the realm: a router module bound to the old instance registers there
21
+ * while urls modules re-evaluate against a fresh one, so include() looks its
22
+ * projection up in the fresh, empty Map ("include() could not resolve the
23
+ * server projection"). Such a pass is redone, at most
24
+ * MAX_DISCOVERY_PASSES times; the redo evaluates the entry in one realm.
16
25
  */
17
26
  export declare function discoverRouters(state: DiscoveryState, rscEnv: any, ssrEnv?: any): Promise<any>;
@@ -188,14 +188,21 @@ export interface DiscoveryState {
188
188
  /** Cleanup function for build-time env resources (e.g., miniflare). */
189
189
  buildEnvDispose?: (() => Promise<void> | void) | null;
190
190
  /**
191
- * Set when the most recent HMR re-discovery threw. Cleared on the next
192
- * successful discovery. Surfaced via debug logs so we can detect "manifest
193
- * frozen at last-good after error → user fix in non-route file → no
194
- * rediscovery trigger" scenarios.
191
+ * Set when the most recent discovery threw: an HMR re-discovery, or the
192
+ * cold dev discovery on a main RSC runner. Cleared on the next successful
193
+ * discovery. While set, the route-file watcher treats any in-scan source
194
+ * change as a rediscovery trigger (recovery mode).
195
195
  */
196
196
  lastDiscoveryError?: {
197
197
  message: string;
198
198
  at: number;
199
199
  } | null;
200
200
  }
201
+ /**
202
+ * Whether the route-file watcher can re-run runtime discovery. A committed
203
+ * manifest is the usual precondition. A failed cold discovery commits none,
204
+ * so on a main RSC runner its recorded failure qualifies too; without that
205
+ * the dev server stayed broken until a restart.
206
+ */
207
+ export declare function canRefreshRuntimeDiscovery(state: Pick<DiscoveryState, "perRouterManifests" | "lastDiscoveryError">, hasMainRunner: boolean): boolean;
201
208
  export declare function createDiscoveryState(entryPath: string | undefined, opts: PluginOptions | undefined): DiscoveryState & ClientUrlDiscoveryState;
@@ -0,0 +1,54 @@
1
+ import type { Plugin } from "vite";
2
+ import MagicString from "magic-string";
3
+ /**
4
+ * The key of the predicate `source` declared in `relativeFile` (relative to
5
+ * the project root): a hash of the file and the predicate's syntax, so the
6
+ * same predicate gets one key in every environment and however it is
7
+ * formatted.
8
+ */
9
+ export declare function revalidateKey(relativeFile: string, source: string): string;
10
+ interface HoistClientUrlsRevalidateDeps {
11
+ /** Project root: keys hash the file relative to it. */
12
+ readonly root: string;
13
+ /**
14
+ * Whether a module a predicate imports is a "use client" module beyond its
15
+ * specifier (the plugin resolves it and reads its directive prologue).
16
+ */
17
+ isClientModule?(source: string): Promise<boolean> | boolean;
18
+ }
19
+ interface HoistClientUrlsRevalidateResult {
20
+ /** The module with each predicate replaced by its marker. */
21
+ readonly code: string;
22
+ readonly map: ReturnType<MagicString["generateMap"]>;
23
+ /** The server module that registers every hoisted predicate. */
24
+ readonly module: string;
25
+ /** The keys, in declaration order, duplicates removed. */
26
+ readonly keys: readonly string[];
27
+ }
28
+ /**
29
+ * Hoist every clientUrls() `revalidate()` predicate of a "use client"
30
+ * module. Returns null when there is none. Throws, naming file:line, for a
31
+ * predicate that is not pure.
32
+ */
33
+ export declare function hoistClientUrlsRevalidates(code: string, id: string, deps: HoistClientUrlsRevalidateDeps): Promise<HoistClientUrlsRevalidateResult | null>;
34
+ /** The file a `?rango-revalidate` id names, or null. */
35
+ export declare function parseHoistedRevalidateId(id: string): string | null;
36
+ /**
37
+ * The plugins: a pre transform that hoists in every environment (markers in
38
+ * the client and SSR copies, the server module recorded from the RSC
39
+ * transform) and serves `?rango-revalidate`, and a post transform that
40
+ * appends its import to the RSC client-reference proxy.
41
+ *
42
+ * `load` serves the module the RSC transform emitted, which hoisted the
43
+ * pipeline code; the disk source is re-hoisted only when the transform has
44
+ * not seen the current file (loadEmittedOrDisk). A file whose edit removed
45
+ * every predicate serves an empty module to a proxy that still imports it.
46
+ *
47
+ * The transform's code filter skips a module that never mentions clientUrls,
48
+ * so a file that stops doing so would keep its `emitted` entry: watchChange
49
+ * drops it, together with the cached "use client" answer for an edited
50
+ * dependency (isClientModule memoizes per resolved file; buildStart resets
51
+ * it).
52
+ */
53
+ export declare function clientUrlsRevalidateHoistPlugin(): Plugin[];
54
+ export {};