@rangojs/router 0.5.2 → 0.7.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 (178) hide show
  1. package/dist/bin/rango.js +343 -125
  2. package/dist/types/browser/react/use-router.d.ts +10 -3
  3. package/dist/types/browser/react/use-search-params.d.ts +57 -10
  4. package/dist/types/browser/types.d.ts +22 -0
  5. package/dist/types/build/merge-full-manifests.d.ts +3 -0
  6. package/dist/types/build/route-trie.d.ts +4 -73
  7. package/dist/types/build/route-types/per-module-writer.d.ts +6 -4
  8. package/dist/types/build/route-types/router-processing.d.ts +2 -3
  9. package/dist/types/cache/cache-exec-scope.d.ts +31 -0
  10. package/dist/types/cache/taint.d.ts +12 -6
  11. package/dist/types/client-urls/client-root.d.ts +38 -0
  12. package/dist/types/client-urls/client-urls.d.ts +5 -0
  13. package/dist/types/client-urls/navigation.d.ts +38 -0
  14. package/dist/types/client-urls/revalidation-protocol.d.ts +25 -0
  15. package/dist/types/client-urls/server-projection.d.ts +71 -0
  16. package/dist/types/client-urls/types.d.ts +147 -0
  17. package/dist/types/client.d.ts +12 -4
  18. package/dist/types/client.rsc.d.ts +4 -1
  19. package/dist/types/decode-loader-results.d.ts +37 -0
  20. package/dist/types/errors.d.ts +1 -0
  21. package/dist/types/index.d.ts +1 -1
  22. package/dist/types/loader-redirect.d.ts +27 -0
  23. package/dist/types/outlet-context.d.ts +12 -0
  24. package/dist/types/outlet-provider.d.ts +3 -1
  25. package/dist/types/redirect-origin.d.ts +4 -0
  26. package/dist/types/route-content-wrapper.d.ts +42 -1
  27. package/dist/types/route-definition/helpers-types.d.ts +13 -2
  28. package/dist/types/router/error-handling.d.ts +35 -1
  29. package/dist/types/router/intercept-resolution.d.ts +12 -0
  30. package/dist/types/router/loader-resolution.d.ts +24 -2
  31. package/dist/types/router/revalidation.d.ts +7 -0
  32. package/dist/types/router/route-trie-builder.d.ts +77 -0
  33. package/dist/types/router/router-interfaces.d.ts +20 -0
  34. package/dist/types/router/segment-resolution/helpers.d.ts +1 -1
  35. package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -9
  36. package/dist/types/router/trie-matching.d.ts +1 -1
  37. package/dist/types/rsc/manifest-init.d.ts +5 -5
  38. package/dist/types/rsc/shell-capture.d.ts +9 -0
  39. package/dist/types/rsc/shell-serve.d.ts +11 -0
  40. package/dist/types/rsc/types.d.ts +30 -0
  41. package/dist/types/segment-system.d.ts +2 -0
  42. package/dist/types/server/context.d.ts +10 -0
  43. package/dist/types/server/handle-store.d.ts +34 -3
  44. package/dist/types/server/request-context.d.ts +11 -1
  45. package/dist/types/server.d.ts +1 -0
  46. package/dist/types/ssr/index.d.ts +22 -0
  47. package/dist/types/ssr/ssr-root.d.ts +10 -0
  48. package/dist/types/testing/dom.entry.d.ts +1 -1
  49. package/dist/types/testing/render-route.d.ts +16 -6
  50. package/dist/types/testing/run-loader.d.ts +9 -0
  51. package/dist/types/types/boundaries.d.ts +22 -0
  52. package/dist/types/types/index.d.ts +1 -1
  53. package/dist/types/types/loader-types.d.ts +57 -5
  54. package/dist/types/types/segments.d.ts +7 -0
  55. package/dist/types/urls/path-helper-types.d.ts +13 -4
  56. package/dist/types/vite/discovery/client-urls-projection.d.ts +53 -0
  57. package/dist/types/vite/discovery/discover-routers.d.ts +1 -1
  58. package/dist/types/vite/discovery/state.d.ts +8 -1
  59. package/dist/types/vite/plugins/client-ref-dedup.d.ts +0 -11
  60. package/dist/vite/index.js +6159 -2959
  61. package/package.json +6 -5
  62. package/skills/breadcrumbs/SKILL.md +39 -9
  63. package/skills/catalog.json +7 -1
  64. package/skills/client-urls/SKILL.md +338 -0
  65. package/skills/comparison/references/framework-comparison.md +23 -9
  66. package/skills/hooks/SKILL.md +2 -2
  67. package/skills/hooks/data.md +11 -2
  68. package/skills/hooks/handle-and-actions.md +7 -0
  69. package/skills/hooks/outlets.md +26 -5
  70. package/skills/hooks/urls.md +40 -3
  71. package/skills/loader/SKILL.md +132 -20
  72. package/skills/migrate-nextjs/SKILL.md +70 -10
  73. package/skills/migrate-react-router/SKILL.md +49 -13
  74. package/skills/migrate-react-router/component-migration.md +18 -13
  75. package/skills/migrate-react-router/data-and-actions.md +14 -3
  76. package/skills/migrate-react-router/route-mapping.md +15 -2
  77. package/skills/parallel/SKILL.md +32 -1
  78. package/skills/ppr/SKILL.md +16 -6
  79. package/skills/prerender/SKILL.md +8 -4
  80. package/skills/rango/SKILL.md +21 -17
  81. package/skills/react-compiler/SKILL.md +3 -3
  82. package/skills/route/SKILL.md +5 -2
  83. package/skills/router-setup/SKILL.md +16 -2
  84. package/skills/scripts/SKILL.md +16 -6
  85. package/skills/shell-manifest/SKILL.md +16 -7
  86. package/skills/testing/SKILL.md +2 -2
  87. package/skills/testing/client-components.md +6 -0
  88. package/skills/testing/handles.md +30 -8
  89. package/skills/testing/loader.md +51 -49
  90. package/skills/testing/middleware.md +1 -1
  91. package/skills/theme/SKILL.md +8 -5
  92. package/src/bin/rango.ts +7 -3
  93. package/src/browser/navigation-bridge.ts +6 -0
  94. package/src/browser/navigation-client.ts +5 -0
  95. package/src/browser/partial-update.ts +65 -13
  96. package/src/browser/react/use-router.ts +40 -11
  97. package/src/browser/react/use-search-params.ts +140 -17
  98. package/src/browser/rsc-router.tsx +59 -0
  99. package/src/browser/server-action-bridge.ts +26 -0
  100. package/src/browser/types.ts +22 -0
  101. package/src/build/merge-full-manifests.ts +161 -0
  102. package/src/build/route-trie.ts +9 -332
  103. package/src/build/route-types/include-resolution.ts +66 -11
  104. package/src/build/route-types/per-module-writer.ts +11 -6
  105. package/src/build/route-types/router-processing.ts +184 -153
  106. package/src/build/runtime-discovery.ts +23 -12
  107. package/src/cache/cache-exec-scope.ts +47 -0
  108. package/src/cache/cache-runtime.ts +24 -25
  109. package/src/cache/taint.ts +28 -9
  110. package/src/client-urls/client-root.tsx +168 -0
  111. package/src/client-urls/client-urls.ts +776 -0
  112. package/src/client-urls/navigation.ts +237 -0
  113. package/src/client-urls/revalidation-protocol.ts +56 -0
  114. package/src/client-urls/server-projection.ts +670 -0
  115. package/src/client-urls/types.ts +201 -0
  116. package/src/client.rsc.tsx +12 -0
  117. package/src/client.tsx +49 -6
  118. package/src/decode-loader-results.ts +113 -0
  119. package/src/errors.ts +14 -0
  120. package/src/handles/deferred-resolution.ts +14 -7
  121. package/src/index.ts +1 -0
  122. package/src/loader-redirect.tsx +64 -0
  123. package/src/outlet-context.ts +12 -0
  124. package/src/outlet-provider.tsx +15 -1
  125. package/src/redirect-origin.ts +29 -0
  126. package/src/route-content-wrapper.tsx +96 -3
  127. package/src/route-definition/dsl-helpers.ts +28 -3
  128. package/src/route-definition/helpers-types.ts +13 -0
  129. package/src/route-definition/redirect.ts +17 -18
  130. package/src/router/error-handling.ts +65 -11
  131. package/src/router/intercept-resolution.ts +29 -0
  132. package/src/router/loader-resolution.ts +261 -28
  133. package/src/router/match-result.ts +7 -0
  134. package/src/router/revalidation.ts +24 -11
  135. package/src/router/route-trie-builder.ts +334 -0
  136. package/src/router/router-interfaces.ts +38 -0
  137. package/src/router/segment-resolution/fresh.ts +55 -2
  138. package/src/router/segment-resolution/helpers.ts +9 -11
  139. package/src/router/segment-resolution/loader-cache.ts +34 -23
  140. package/src/router/segment-resolution/loader-mask.ts +9 -9
  141. package/src/router/segment-resolution/revalidation.ts +23 -2
  142. package/src/router/trie-matching.ts +3 -3
  143. package/src/router.ts +46 -1
  144. package/src/rsc/full-payload.ts +6 -0
  145. package/src/rsc/handler.ts +10 -7
  146. package/src/rsc/loader-fetch.ts +2 -2
  147. package/src/rsc/manifest-init.ts +28 -9
  148. package/src/rsc/rsc-rendering.ts +15 -1
  149. package/src/rsc/shell-capture.ts +12 -0
  150. package/src/rsc/shell-serve.ts +15 -2
  151. package/src/rsc/ssr-setup.ts +10 -1
  152. package/src/rsc/types.ts +31 -2
  153. package/src/segment-system.tsx +83 -26
  154. package/src/server/context.ts +10 -0
  155. package/src/server/cookie-store.ts +19 -19
  156. package/src/server/handle-store.ts +185 -48
  157. package/src/server/request-context.ts +30 -6
  158. package/src/server.ts +7 -0
  159. package/src/ssr/index.tsx +37 -2
  160. package/src/ssr/ssr-root.tsx +29 -2
  161. package/src/testing/dom.entry.ts +1 -1
  162. package/src/testing/render-route.tsx +22 -8
  163. package/src/testing/run-loader.ts +51 -13
  164. package/src/types/boundaries.ts +19 -0
  165. package/src/types/index.ts +1 -0
  166. package/src/types/loader-types.ts +60 -5
  167. package/src/types/segments.ts +7 -0
  168. package/src/urls/include-helper.ts +22 -4
  169. package/src/urls/path-helper-types.ts +17 -1
  170. package/src/use-loader.tsx +67 -6
  171. package/src/vite/discovery/client-urls-projection.ts +322 -0
  172. package/src/vite/discovery/discover-routers.ts +43 -17
  173. package/src/vite/discovery/state.ts +11 -1
  174. package/src/vite/discovery/virtual-module-codegen.ts +20 -0
  175. package/src/vite/plugins/client-ref-dedup.ts +281 -19
  176. package/src/vite/plugins/expose-action-id.ts +45 -23
  177. package/src/vite/plugins/virtual-entries.ts +12 -3
  178. package/src/vite/router-discovery.ts +163 -12
@@ -273,6 +273,15 @@ export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>,
273
273
  */
274
274
  export interface ShellCaptureDescriptor {
275
275
  key: string;
276
+ /**
277
+ * The key's search portion (shellSearchSeed: `?`-prefixed sorted search,
278
+ * cache.searchParams filter applied, or ""). Seeds the capture render's SSR
279
+ * store so static-part `useSearchParams` reads bake markup consistent with
280
+ * the shell's own key; the resume pass derives the identical string from
281
+ * the HIT request. Computed next to the key so the two cannot drift.
282
+ * Omitted (build-time bare-pathname captures) = search-less, same as "".
283
+ */
284
+ searchSeed?: string;
276
285
  /**
277
286
  * The RSC handler's build version (HandlerContext.version), stamped into the
278
287
  * stored entry as ShellCacheEntry.buildVersion — the serve-side
@@ -94,6 +94,17 @@ export declare function resolvePprConfig(entry: EntryData | undefined | null): R
94
94
  * and lookup makes every shell request a permanent miss.
95
95
  */
96
96
  export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
97
+ /**
98
+ * The shell key's search portion (`?`-prefixed sorted search with the
99
+ * cache.searchParams filter applied, or "") — ALSO the string the capture and
100
+ * resume SSR renders seed their store location with (SSRRenderOptions.search
101
+ * / ShellCaptureOptions.search / ShellResumeOptions.search). Search is part
102
+ * of shell identity, so static-part `useSearchParams` reads render exactly
103
+ * what the key names; deriving seed and key from this one helper is what
104
+ * keeps capture, resume, and lookup byte-agreed (drift = replay mismatch or
105
+ * permanent MISS).
106
+ */
107
+ export declare function shellSearchSeed(url: URL, filter?: SearchParamsFilter): string;
97
108
  /**
98
109
  * Version gates for a stored shell: reactVersion AND buildVersion must both
99
110
  * match the running server. The postponed blob encodes hole positions against
@@ -33,12 +33,29 @@ export interface RscPayload {
33
33
  /** Merged route params from the matched route */
34
34
  params?: Record<string, string>;
35
35
  slots?: Record<string, SlotState>;
36
+ /**
37
+ * Intercept TARGET route names reachable from this location as a
38
+ * navigation origin (see MatchResult.interceptTargets). The browser-local
39
+ * clientUrls matcher declines optimistic presentation for these.
40
+ */
41
+ interceptTargets?: string[];
36
42
  /** Root layout component for browser-side re-renders (client component reference) */
37
43
  rootLayout?: React.ComponentType<{
38
44
  children: React.ReactNode;
39
45
  }>;
40
46
  /** Handle data accumulated across route segments (async generator that yields on each push) */
41
47
  handles?: AsyncGenerator<HandleData, void, unknown>;
48
+ /**
49
+ * Document-lane late handle channel: full-state updates for pushes landing
50
+ * AFTER the handler barrier (streaming loader bodies writing handles
51
+ * mid-body). `handles` above is drained to completion in blocking
52
+ * positions (SSR seed, pre-hydration), so late pushes need this separate
53
+ * generator, consumed non-blocking post-hydration (rsc-router.tsx).
54
+ * Empty/instantly-complete when no auxiliary-lane work is pending at the
55
+ * handler barrier. Full payloads only — partial payloads' `handles`
56
+ * generator streams to full settle already.
57
+ */
58
+ handlesLate?: AsyncGenerator<HandleData, void, unknown>;
42
59
  /** RSC version string for cache invalidation */
43
60
  version?: string;
44
61
  /** Cloudflare dev worker generation used for stale-document convergence. */
@@ -147,6 +164,17 @@ export interface SSRRenderOptions {
147
164
  * - `"allReady"` — await `stream.allReady` before returning.
148
165
  */
149
166
  streamMode?: import("../router/router-options.js").SSRStreamMode;
167
+ /**
168
+ * The live request's query string (`url.search`, `?`-prefixed or empty).
169
+ * Seeds the SSR navigation store so `useSearchParams` (and
170
+ * `useNavigation().location`) carry real values during document renders.
171
+ * Out-of-band by design — never payload metadata, which cached/prerendered
172
+ * payloads replay; search is not route identity. The build-time prerender
173
+ * pass passes none — build shells capture bare pathnames and serve
174
+ * search-less requests only (runtime ppr captures seed the shell key's
175
+ * search; see ShellCaptureOptions.search in the SSR entry).
176
+ */
177
+ search?: string;
150
178
  }
151
179
  /**
152
180
  * SSR module interface for HTML rendering
@@ -164,6 +192,7 @@ export interface SSRModule {
164
192
  captureShellHTML?: (rscStream: ReadableStream<Uint8Array>, options: {
165
193
  quiesce: Promise<void>;
166
194
  maxWaitMs?: number;
195
+ search?: string;
167
196
  }) => Promise<{
168
197
  prelude: Uint8Array;
169
198
  postponed: string | null;
@@ -179,6 +208,7 @@ export interface SSRModule {
179
208
  resumeShellHTML?: (rscStream: ReadableStream<Uint8Array>, options: {
180
209
  postponed: string | null;
181
210
  nonce?: string;
211
+ search?: string;
182
212
  }) => Promise<ReadableStream<Uint8Array>>;
183
213
  }
184
214
  /**
@@ -17,6 +17,8 @@ export interface RenderSegmentsOptions {
17
17
  * from cache without showing loading skeletons.
18
18
  */
19
19
  forceAwait?: boolean;
20
+ /** Seeded descendant client-route pending state for testing. */
21
+ outletPending?: boolean;
20
22
  /**
21
23
  * Intercept segments to inject into the tree.
22
24
  * These are parallel segments from intercept routes that need to be
@@ -82,6 +82,16 @@ export type LoaderEntry = {
82
82
  revalidate: ShouldRevalidateFn<any, any>[];
83
83
  /** Cache config for this specific loader (loaders are NOT cached by default) */
84
84
  cache?: EntryCacheConfig;
85
+ /**
86
+ * Document renders await this loader before segment resolution returns
87
+ * (loader(Def, { stream: "navigation" })), so its data, handle pushes, and
88
+ * thrown notFound()/redirect() deterministically precede first flush.
89
+ * Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
90
+ * per-isSSR (router/manifest.ts cache key), so the flag is already
91
+ * request-mode-correct when resolveLoaders (fresh.ts) reads it and never
92
+ * appears on navigation-lane entries.
93
+ */
94
+ awaitBeforeFlush?: true;
85
95
  };
86
96
  /**
87
97
  * Segments state for intercept context
@@ -49,6 +49,24 @@ export interface HandleStore {
49
49
  * to onError and telemetry.
50
50
  */
51
51
  onError?: (error: Error) => void;
52
+ /**
53
+ * Track a promise on the AUXILIARY (loader) settlement lane. Aux tracking
54
+ * keeps the store OPEN for pushes (a mid-body `ctx.handle(H)(...)` from a
55
+ * streaming loader is legal until this lane drains) WITHOUT joining
56
+ * `settled` — the handler barrier that rendered()-readers, the document
57
+ * handle snapshot, and prerender/cache collection wait on. Two lanes exist
58
+ * because loader bodies stream: joining them to `settled` would block SSR
59
+ * markup and hydration on the slowest loader (ssr-root.tsx and
60
+ * rsc-router.tsx both drain the document handle stream in blocking
61
+ * positions), and would self-deadlock any loader awaiting ctx.rendered().
62
+ */
63
+ trackAuxiliary<T>(promise: Promise<T>): Promise<T>;
64
+ /**
65
+ * Promise that resolves when the store is sealed AND BOTH lanes (handler +
66
+ * auxiliary) have drained. Late-push legality and default stream completion
67
+ * key on this, not on `settled`.
68
+ */
69
+ readonly fullySettled: Promise<void>;
52
70
  /**
53
71
  * Push handle data for a specific handle and segment.
54
72
  * Multiple pushes to the same handle/segment accumulate in an array.
@@ -57,15 +75,28 @@ export interface HandleStore {
57
75
  push(handleName: string, segmentId: string, data: unknown): void;
58
76
  /**
59
77
  * Get all collected handle data after all handlers have settled.
60
- * Waits for `settled`, then returns the finalized data.
78
+ * Waits for `settled` (handler lane), then returns the data at that point.
61
79
  */
62
80
  getData(): Promise<HandleData>;
63
81
  /**
64
82
  * Get an async iterator that yields handle data on each push.
65
- * The iterator completes when all handlers have settled.
83
+ * Completes at the chosen settlement barrier: "fullySettled" (default —
84
+ * nav/action payloads, whose consumer applies each yield progressively) or
85
+ * "settled" (the document lane, whose consumers drain to completion in
86
+ * blocking positions and must not wait on loader bodies).
66
87
  * Each yield contains the full accumulated state (not just the delta).
88
+ * Safe for concurrent consumers (per-consumer version cursor).
89
+ */
90
+ stream(until?: "settled" | "fullySettled"): AsyncGenerator<HandleData, void, unknown>;
91
+ /**
92
+ * Document-lane late channel: yields full-state updates for pushes that
93
+ * land AFTER the handler barrier (streaming loader bodies), completing at
94
+ * fullySettled. Returns without yielding when the auxiliary lane is empty
95
+ * by the time `settled` resolves. The client consumes this post-hydration
96
+ * (rsc-router.tsx) and merges via the same application path as nav-lane
97
+ * progressive handle updates.
67
98
  */
68
- stream(): AsyncGenerator<HandleData, void, unknown>;
99
+ streamLate(): AsyncGenerator<HandleData, void, unknown>;
69
100
  /**
70
101
  * Get handle data for a specific segment (for caching).
71
102
  * Returns data in format: { handleName: [values...] }
@@ -507,6 +507,16 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
507
507
  * rendered() and a handler already awaits it, we can detect the deadlock.
508
508
  */
509
509
  _handlerLoaderDeps?: Set<string>;
510
+ /**
511
+ * @internal Loader IDs ($$id) whose entries carry `awaitBeforeFlush`
512
+ * (loader(Def, { stream: "navigation" })): segment resolution awaits these
513
+ * before returning, so the render barrier cannot resolve until they settle.
514
+ * rendered() checks this set to fail fast — a flagged loader awaiting the
515
+ * barrier is a guaranteed cycle, not a race. Registered by resolveLoaders
516
+ * (fresh.ts) before loader kickoff; only ever populated on document renders
517
+ * (the flag is stamped per-isSSR at DSL evaluation).
518
+ */
519
+ _awaitBeforeFlushLoaderIds?: Set<string>;
510
520
  /**
511
521
  * @internal Cached HandleData snapshot built at barrier resolution time.
512
522
  * Avoids rebuilding the snapshot on every loader ctx.use(handle) call.
@@ -588,7 +598,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
588
598
  * This is the type exported to library consumers. Internal code should
589
599
  * use the full RequestContext interface directly.
590
600
  */
591
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhen" | "_pprTransitionDecisions" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureHandleLiveness" | "_shellCaptureLoaderHandleValues" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_locationState" | "_routeName" | "_prevRouteKey" | "_gateCurrentUrl" | "_gateCurrentParams" | "_gateActionId" | "_gateActionUrl" | "_gateActionResult" | "_gateFormData" | "_inActionRevalidation" | "_reportedErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
601
+ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhen" | "_pprTransitionDecisions" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureHandleLiveness" | "_shellCaptureLoaderHandleValues" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_locationState" | "_routeName" | "_prevRouteKey" | "_gateCurrentUrl" | "_gateCurrentParams" | "_gateActionId" | "_gateActionUrl" | "_gateActionResult" | "_gateFormData" | "_inActionRevalidation" | "_reportedErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
592
602
  /**
593
603
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
594
604
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -13,3 +13,4 @@ export { registerRouteMap, setCachedManifest, clearCachedManifest, clearAllRoute
13
13
  export { registerLoaderById, setLoaderImports, } from "./server/loader-registry.js";
14
14
  export { createRequestContext, type CreateRequestContextOptions, } from "./server/request-context.js";
15
15
  export { isClientComponent, assertClientComponent } from "./component-utils.js";
16
+ export { clearClientUrlProjections, setClientUrlProjection, type ClientUrlProjection, } from "./client-urls/server-projection.js";
@@ -82,6 +82,14 @@ export interface SSRRenderOptions {
82
82
  * - `"allReady"` — await `stream.allReady` before returning.
83
83
  */
84
84
  streamMode?: import("../router/router-options.js").SSRStreamMode;
85
+ /**
86
+ * The live request's query string (`?`-prefixed or empty). Seeds the SSR
87
+ * navigation store location so `useSearchParams` carries real values
88
+ * during document renders. Absent on the build-time prerender pass —
89
+ * build shells capture bare pathnames and serve search-less requests
90
+ * only (runtime captures own the search variants, seeded per key).
91
+ */
92
+ search?: string;
85
93
  }
86
94
  /**
87
95
  * SSR dependencies from external packages
@@ -169,6 +177,13 @@ interface ShellCaptureOptions {
169
177
  quiesce: Promise<void>;
170
178
  /** Upper bound on how long to wait for `quiesce`. Default SHELL_CAPTURE_MAX_WAIT_MS. */
171
179
  maxWaitMs?: number;
180
+ /**
181
+ * The SHELL KEY's search string (`?`-prefixed, sorted, cache.searchParams
182
+ * filter applied — shellSearchSeed in rsc/shell-serve.ts), seeding the SSR
183
+ * store so static-part `useSearchParams` reads bake markup consistent with
184
+ * the shell's own key. MUST equal the resume pass's seed for the same key.
185
+ */
186
+ search?: string;
172
187
  }
173
188
  /**
174
189
  * Result of a successful shell capture. `prelude` is the raw prelude bytes;
@@ -188,6 +203,13 @@ interface ShellResumeOptions {
188
203
  postponed: string | null;
189
204
  /** Nonce for CSP. */
190
205
  nonce?: string;
206
+ /**
207
+ * The SHELL KEY's search string — same derivation as the capture pass
208
+ * (shellSearchSeed). A HIT shares the capture's key, so seeding the same
209
+ * string keeps the resume tree identical to the captured tree above the
210
+ * postponed holes.
211
+ */
212
+ search?: string;
191
213
  }
192
214
  /**
193
215
  * Create an SSR handler that converts RSC streams to HTML.
@@ -48,6 +48,16 @@ export interface SsrRootOptions {
48
48
  * they postpone below the root.
49
49
  */
50
50
  onPayloadSettled?: () => void;
51
+ /**
52
+ * The query string seeding the SSR store location (`?`-prefixed or
53
+ * empty), so `useSearchParams`/`useNavigation` carry real values during
54
+ * document renders. Live fizz passes the request's raw search. The shell
55
+ * capture and resume passes pass the SHELL KEY's search (sorted,
56
+ * cache.searchParams filter applied — search is part of shell identity):
57
+ * a HIT shares the capture's key, so both passes seed the SAME string and
58
+ * the resume tree matches the captured tree above the postponed holes.
59
+ */
60
+ search?: string;
51
61
  }
52
62
  /**
53
63
  * Build the closure component that deserializes the Flight payload, consumes
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Component-render testing: `renderRoute`, the React-Testing-Library-style stub
5
5
  * for client components that read router context (useParams / useReverse /
6
- * Outlet / useNavigation / useLoader).
6
+ * Outlet / useOutlet / useNavigation / useLoader).
7
7
  *
8
8
  * Separate from the main `@rangojs/router/testing` barrel so unit suites that
9
9
  * only test loaders, middleware, or `dispatch` never reference React, the
@@ -19,18 +19,19 @@
19
19
  * props crossing the RSC boundary), loader execution on the server,
20
20
  * middleware, or handler ordering. Those are renderServerTree / renderHandler
21
21
  * / e2e territory.
22
- * - Loader data, location state, and handle output are SEEDED directly into
23
- * client context (see the `loaders` / `locationState` / `handles` options) —
24
- * nothing is executed on the server. This exercises the read path
25
- * (useLoader / useLocationState / useHandle from context), not the run path.
22
+ * - Loader data, location state, handle output, and outlet pending state are
23
+ * SEEDED directly into client context (see the `loaders` / `locationState` /
24
+ * `handles` / `outletPending` options) — nothing is executed on the server.
25
+ * This exercises the context read path, not the run path.
26
26
  * - navigate() commits synchronously, so it does NOT drive the navigation
27
27
  * lifecycle: useNavigation().state, useLinkStatus().pending, and
28
28
  * useAction().state stay "idle". Assert pending/loading/submitting transition
29
29
  * states with renderServerTree / e2e instead (navigate() warns once if used).
30
30
  * What it DOES cover: client hooks that read NavigationProvider /
31
31
  * OutletContext — useParams, useReverse, useHref, useMount, useNavigation,
32
- * useRouter, usePathname, useSearchParams, Outlet nesting, useLoader /
33
- * useFetchLoader (seeded data), useLocationState (seeded), and useHandle (seeded).
32
+ * useRouter, usePathname, useSearchParams, Outlet/useOutlet nesting and seeded
33
+ * descendant pending state, useLoader/useFetchLoader (seeded data),
34
+ * useLocationState (seeded), and useHandle (seeded).
34
35
  * Basename-mounted apps: pass the `basename` option so useRouter().basename,
35
36
  * <Link> prefixing, and useMount/useHref resolve against the mount prefix
36
37
  * (without it they resolve at the root "/"). For an include("/shop", ...)
@@ -96,6 +97,15 @@ export interface RenderRouteOptions {
96
97
  * the read path is exercised without executing any loader.
97
98
  */
98
99
  loaderData?: Record<string, unknown>;
100
+ /**
101
+ * Descendant client-route pending state to seed into each synthetic segment's
102
+ * production OutletProvider, so `useOutlet().pending` can be tested alongside
103
+ * `useOutlet().content`. Defaults to false.
104
+ *
105
+ * This is a seeded outlet-context value only. It does not model arbitrary
106
+ * Suspense, navigation, or action pending state.
107
+ */
108
+ outletPending?: boolean;
99
109
  /**
100
110
  * Loaders to seed by REFERENCE — the robust way to test a component that calls
101
111
  * `useLoader(loader)`. A real `createLoader()` handle has an empty `$$id` in a
@@ -52,6 +52,7 @@ export type TestLoaderContext<TEnv = any> = Omit<LoaderContext<any, TEnv>, "reve
52
52
  reverse: (name: string, params?: Record<string, string>, search?: Record<string, unknown>) => string;
53
53
  get: {
54
54
  <T>(contextVar: ContextVar<T>): T | undefined;
55
+ <TData, TAccumulated = TData[]>(handle: Handle<TData, TAccumulated>): TAccumulated;
55
56
  <T = unknown>(key: string): T | undefined;
56
57
  };
57
58
  };
@@ -182,5 +183,13 @@ export interface RunLoaderResult<T> {
182
183
  locationState: Record<string, unknown>;
183
184
  /** The resolved rango state cookie name seeded for the run (default `rango-state_router_0`). */
184
185
  stateCookieName: string;
186
+ /**
187
+ * Handle writes the loader made via `ctx.use(SomeHandle)({...})`, in push
188
+ * order. A `.defer()` resolver's value is recorded when the resolver runs.
189
+ */
190
+ handlePushes: Array<{
191
+ handle: Handle<any, any>;
192
+ value: unknown;
193
+ }>;
185
194
  }
186
195
  export declare function runLoaderResult<T>(loader: RunnableLoader<T>, opts?: RunLoaderOptions): Promise<RunLoaderResult<T>>;
@@ -63,6 +63,28 @@ export type LoaderDataResult<T = unknown> = {
63
63
  ok: false;
64
64
  error: ErrorInfo;
65
65
  fallback: ReactNode | null;
66
+ /**
67
+ * Loader threw notFound() (DataNotFoundError). `fallback` carries the
68
+ * SERVER-RENDERED not-found UI (nearest notFoundBoundary → router
69
+ * notFound option → default), so the client swaps to 404 presentation
70
+ * with zero extra round trips. Routed by decodeLoaderEntry via
71
+ * LOADER_NOT_FOUND_FALLBACK, not the error-fallback marker.
72
+ */
73
+ notFound?: true;
74
+ /**
75
+ * Loader threw redirect(...) (a 3xx Response). `to` is resolved through
76
+ * the soft-redirect same-origin rules BEFORE leaving the server
77
+ * (resolveSoftRedirectUrl), so unsafe targets never reach the wire. The
78
+ * client navigates (replace) when the entry decodes. `state` is the
79
+ * resolved `redirect(url, { state })` record (`__rsc_ls_*` keys) — it
80
+ * travels on the marker because a streaming loader settles after
81
+ * payload metadata flushed; the redirect navigation merges it at the
82
+ * target entry.
83
+ */
84
+ redirect?: {
85
+ to: string;
86
+ state?: Record<string, unknown>;
87
+ };
66
88
  };
67
89
  export declare function isLoaderDataResult(value: unknown): value is LoaderDataResult;
68
90
  export interface NotFoundInfo {
@@ -6,6 +6,6 @@ export { isLoaderDataResult } from "./boundaries.js";
6
6
  export type { MiddlewareFn, ScopedRouteMap, Handler, HandlerContext, InternalHandlerContext, GenericParams, RevalidateParams, ShouldRevalidateFn, ActionRef, RouteKeys, ExtractRouteParams, HandlersForRouteMap, Revalidate, Middleware, } from "./handler-context.js";
7
7
  export type { ViewTransitionClass, TransitionConfig, TransitionWhenFn, TransitionWhenContext, ResolvedSegment, SegmentMetadata, SlotState, RootLayoutProps, MatchResult, } from "./segments.js";
8
8
  export type { LazyIncludeContext, RouteEntry } from "./route-entry.js";
9
- export type { LoaderContext, LoaderFn, FetchableLoaderOptions, LoadOptions, LoaderDefinition, } from "./loader-types.js";
9
+ export type { LoaderContext, LoaderFn, FetchableLoaderOptions, LoaderOptions, LoadOptions, LoaderDefinition, } from "./loader-types.js";
10
10
  export type { CacheContext, CacheOptions, PartialCacheOptions, EntryCacheConfig, } from "./cache-types.js";
11
11
  export type { ErrorPhase, OnErrorContext, OnErrorCallback, } from "./error-types.js";
@@ -1,5 +1,6 @@
1
1
  import type { ContextVar } from "../context-var.js";
2
2
  import type { Handle } from "../handle.js";
3
+ import type { HandlePush } from "../defer.js";
3
4
  import type { MiddlewareFn } from "../router/middleware.js";
4
5
  import type { ScopedReverseFunction } from "../reverse.js";
5
6
  import type { SearchSchema, ResolveSearchSchema } from "../search-params.js";
@@ -41,24 +42,50 @@ export type LoaderContext<TParams = Record<string, string | undefined>, TEnv = D
41
42
  */
42
43
  routeParams: Record<string, string>;
43
44
  search: {} extends TSearch ? {} : ResolveSearchSchema<TSearch>;
45
+ /**
46
+ * Read a context variable — or READ collected handle data after
47
+ * `await ctx.rendered()` (the rendered-barrier contract; handle reads
48
+ * moved here from ctx.use(handle), which is now the write).
49
+ */
44
50
  get: {
45
51
  <T>(contextVar: ContextVar<T>): T | undefined;
52
+ <TData, TAccumulated = TData[]>(handle: Handle<TData, TAccumulated>): TAccumulated;
46
53
  } & (<K extends keyof DefaultVars>(key: K) => DefaultVars[K]);
47
54
  /**
48
- * Access another loader's data, or read handle data after rendered().
55
+ * Access another loader's data, or WRITE handle data (meta, breadcrumbs, …)
56
+ * — handler parity: `ctx.use(Meta)({ title })` pushes exactly like it does
57
+ * in a handler. Handle READS live on `ctx.get(handle)` (after rendered()).
49
58
  *
50
59
  * For loaders: returns a promise (loaders run in parallel).
51
- * For handles: returns collected data (only after `await ctx.rendered()`).
60
+ * For handles: returns the push function, legal for the whole body,
61
+ * streaming loaders included. Delivery is async by the race model: pushes
62
+ * that settle before the handler barrier ride the SSR handle snapshot;
63
+ * later ones stream to the client and apply post-hydration (document lane)
64
+ * or progressively (navigation/action lanes). To guarantee a loader's
65
+ * handles are in the SSR'd document, register it as
66
+ * `loader(Def, { stream: "navigation" })` so the document render awaits it
67
+ * (see {@link LoaderOptions}).
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * export const ProductLoader = createLoader(async (ctx) => {
72
+ * "use server";
73
+ * const product = await getProduct(ctx.params.slug);
74
+ * ctx.use(Meta)({ title: product.name });
75
+ * ctx.use(Breadcrumbs)({ label: product.name });
76
+ * return product;
77
+ * });
78
+ * ```
52
79
  */
53
80
  use: {
54
81
  <T, TLoaderParams = any>(loader: LoaderDefinition<T, TLoaderParams>): Promise<T>;
55
- <TData, TAccumulated = TData[]>(handle: Handle<TData, TAccumulated>): TAccumulated;
82
+ <TData, TAccumulated = TData[]>(handle: Handle<TData, TAccumulated>): HandlePush<TData>;
56
83
  };
57
84
  /**
58
85
  * **Experimental.** Wait for all non-loader segments to settle.
59
86
  *
60
87
  * After the returned promise resolves, handle data is available via
61
- * `ctx.use(handle)`. Supported in DSL loaders, including on streaming
88
+ * `ctx.get(handle)`. Supported in DSL loaders, including on streaming
62
89
  * trees that use `loading()` — the barrier waits for the streaming
63
90
  * handlers to finish pushing before it resolves. Throws if called from a
64
91
  * handler-invoked loader, or if a handler is already awaiting this loader
@@ -70,7 +97,7 @@ export type LoaderContext<TParams = Record<string, string | undefined>, TEnv = D
70
97
  * const PricesLoader = createLoader(async (ctx) => {
71
98
  * "use server";
72
99
  * await ctx.rendered();
73
- * const products = ctx.use(Products); // reads handle data
100
+ * const products = ctx.get(Products); // reads handle data
74
101
  * return pricing.getLive(products.map(p => p.id));
75
102
  * });
76
103
  * ```
@@ -121,6 +148,31 @@ export type LoaderContext<TParams = Record<string, string | undefined>, TEnv = D
121
148
  * ```
122
149
  */
123
150
  export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = DefaultEnv> = (ctx: LoaderContext<TParams, TEnv>) => Promise<T> | T;
151
+ /**
152
+ * Delivery mode for a DSL-registered loader: `loader(Def, { stream })`.
153
+ *
154
+ * Default (omitted): the loader streams on every render. Its data, its
155
+ * `ctx.use(Handle)` pushes, and any `notFound()`/`redirect()` it throws may land
156
+ * AFTER the document Response is constructed, so none of them are guaranteed to
157
+ * be in the SSR'd HTML.
158
+ *
159
+ * `"navigation"` narrows streaming to client navigations only: on a DOCUMENT
160
+ * request the loader is awaited before first flush. `useLoader` still suspends,
161
+ * but on an already-settled promise, so no fallback paints. This is the
162
+ * SSR-completeness opt-in — the name is about WHERE streaming still applies, not
163
+ * about disabling it. Choose it when the loader feeds something that must exist
164
+ * in the document: `<head>` meta via a handle, or a real 404 status (an awaited
165
+ * `notFound()` deterministically precedes Response construction, where the
166
+ * streamed default only wins that race opportunistically). It does NOT change
167
+ * PPR capture behavior: capture renders mask loaders and skip this await.
168
+ *
169
+ * Scoped per LOADER, not per segment: a baked loader alongside a deliberately
170
+ * dynamic sibling awaits only itself, and the sibling keeps streaming behind its
171
+ * `loading()`/Suspense boundary.
172
+ */
173
+ export type LoaderOptions = {
174
+ stream?: "navigation";
175
+ };
124
176
  /**
125
177
  * Options for fetchable loaders
126
178
  *
@@ -221,6 +221,13 @@ export interface MatchResult {
221
221
  * Slots are used for intercepting routes during soft navigation
222
222
  */
223
223
  slots?: Record<string, SlotState>;
224
+ /**
225
+ * Intercept TARGET route names reachable when this location is a navigation
226
+ * origin (chain walk of the matched entry, when-conditionals included).
227
+ * Shipped in payload metadata so the browser-local clientUrls matcher can
228
+ * decline its optimistic presentation for targets an intercept would claim.
229
+ */
230
+ interceptTargets?: string[];
224
231
  /**
225
232
  * Redirect URL for trailing slash normalization.
226
233
  * When set, the RSC handler should return a 308 redirect to this URL
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
- import type { ErrorBoundaryHandler, ExtractParams, Handler, HandlerContext, LoaderDefinition, MiddlewareFn, NotFoundBoundaryHandler, PartialCacheOptions, ShouldRevalidateFn, TransitionConfig } from "../types.js";
2
+ import type { ErrorBoundaryHandler, ExtractParams, Handler, HandlerContext, LoaderDefinition, LoaderOptions, MiddlewareFn, NotFoundBoundaryHandler, PartialCacheOptions, ShouldRevalidateFn, TransitionConfig } from "../types.js";
3
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";
4
4
  import type { SearchSchema } from "../search-params.js";
5
5
  import type { PrerenderHandlerDefinition, PassthroughHandlerDefinition } from "../prerender.js";
@@ -7,6 +7,7 @@ import type { StaticHandlerDefinition, StaticHandlerRef } from "../static-handle
7
7
  import type { ResponseHandler, ResponseHandlerContext, TextResponseHandler } from "./response-types.js";
8
8
  import type { UnnamedRoute, LocalOnlyInclude, PathOptions, UrlPatterns, IncludeOptions } from "./pattern-types.js";
9
9
  import type { ExtractRoutes, ExtractResponses } from "./type-extraction.js";
10
+ import type { ClientUrlPatterns } from "../client-urls/types.js";
10
11
  /**
11
12
  * Base path function signature for defining routes with URL patterns.
12
13
  */
@@ -45,7 +46,7 @@ type IncludeResolved<TEnv, TRoutes extends Record<string, any>, TResponses exten
45
46
  default: UrlPatterns<TEnv, TRoutes, TResponses>;
46
47
  };
47
48
  /** include() argument: an eager `urls()` value or an async provider thunk. */
48
- export type IncludeArg<TEnv, TRoutes extends Record<string, any>, TResponses extends Record<string, unknown>> = UrlPatterns<TEnv, TRoutes, TResponses> | (() => IncludeResolved<TEnv, TRoutes, TResponses> | Promise<IncludeResolved<TEnv, TRoutes, TResponses>>);
49
+ export type IncludeArg<TEnv, TRoutes extends Record<string, any>, TResponses extends Record<string, unknown>> = UrlPatterns<TEnv, TRoutes, TResponses> | ClientUrlPatterns<TRoutes> | (() => IncludeResolved<TEnv, TRoutes, TResponses> | Promise<IncludeResolved<TEnv, TRoutes, TResponses>>);
49
50
  /**
50
51
  * Base include function signature.
51
52
  */
@@ -145,9 +146,17 @@ export type PathHelpers<TEnv> = {
145
146
  */
146
147
  revalidate: (fn: ShouldRevalidateFn<any, TEnv>) => RevalidateItem;
147
148
  /**
148
- * Attach a data loader to the current route/layout
149
+ * Attach a data loader to the current route/layout.
150
+ *
151
+ * Pass `{ stream: "navigation" }` to await this loader before first flush
152
+ * on DOCUMENT requests (see {@link LoaderOptions}) — the opt-in for loaders
153
+ * whose data, handle pushes, or thrown notFound()/redirect() must be in the
154
+ * SSR'd HTML. Per-loader: a dynamic sibling keeps streaming. Under a
155
+ * `ppr` route the flag BAKES: the loader executes at shell capture and
156
+ * its settled return freezes into the shell (nested promises stay live
157
+ * holes) — the pre-flush promise applied to the prelude.
149
158
  */
150
- loader: <TData>(loaderDef: LoaderDefinition<TData>, use?: () => LoaderUseItem[]) => LoaderItem;
159
+ loader: <TData>(loaderDef: LoaderDefinition<TData>, optionsOrUse?: LoaderOptions | (() => LoaderUseItem[]), use?: () => LoaderUseItem[]) => LoaderItem;
151
160
  /**
152
161
  * Attach a loading component to the current route/layout
153
162
  */
@@ -0,0 +1,53 @@
1
+ import { type ClientUrlProjection } from "../../client-urls/server-projection.js";
2
+ import type { DiscoveryState } from "./state.js";
3
+ interface ClientUrlSsrEnvironment {
4
+ readonly runner?: {
5
+ import(id: string): Promise<Record<string, unknown>>;
6
+ };
7
+ }
8
+ interface ClientUrlProjectionServerModule {
9
+ clearClientUrlProjections(): void;
10
+ setClientUrlProjection(referenceId: string, projection: ClientUrlProjection): void;
11
+ }
12
+ export declare function recordClientUrlsModule(state: DiscoveryState, code: string, id: string): void;
13
+ export declare function resolveClientUrlsSource(state: DiscoveryState, referenceId: string): string | undefined;
14
+ /**
15
+ * Deterministic filesystem discovery of clientUrls modules. Transform-based
16
+ * recording only sees modules that some environment actually loads — a
17
+ * clientUrls module not yet reachable from any transformed graph at discovery
18
+ * time (cold ordering, a mount added before its first import is served) would
19
+ * never be recorded and its include would fail with empty projections. Walking
20
+ * the project source (the same walk static route-type generation performs)
21
+ * makes recording independent of module-graph timing. The transform hooks
22
+ * still record too — they refresh dev HMR edits between scans.
23
+ */
24
+ export declare function scanForClientUrlModules(state: DiscoveryState): void;
25
+ /**
26
+ * Lenient pre-entry projection refresh. Re-serializes every RECORDED clientUrls
27
+ * module before the discovery pass imports the entry, so routers re-created by
28
+ * that import materialize against the CURRENT module contents.
29
+ *
30
+ * Scar: node-preset HMR served stale client-urls routes after a route-shape
31
+ * edit — the clientUrls module is an HMR-accepted client boundary in the rsc
32
+ * graph, and the strict registry-driven pass below only runs AFTER the entry
33
+ * import, so `.routes(reference)` materialized the previous pass's projection.
34
+ *
35
+ * Errors are deliberately swallowed per source (a module mid-edit keeps its
36
+ * last-known projection); the strict discoverClientUrlProjections() pass still
37
+ * surfaces real failures afterwards. No-ops on cold start (nothing recorded
38
+ * yet) and when the SSR runner is unavailable.
39
+ */
40
+ export declare function refreshRecordedClientUrlProjections(state: DiscoveryState, ssrEnv: ClientUrlSsrEnvironment | undefined, serverMod: ClientUrlProjectionServerModule): Promise<void>;
41
+ /**
42
+ * Strict projection discovery over every RECORDED clientUrls module. Recorded
43
+ * modules — not router references — are the source of truth: include() mounts
44
+ * materialize lazily from the projection registry, so there is no router-level
45
+ * reference list to consult. Serializes every source before atomically
46
+ * installing the new projections (a failure preserves last-known state).
47
+ *
48
+ * A recorded source whose file no longer exists is dropped silently
49
+ * (recordClientUrlsModule never un-records, so deletions must self-heal here).
50
+ * A present-but-broken module is a hard error: it is part of the app graph.
51
+ */
52
+ export declare function discoverClientUrlProjections(state: DiscoveryState, ssrEnv: ClientUrlSsrEnvironment | undefined, serverMod: ClientUrlProjectionServerModule): Promise<void>;
53
+ export {};
@@ -14,4 +14,4 @@ import type { DiscoveryState } from "./state.js";
14
14
  * Returns the imported `@rangojs/router/server` module so the caller
15
15
  * can access the RouterRegistry and manifest setters.
16
16
  */
17
- export declare function discoverRouters(state: DiscoveryState, rscEnv: any): Promise<any>;
17
+ export declare function discoverRouters(state: DiscoveryState, rscEnv: any, ssrEnv?: any): Promise<any>;