@rangojs/router 0.15.1 → 0.17.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 (249) hide show
  1. package/README.md +254 -89
  2. package/dist/testing/vitest.js +252 -0
  3. package/dist/types/browser/navigation-transaction.d.ts +6 -0
  4. package/dist/types/browser/partial-update.d.ts +11 -0
  5. package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
  6. package/dist/types/browser/rsc-router.d.ts +1 -1
  7. package/dist/types/browser/scroll-restoration.d.ts +7 -0
  8. package/dist/types/cache/cache-exec-scope.d.ts +18 -1
  9. package/dist/types/cache/cache-scope.d.ts +34 -5
  10. package/dist/types/cache/handle-capture.d.ts +41 -3
  11. package/dist/types/cache/handle-snapshot.d.ts +53 -13
  12. package/dist/types/cache/segment-codec.d.ts +10 -3
  13. package/dist/types/cache/taint.d.ts +1 -1
  14. package/dist/types/cache/types.d.ts +15 -3
  15. package/dist/types/client.d.ts +4 -4
  16. package/dist/types/client.rsc.d.ts +4 -5
  17. package/dist/types/components/DefaultDocument.d.ts +5 -2
  18. package/dist/types/context-var.d.ts +6 -5
  19. package/dist/types/escape-script.d.ts +1 -1
  20. package/dist/types/handles/MetaTags.d.ts +5 -4
  21. package/dist/types/handles/Scripts.d.ts +8 -7
  22. package/dist/types/handles/meta.d.ts +2 -2
  23. package/dist/types/handles/script.d.ts +17 -16
  24. package/dist/types/href-client.d.ts +1 -1
  25. package/dist/types/html.d.ts +12 -0
  26. package/dist/types/index.d.ts +1 -1
  27. package/dist/types/index.rsc.d.ts +3 -2
  28. package/dist/types/loader-store.d.ts +52 -0
  29. package/dist/types/reverse.d.ts +36 -4
  30. package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
  31. package/dist/types/route-definition/helpers-types.d.ts +36 -10
  32. package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
  33. package/dist/types/route-types.d.ts +3 -1
  34. package/dist/types/router/debug-manifest.d.ts +3 -2
  35. package/dist/types/router/error-handling.d.ts +20 -0
  36. package/dist/types/router/handler-context.d.ts +6 -0
  37. package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
  38. package/dist/types/router/middleware-types.d.ts +3 -2
  39. package/dist/types/router/router-context.d.ts +3 -1
  40. package/dist/types/router/router-interfaces.d.ts +24 -2
  41. package/dist/types/router/router-options.d.ts +8 -5
  42. package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
  43. package/dist/types/router/segment-resolution/loader-cache.d.ts +37 -1
  44. package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
  45. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +3 -3
  46. package/dist/types/router/segment-resolution/mask-nested.d.ts +7 -7
  47. package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
  48. package/dist/types/router/segment-wrappers.d.ts +1 -1
  49. package/dist/types/rsc/response-route-handler.d.ts +1 -1
  50. package/dist/types/rsc/rsc-rendering.d.ts +1 -2
  51. package/dist/types/rsc/shell-capture-constants.d.ts +8 -0
  52. package/dist/types/rsc/shell-capture.d.ts +5 -4
  53. package/dist/types/rsc/ssr-setup.d.ts +6 -6
  54. package/dist/types/rsc/types.d.ts +10 -0
  55. package/dist/types/server/context.d.ts +33 -3
  56. package/dist/types/server/handle-store.d.ts +26 -2
  57. package/dist/types/server/request-context.d.ts +24 -21
  58. package/dist/types/ssr/index.d.ts +15 -0
  59. package/dist/types/static-handler.d.ts +4 -1
  60. package/dist/types/testing/generated-routes.d.ts +2 -2
  61. package/dist/types/testing/internal/context.d.ts +1 -1
  62. package/dist/types/testing/render-route.d.ts +32 -6
  63. package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
  64. package/dist/types/testing/vitest.d.ts +35 -1
  65. package/dist/types/theme/ThemeScript.d.ts +3 -3
  66. package/dist/types/thenable-status.d.ts +9 -0
  67. package/dist/types/types/cache-types.d.ts +14 -10
  68. package/dist/types/types/handler-context.d.ts +14 -0
  69. package/dist/types/types/loader-types.d.ts +8 -6
  70. package/dist/types/urls/response-types.d.ts +3 -12
  71. package/dist/types/use-loader.d.ts +12 -3
  72. package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
  73. package/dist/types/vite/rango.d.ts +1 -1
  74. package/dist/vite/index.js +884 -768
  75. package/package.json +4 -4
  76. package/skills/api-client/SKILL.md +22 -10
  77. package/skills/breadcrumbs/SKILL.md +65 -22
  78. package/skills/bundle-analysis/SKILL.md +22 -22
  79. package/skills/cache-guide/SKILL.md +207 -97
  80. package/skills/caching/SKILL.md +295 -93
  81. package/skills/catalog.json +16 -16
  82. package/skills/client-urls/SKILL.md +53 -31
  83. package/skills/cloudflare/SKILL.md +72 -20
  84. package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
  85. package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
  86. package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
  87. package/skills/comparison/SKILL.md +5 -0
  88. package/skills/comparison/references/framework-comparison.md +39 -33
  89. package/skills/composability/SKILL.md +38 -29
  90. package/skills/css/SKILL.md +10 -13
  91. package/skills/debug-manifest/SKILL.md +74 -31
  92. package/skills/defer-hydration/SKILL.md +2 -1
  93. package/skills/deployment-caching/SKILL.md +6 -1
  94. package/skills/document-cache/SKILL.md +92 -28
  95. package/skills/fonts/SKILL.md +16 -8
  96. package/skills/handler-use/SKILL.md +53 -17
  97. package/skills/hooks/SKILL.md +28 -20
  98. package/skills/hooks/data.md +43 -1
  99. package/skills/hooks/handle-and-actions.md +31 -16
  100. package/skills/hooks/navigation.md +39 -10
  101. package/skills/hooks/outlets.md +13 -6
  102. package/skills/hooks/state.md +37 -15
  103. package/skills/hooks/urls.md +7 -5
  104. package/skills/host-router/SKILL.md +64 -12
  105. package/skills/i18n/SKILL.md +60 -34
  106. package/skills/intercept/SKILL.md +161 -26
  107. package/skills/layout/SKILL.md +106 -50
  108. package/skills/links/SKILL.md +51 -19
  109. package/skills/loader/SKILL.md +242 -106
  110. package/skills/middleware/SKILL.md +119 -23
  111. package/skills/migrate-nextjs/SKILL.md +100 -45
  112. package/skills/migrate-nextjs/backend-host-swap.md +5 -2
  113. package/skills/migrate-react-router/SKILL.md +49 -38
  114. package/skills/migrate-react-router/component-migration.md +25 -6
  115. package/skills/migrate-react-router/data-and-actions.md +18 -5
  116. package/skills/migrate-react-router/route-mapping.md +12 -6
  117. package/skills/mime-routes/SKILL.md +12 -7
  118. package/skills/observability/SKILL.md +28 -14
  119. package/skills/parallel/SKILL.md +75 -39
  120. package/skills/ppr/SKILL.md +345 -150
  121. package/skills/prerender/SKILL.md +189 -100
  122. package/skills/rango/SKILL.md +65 -34
  123. package/skills/react-compiler/SKILL.md +6 -5
  124. package/skills/response-routes/SKILL.md +133 -25
  125. package/skills/route/SKILL.md +165 -60
  126. package/skills/router-setup/SKILL.md +418 -240
  127. package/skills/scripts/SKILL.md +31 -20
  128. package/skills/server-actions/SKILL.md +220 -59
  129. package/skills/shell-manifest/SKILL.md +12 -7
  130. package/skills/streams-and-websockets/SKILL.md +32 -14
  131. package/skills/tailwind/SKILL.md +37 -33
  132. package/skills/testing/SKILL.md +68 -32
  133. package/skills/testing/cache-prerender.md +55 -29
  134. package/skills/testing/client-components.md +59 -6
  135. package/skills/testing/e2e-parity.md +12 -2
  136. package/skills/testing/flight.md +19 -11
  137. package/skills/testing/handles.md +8 -5
  138. package/skills/testing/loader.md +8 -5
  139. package/skills/testing/middleware.md +8 -3
  140. package/skills/testing/predicates.md +120 -0
  141. package/skills/testing/render-handler.md +70 -22
  142. package/skills/testing/response-routes.md +11 -4
  143. package/skills/testing/reverse-and-types.md +20 -14
  144. package/skills/testing/server-actions.md +12 -3
  145. package/skills/testing/server-tree.md +9 -0
  146. package/skills/testing/setup.md +9 -5
  147. package/skills/theme/SKILL.md +106 -29
  148. package/skills/typesafety/SKILL.md +20 -9
  149. package/skills/typesafety/env-and-bindings.md +126 -47
  150. package/skills/typesafety/generated-files-and-cli.md +26 -14
  151. package/skills/typesafety/params-and-search.md +44 -19
  152. package/skills/typesafety/route-types.md +50 -14
  153. package/skills/use-cache/SKILL.md +200 -82
  154. package/skills/vercel/SKILL.md +21 -11
  155. package/skills/view-transitions/SKILL.md +41 -20
  156. package/src/__augment-tests__/augmented.check.ts +26 -1
  157. package/src/browser/index.ts +2 -2
  158. package/src/browser/navigation-bridge.ts +3 -4
  159. package/src/browser/navigation-transaction.ts +22 -2
  160. package/src/browser/partial-update.ts +75 -80
  161. package/src/browser/react/ScrollRestoration.tsx +6 -6
  162. package/src/browser/rsc-router.tsx +1 -1
  163. package/src/browser/scroll-restoration.ts +53 -6
  164. package/src/cache/cache-exec-scope.ts +37 -4
  165. package/src/cache/cache-key-utils.ts +1 -6
  166. package/src/cache/cache-runtime.ts +230 -61
  167. package/src/cache/cache-scope.ts +76 -12
  168. package/src/cache/document-cache.ts +15 -0
  169. package/src/cache/handle-capture.ts +90 -10
  170. package/src/cache/handle-snapshot.ts +132 -28
  171. package/src/cache/segment-codec.ts +26 -7
  172. package/src/cache/tag-invalidation.ts +4 -3
  173. package/src/cache/taint.ts +1 -1
  174. package/src/cache/types.ts +16 -3
  175. package/src/client.rsc.tsx +10 -9
  176. package/src/client.tsx +5 -4
  177. package/src/components/DefaultDocument.tsx +7 -2
  178. package/src/context-var.ts +6 -5
  179. package/src/escape-script.ts +1 -1
  180. package/src/handles/MetaTags.tsx +13 -11
  181. package/src/handles/Scripts.tsx +11 -10
  182. package/src/handles/meta.ts +2 -2
  183. package/src/handles/script.ts +17 -16
  184. package/src/href-client.ts +1 -1
  185. package/src/html.ts +12 -0
  186. package/src/index.rsc.ts +5 -0
  187. package/src/index.ts +1 -0
  188. package/src/loader-store.ts +106 -0
  189. package/src/prerender/build-shell-capture.ts +8 -11
  190. package/src/reverse.ts +44 -4
  191. package/src/route-definition/dsl-helpers.ts +134 -42
  192. package/src/route-definition/helpers-types.ts +36 -10
  193. package/src/route-definition/resolve-handler-use.ts +121 -6
  194. package/src/route-types.ts +2 -3
  195. package/src/router/debug-manifest.ts +10 -2
  196. package/src/router/error-handling.ts +51 -15
  197. package/src/router/handler-context.ts +34 -25
  198. package/src/router/intercept-resolution.ts +125 -39
  199. package/src/router/loader-resolution.ts +56 -11
  200. package/src/router/match-api.ts +12 -17
  201. package/src/router/match-middleware/background-revalidation.ts +161 -96
  202. package/src/router/match-middleware/cache-lookup.ts +93 -10
  203. package/src/router/match-middleware/cache-store.ts +17 -90
  204. package/src/router/middleware-types.ts +3 -5
  205. package/src/router/middleware.ts +52 -9
  206. package/src/router/prerender-match.ts +53 -19
  207. package/src/router/route-snapshot.ts +11 -1
  208. package/src/router/router-context.ts +2 -0
  209. package/src/router/router-interfaces.ts +25 -2
  210. package/src/router/router-options.ts +8 -5
  211. package/src/router/segment-resolution/fresh.ts +44 -12
  212. package/src/router/segment-resolution/loader-cache.ts +205 -45
  213. package/src/router/segment-resolution/loader-mask.ts +12 -22
  214. package/src/router/segment-resolution/loader-snapshot.ts +6 -6
  215. package/src/router/segment-resolution/mask-nested.ts +7 -7
  216. package/src/router/segment-resolution/revalidation.ts +34 -6
  217. package/src/router/segment-wrappers.ts +4 -0
  218. package/src/rsc/render-pipeline.ts +3 -0
  219. package/src/rsc/response-route-handler.ts +11 -3
  220. package/src/rsc/rsc-rendering.ts +8 -45
  221. package/src/rsc/shell-capture-constants.ts +13 -0
  222. package/src/rsc/shell-capture.ts +111 -90
  223. package/src/rsc/ssr-setup.ts +14 -8
  224. package/src/rsc/types.ts +11 -0
  225. package/src/server/context.ts +88 -11
  226. package/src/server/cookie-store.ts +5 -4
  227. package/src/server/handle-store.ts +232 -7
  228. package/src/server/request-context.ts +35 -30
  229. package/src/ssr/index.tsx +40 -7
  230. package/src/ssr-suspension-warning.ts +2 -13
  231. package/src/static-handler.ts +4 -1
  232. package/src/testing/flight-runtime.d.ts +21 -0
  233. package/src/testing/generated-routes.ts +2 -2
  234. package/src/testing/internal/context.ts +1 -1
  235. package/src/testing/internal/flight-client-globals.ts +7 -5
  236. package/src/testing/render-route.tsx +85 -24
  237. package/src/testing/run-loader.ts +5 -1
  238. package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
  239. package/src/testing/vitest.ts +62 -1
  240. package/src/theme/ThemeProvider.tsx +14 -12
  241. package/src/theme/ThemeScript.tsx +3 -3
  242. package/src/thenable-status.ts +16 -0
  243. package/src/types/cache-types.ts +14 -10
  244. package/src/types/handler-context.ts +14 -0
  245. package/src/types/loader-types.ts +8 -6
  246. package/src/urls/response-types.ts +3 -23
  247. package/src/use-loader.tsx +24 -4
  248. package/src/vite/plugins/use-cache-transform.ts +118 -74
  249. package/src/vite/rango.ts +7 -3
@@ -377,9 +377,8 @@ export type DocumentShellCacheEntry = ShellCacheEntry & {
377
377
  /**
378
378
  * The families a shell snapshot pins. The item/segment/response families are
379
379
  * cache-store reads/writes (recorded by RecordingShellStore); the loader family
380
- * pins the settled CONTAINER of a bake-lane loader (a loader on an entry with
381
- * no renderable loading(), executed during capture — see
382
- * docs/design/loader-container-bake.md). Excludes the shell family itself
380
+ * pins the settled CONTAINER of a bake-lane loader (lane rule: see
381
+ * resolveLoaderData, loader-cache.ts). Excludes the shell family itself
383
382
  * (getShell/putShell) — the snapshot rides INSIDE a shell entry, so recording
384
383
  * it would be self-referential.
385
384
  */
@@ -481,6 +480,11 @@ export interface CachedEntryData {
481
480
  * (see handle-snapshot.ts encodeHandles) so Promise/ReactNode handle values
482
481
  * round-trip through JSON-serializing stores instead of being flattened. */
483
482
  handles: string;
483
+ /**
484
+ * Owning loader ids index-aligned with the decoded `handles` values
485
+ * (HandleOwners). Absent: every value restores as a plain replay.
486
+ */
487
+ handleOwners?: HandleOwners;
484
488
  /** Expiration timestamp (ms since epoch) */
485
489
  expiresAt: number;
486
490
  /** Cache tags for invalidation */
@@ -520,3 +524,11 @@ export interface CacheDefaults {
520
524
  * Structure: { handleName: [values...] }
521
525
  */
522
526
  export type SegmentHandleData = Record<string, unknown[]>;
527
+ /**
528
+ * segmentId -> handleName -> the owning loader id of each recorded value, by
529
+ * index (null: not owned). Only a PPR shell capture writes owners: the
530
+ * settled pushes of an `ssr: false` loader's own body, which the record keeps
531
+ * because the prelude rendered them. restoreHandles replays an owned value
532
+ * through HandleStore.pushReplayed, so that loader's live re-run replaces it.
533
+ */
534
+ export type HandleOwners = Record<string, Record<string, (string | null)[]>>;
@@ -1,4 +1,5 @@
1
1
  import { Component, type ReactNode } from "react";
2
+ import * as Html from "./html.js";
2
3
  import { type ClientErrorBoundaryFallbackProps } from "./types";
3
4
  /**
4
5
  * Outlet component - renders child content in layouts
@@ -125,7 +126,7 @@ interface ErrorBoundaryState {
125
126
  * @example
126
127
  * ```tsx
127
128
  * "use client";
128
- * import { ErrorBoundary } from "rsc-router/client";
129
+ * import { ErrorBoundary } from "@rangojs/router/client";
129
130
  *
130
131
  * function MyComponent() {
131
132
  * return (
@@ -172,14 +173,13 @@ export { useSegments, type SegmentsState, } from "./browser/react/use-segments.j
172
173
  export { NavigationProvider, type NavigationProviderProps, } from "./browser/react/NavigationProvider.js";
173
174
  export { Link, type LinkProps, type PrefetchStrategy, type StateOrGetter, type LinkState, } from "./browser/react/Link.js";
174
175
  export { useLinkStatus, type LinkStatus, } from "./browser/react/use-link-status.js";
175
- export { ScrollRestoration, useScrollRestoration, type ScrollRestorationProps, } from "./browser/react/ScrollRestoration.js";
176
+ export { useScrollRestoration, type ScrollRestorationProps, } from "./browser/react/ScrollRestoration.js";
176
177
  export { type Handle } from "./handle.js";
177
178
  export { useHandle } from "./browser/react/use-handle.js";
178
179
  export { Meta } from "./handles/meta.js";
179
- export { MetaTags } from "./handles/MetaTags.js";
180
180
  export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
181
181
  export { Script, type ScriptConfig, type ScriptAttributes, } from "./handles/script.js";
182
- export { Scripts } from "./handles/Scripts.js";
182
+ export { Html };
183
183
  export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
184
184
  export { createLocationState, useLocationState, type LocationStateDefinition, type LocationStateEntry, type LocationStateOptions, } from "./browser/react/location-state.js";
185
185
  export { href, type PatternToPath } from "./href-client.js";
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * RSC-environment version of client exports
3
3
  *
4
- * This file is used when importing "rsc-router/client" from RSC (server components).
4
+ * This file is used when importing "@rangojs/router/client" from RSC (server components).
5
5
  * It re-exports the server's createLoader so that loader definitions work in both
6
6
  * environments with the same import.
7
7
  *
8
8
  * The bundler uses the "react-server" export condition to select this file
9
9
  * in RSC context, while the regular client.tsx is used in client components.
10
10
  */
11
+ import * as Html from "./html.js";
11
12
  export { Outlet, ParallelOutlet, useOutlet, type OutletState, useLoader, ErrorBoundary, type ErrorBoundaryProps, } from "./client.js";
12
13
  export { useFetchLoader, useRefreshLoaders, type LoadFunction, type UseLoaderResult, type UseFetchLoaderResult, type UseLoaderOptions, } from "./use-loader.js";
13
14
  export { createLoader } from "./route-definition.js";
@@ -22,18 +23,16 @@ export { useNonce } from "./browser/react/nonce-context.js";
22
23
  export { useMount } from "./browser/react/use-mount.js";
23
24
  export { useSegments, type SegmentsState, } from "./browser/react/use-segments.js";
24
25
  export { useLinkStatus, type LinkStatus, } from "./browser/react/use-link-status.js";
25
- export { useScrollRestoration } from "./browser/react/ScrollRestoration.js";
26
+ export { useScrollRestoration, type ScrollRestorationProps, } from "./browser/react/ScrollRestoration.js";
26
27
  export { Link, type LinkProps, type PrefetchStrategy, } from "./browser/react/Link.js";
27
- export { ScrollRestoration, type ScrollRestorationProps, } from "./browser/react/ScrollRestoration.js";
28
28
  export { NavigationProvider, type NavigationProviderProps, } from "./browser/react/NavigationProvider.js";
29
29
  export { href } from "./href-client.js";
30
30
  export { MountContext } from "./browser/react/mount-context.js";
31
31
  export { createHandle, isHandle, type Handle } from "./handle.js";
32
32
  export { Meta } from "./handles/meta.js";
33
- export { MetaTags } from "./handles/MetaTags.js";
34
33
  export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
35
34
  export { Script, type ScriptConfig, type ScriptAttributes, } from "./handles/script.js";
36
- export { Scripts } from "./handles/Scripts.js";
35
+ export { Html };
37
36
  export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
38
37
  export { createLocationState, type LocationStateDefinition, type LocationStateEntry, type LocationStateOptions, } from "./browser/react/location-state-shared.js";
39
38
  export { useHref } from "./browser/react/use-href.js";
@@ -2,8 +2,11 @@ import type { ReactNode, ReactElement } from "react";
2
2
  /**
3
3
  * Default document component that provides a basic HTML structure.
4
4
  * Used when no custom document is provided to createRouter.
5
- * Includes MetaTags for automatic charset, viewport, and route meta support,
6
- * and Scripts (head + body sites) so the Script handle works out of the box.
5
+ * Renders every Html member: Html.Meta (charset, viewport, route meta), head +
6
+ * body Html.Scripts sites for the Script handle, and Html.ScrollRestoration.
7
+ * An app that wants a custom getKey or no scroll restoration passes its own
8
+ * document; rendering a second Html.ScrollRestoration under this one only
9
+ * warns ("[Scroll] Already initialized").
7
10
  *
8
11
  * Uses suppressHydrationWarning on <html> because the theme script
9
12
  * may modify class/style attributes before React hydrates.
@@ -12,7 +12,7 @@
12
12
  * interface PaginationData { current: number; total: number }
13
13
  * export const Pagination = createVar<PaginationData>();
14
14
  *
15
- * // Non-cacheable var — ctx.get(User) throws inside a cache() boundary
15
+ * // Non-cacheable var — ctx.get(User) throws inside cache() or "use cache"
16
16
  * export const User = createVar<UserData>({ cache: false });
17
17
  *
18
18
  * // handler
@@ -25,7 +25,7 @@
25
25
  export interface ContextVar<T> {
26
26
  readonly __brand: "context-var";
27
27
  readonly key: symbol;
28
- /** When false, ctx.get(var) throws inside a cache() boundary. */
28
+ /** When false, ctx.get(var) throws inside cache() or "use cache". */
29
29
  readonly cache: boolean;
30
30
  /** Phantom field to carry the type parameter. Never set at runtime. */
31
31
  readonly __type?: T;
@@ -33,9 +33,10 @@ export interface ContextVar<T> {
33
33
  export interface ContextVarOptions {
34
34
  /**
35
35
  * When false, marks this variable as non-cacheable.
36
- * Reading this var with ctx.get() inside a cache() boundary throws. Use for
37
- * inherently request-specific data (user sessions, auth tokens, etc.) that
38
- * must never be baked into cached segments.
36
+ * Reading this var with ctx.get() inside a cache() boundary or a "use cache"
37
+ * function throws. Use for inherently request-specific data (user sessions,
38
+ * auth tokens, etc.) that must never be baked into cached segments or
39
+ * entries; pass the value into a "use cache" function as an argument.
39
40
  *
40
41
  * @default true
41
42
  */
@@ -39,6 +39,6 @@ export declare function escapeJsonForScript(json: string): string;
39
39
  * source; for untrusted dynamic data, JSON-encode it and read it back, rather than
40
40
  * inlining it as code.
41
41
  *
42
- * Used by the Script handle's <Scripts> renderer for inline `children`.
42
+ * Used by the Script handle's <Html.Scripts> renderer for inline `children`.
43
43
  */
44
44
  export declare function escapeScriptBody(js: string): string;
@@ -1,17 +1,18 @@
1
1
  import type { MetaDescriptorBase } from "../router/types.js";
2
2
  export declare function renderMetaDescriptor(descriptor: MetaDescriptorBase, index: number): React.ReactNode;
3
3
  /**
4
- * Renders all collected meta descriptors from route handlers.
4
+ * Renders all collected meta descriptors from route handlers. Public as
5
+ * `Html.Meta` (`@rangojs/router/client`).
5
6
  *
6
- * Place this component inside the `<head>` element of your document.
7
+ * Place `<Html.Meta />` inside the `<head>` element of your document.
7
8
  * It will automatically update when meta descriptors change during navigation.
8
9
  *
9
10
  * When theme is enabled in router config, also renders the theme initialization
10
11
  * script to prevent FOUC (flash of unstyled content).
11
12
  *
12
- * Deferred (Promise) meta descriptors are resolved BEFORE MetaTags renders —
13
+ * Deferred (Promise) meta descriptors are resolved BEFORE this renders —
13
14
  * server-side on the full/SSR render, client-side before apply on navigation
14
- * (resolve-by-default) — so MetaTags only ever receives resolved descriptors and
15
+ * (resolve-by-default) — so it only ever receives resolved descriptors and
15
16
  * never suspends.
16
17
  */
17
18
  export declare function MetaTags(): React.ReactNode;
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Renders the scripts collected by the Script handle into the document.
2
+ * Renders the scripts collected by the Script handle into the document. Public
3
+ * as `Html.Scripts` (`@rangojs/router/client`).
3
4
  *
4
- * Place `<Scripts />` inside `<head>` (default) and, if you push body scripts,
5
- * `<Scripts position="body" />` at the top of `<body>`. Each site renders the
6
- * configs whose `position` matches; the request CSP nonce is applied
5
+ * Place `<Html.Scripts />` inside `<head>` (default) and, if you push body
6
+ * scripts, `<Html.Scripts position="body" />` at the top of `<body>`. Each site
7
+ * renders the configs whose `position` matches; the request CSP nonce is applied
7
8
  * automatically to every DOCUMENT-RENDERED <script> (consumers never pass it). An
8
9
  * async script first encountered on a soft navigation is injected client-side
9
10
  * where the nonce is unavailable, so it carries no nonce and relies on
@@ -22,11 +23,11 @@
22
23
  * ```tsx
23
24
  * <html>
24
25
  * <head>
25
- * <MetaTags />
26
- * <Scripts />
26
+ * <Html.Meta />
27
+ * <Html.Scripts />
27
28
  * </head>
28
29
  * <body>
29
- * <Scripts position="body" />
30
+ * <Html.Scripts position="body" />
30
31
  * {children}
31
32
  * </body>
32
33
  * </html>
@@ -19,7 +19,7 @@
19
19
  * return (
20
20
  * <html>
21
21
  * <head>
22
- * <MetaTags />
22
+ * <Html.Meta />
23
23
  * </head>
24
24
  * ...
25
25
  * </html>
@@ -33,7 +33,7 @@ import type { MetaDescriptor } from "../router/types.js";
33
33
  * Built-in handle for managing document metadata.
34
34
  *
35
35
  * Use `ctx.use(Meta)` in route handlers to push meta descriptors.
36
- * Use `<MetaTags />` component to render them in the document head.
36
+ * Use the `<Html.Meta />` component to render them in the document head.
37
37
  *
38
38
  * Deferred (Promise) descriptors are resolved before collectMeta runs
39
39
  * (resolve-by-default), so they participate in deduplication and `%s`
@@ -3,22 +3,23 @@
3
3
  * route/layout handlers.
4
4
  *
5
5
  * Push from a SERVER handler with `ctx.use(Script)(config)`; render with the
6
- * `<Scripts />` component (from `@rangojs/router/client`) placed in the Document
7
- * `<head>` (and optionally a second `<Scripts position="body" />` at the top of
8
- * `<body>`). This mirrors the Meta / <MetaTags> pair.
6
+ * `<Html.Scripts />` component (from `@rangojs/router/client`) placed in the
7
+ * Document `<head>` (and optionally a second `<Html.Scripts position="body" />`
8
+ * at the top of `<body>`). This mirrors the Meta / <Html.Meta> pair.
9
9
  *
10
- * The request CSP nonce is applied AUTOMATICALLY by <Scripts> to document-rendered
11
- * scripts; consumers never pass a nonce. (An async script first loaded on a soft
12
- * navigation is injected client-side without a nonce — it relies on
13
- * 'strict-dynamic' or a host allowance; see the EXECUTION CONTRACT below and the
14
- * /scripts skill.) A ScriptConfig is fully serializable (it crosses the
15
- * server -> client handle-collection boundary), so callbacks like onLoad are NOT
16
- * supported — a consumer needing them renders their own "use client" script.
10
+ * The request CSP nonce is applied AUTOMATICALLY by <Html.Scripts> to
11
+ * document-rendered scripts; consumers never pass a nonce. (An async script
12
+ * first loaded on a soft navigation is injected client-side without a nonce —
13
+ * it relies on 'strict-dynamic' or a host allowance; see the EXECUTION CONTRACT
14
+ * below and the /scripts skill.) A ScriptConfig is fully serializable (it
15
+ * crosses the server -> client handle-collection boundary), so callbacks like
16
+ * onLoad are NOT supported — a consumer needing them renders their own
17
+ * "use client" script.
17
18
  *
18
19
  * EXECUTION CONTRACT (see the /scripts skill for the full story):
19
20
  * - Inline (`children`) and ordered external (`src`, optional `defer`) scripts
20
21
  * are DOCUMENT-LOAD scripts: they execute only when present in the initial HTML
21
- * response. <Scripts> freezes them after hydration, so a later client (soft)
22
+ * response. <Html.Scripts> freezes them after hydration, so a later client (soft)
22
23
  * navigation never inserts an inert copy — React creates client-mounted
23
24
  * <script> elements via innerHTML, which the HTML spec makes non-executing.
24
25
  * - Async external scripts (`src` + `async: true`) are React RESOURCES: they load
@@ -64,9 +65,9 @@ export type ScriptAttributes = Omit<ScriptHTMLAttributes<HTMLScriptElement>, "id
64
65
  /** Fields shared by every script shape. */
65
66
  interface ScriptConfigBase {
66
67
  /**
67
- * Where <Scripts> renders this script.
68
- * - "head" (default): the `<head>` <Scripts> site.
69
- * - "body": the `<Scripts position="body" />` site at the top of <body>.
68
+ * Where <Html.Scripts> renders this script.
69
+ * - "head" (default): the `<head>` <Html.Scripts> site.
70
+ * - "body": the `<Html.Scripts position="body" />` site at the top of <body>.
70
71
  * Note: an external `async` script is hoisted into <head> by React regardless.
71
72
  */
72
73
  position?: "head" | "body";
@@ -81,7 +82,7 @@ interface ScriptConfigBase {
81
82
  /**
82
83
  * Inline script: a raw JS body rendered in place, escaped against `</script>`
83
84
  * breakout. DOCUMENT-LOAD only (executes when present in the initial HTML;
84
- * <Scripts> freezes it after hydration so navigation never inserts an inert
85
+ * <Html.Scripts> freezes it after hydration so navigation never inserts an inert
85
86
  * copy). `id` is REQUIRED — inline scripts are never deduped by React, so a
86
87
  * layout and a child pushing the same bootstrap would inject it twice. It is also
87
88
  * rendered as the script's DOM `id`. Forbids `src`/`async`/`defer`. For analytics
@@ -128,7 +129,7 @@ export interface OrderedScriptConfig extends ScriptConfigBase {
128
129
  * inline (`id` + `children`), external async (`src` + `async: true`), or external
129
130
  * ordered (`src`, optional `defer`). Invalid combinations (both `src`+`children`,
130
131
  * `async`+`defer`, inline without `id`) are compile errors. The CSP nonce is
131
- * applied by <Scripts>, never here.
132
+ * applied by <Html.Scripts>, never here.
132
133
  */
133
134
  export type ScriptConfig = InlineScriptConfig | AsyncScriptConfig | OrderedScriptConfig;
134
135
  /**
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @example
8
8
  * ```typescript
9
- * import { href } from "rsc-router/client";
9
+ * import { href } from "@rangojs/router/client";
10
10
  *
11
11
  * href("/blog/my-post"); // ✓ matches /blog/:slug
12
12
  * href("/shop/product/widget"); // ✓ matches /shop/product/:slug
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Members of the `Html` namespace; client.tsx and client.rsc.tsx expose this
3
+ * module as `import * as Html`. A module namespace, not an object literal, so
4
+ * bundlers drop members an app never renders (a literal kept opt-in
5
+ * ScrollRestoration in every app: +313 B gzip, over the router-chunk ratchet).
6
+ * No "use client": each member stays its own module's client reference, so a
7
+ * server component can dot into `Html`. Pinned by __tests__/html.test.ts and
8
+ * testing/__tests__/html-namespace.rsc-test.tsx.
9
+ */
10
+ export { MetaTags as Meta } from "./handles/MetaTags.js";
11
+ export { Scripts } from "./handles/Scripts.js";
12
+ export { ScrollRestoration } from "./browser/react/ScrollRestoration.js";
@@ -103,7 +103,7 @@ export { Script, type ScriptConfig, type ScriptAttributes, } from "./handles/scr
103
103
  export { Breadcrumbs } from "./handles/breadcrumbs.js";
104
104
  export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
105
105
  export type { BreadcrumbItem } from "./handles/breadcrumbs.js";
106
- export type { ScopedReverseFunction, ReverseFunction, ExtractLocalRoutes, ParamsFor, } from "./reverse.js";
106
+ export type { ScopedReverseFunction, ReverseFunction, GlobalReverseFunction, ExtractLocalRoutes, ParamsFor, } from "./reverse.js";
107
107
  export { scopedReverse } from "./reverse.js";
108
108
  export { createLocationState, type LocationStateDefinition, type LocationStateEntry, type LocationStateOptions, } from "./browser/react/location-state-shared.js";
109
109
  export type { OTelTracer, OTelActiveSpanTracer, OTelSpan, OTelTracingOptions, } from "./router/telemetry-otel.js";
@@ -9,7 +9,7 @@
9
9
  * in RSC context, while the regular index.ts is used in client components.
10
10
  */
11
11
  export { RouteNotFoundError, DataNotFoundError, notFound, MiddlewareError, HandlerError, BuildError, DslContextError, InvalidHandlerError, RouterError, Skip, isSkip, } from "./index.js";
12
- export type { DocumentProps, DefaultEnv, RouteDefinition, RouteConfig, RouteDefinitionOptions, TrailingSlashMode, Handler, HandlerContext, ExtractParams, GenericParams, Middleware, RevalidateParams, Revalidate, ActionRef, IsActionFn, RouteKeys, LoaderDefinition, LoaderFn, LoaderContext, FetchableLoaderOptions, LoadOptions, ErrorInfo, ErrorBoundaryFallbackProps, ErrorBoundaryHandler, ClientErrorBoundaryFallbackProps, NotFoundInfo, NotFoundBoundaryFallbackProps, NotFoundBoundaryHandler, ErrorPhase, OnErrorContext, OnErrorCallback, TransitionConfig, TransitionWhenFn, TransitionWhenContext, ViewTransitionClass, } from "./types.js";
12
+ export type { DocumentProps, DefaultEnv, RouteDefinition, RouteConfig, RouteDefinitionOptions, TrailingSlashMode, Handler, HandlerContext, ExtractParams, GenericParams, Middleware, RevalidateParams, Revalidate, ActionRef, IsActionFn, RouteKeys, LoaderDefinition, LoaderFn, LoaderContext, LoaderOptions, FetchableLoaderOptions, LoadOptions, ErrorInfo, ErrorBoundaryFallbackProps, ErrorBoundaryHandler, ClientErrorBoundaryFallbackProps, NotFoundInfo, NotFoundBoundaryFallbackProps, NotFoundBoundaryHandler, ErrorPhase, OnErrorContext, OnErrorCallback, TransitionConfig, TransitionWhenFn, TransitionWhenContext, ViewTransitionClass, } from "./types.js";
13
13
  export type { RangoOptions, SSRStreamMode, SSROptions, ResolveStreamingContext, } from "./router.js";
14
14
  export type { OriginCheckConfig, OriginCheckContext, OriginCheckPhase, } from "./rsc/origin-guard.js";
15
15
  export type { ShellCaptureDebug, ShellCaptureDebugEvent, } from "./rsc/shell-capture.js";
@@ -23,6 +23,7 @@ export { Prerender, Passthrough, type PrerenderHandlerDefinition, type Passthrou
23
23
  export { Static, type StaticHandlerDefinition, type StaticHandlerOptions, } from "./static-handler.js";
24
24
  export { urls, type PathHelpers, type PathOptions, type PartialPrerenderProps, type UrlPatterns, type IncludeOptions, type IncludeItem, type RouteResponse, type ProblemDetails, type ResponseHandler, type ResponseHandlerContext, type JsonResponseHandler, type TextResponseHandler, type JsonValue, type ResponsePathFn, type JsonResponsePathFn, type TextResponsePathFn, } from "./urls.js";
25
25
  export { createRouter, type Rango, type RootLayoutProps, type RouterRequestInput, } from "./router.js";
26
+ export type { SerializedManifest } from "./debug.js";
26
27
  export type { HandlerCacheConfig } from "./rsc/types.js";
27
28
  export { TRACKING_SEARCH_PARAMS, type CacheSearchParams, } from "./cache/search-params-filter.js";
28
29
  export { Meta } from "./handles/meta.js";
@@ -38,7 +39,7 @@ export { cacheTag } from "./cache/cache-tag.js";
38
39
  export { updateTag, revalidateTag } from "./cache/tag-invalidation.js";
39
40
  export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
40
41
  export type { MiddlewareContext, CookieOptions, MiddlewareFn, } from "./router/middleware.js";
41
- export type { ScopedReverseFunction, ReverseFunction, ExtractLocalRoutes, ParamsFor, } from "./reverse.js";
42
+ export type { ScopedReverseFunction, ReverseFunction, GlobalReverseFunction, ExtractLocalRoutes, ParamsFor, } from "./reverse.js";
42
43
  export { scopedReverse, createReverse } from "./reverse.js";
43
44
  export type { SearchSchema, SearchSchemaValue, ResolveSearchSchema, RouteSearchParams, RouteParams, } from "./search-params.js";
44
45
  export { createLocationState, type LocationStateDefinition, type LocationStateEntry, type LocationStateOptions, } from "./browser/react/location-state-shared.js";
@@ -33,6 +33,12 @@
33
33
  * realm, so there is no cross-request pollution. Server renders never mutate
34
34
  * the store — the hook falls back to `OutletContext.loaderData`.
35
35
  */
36
+ /** The loader-segment shape announcePendingStreams reads (ResolvedSegment). */
37
+ export interface PendingStreamSource {
38
+ type: string;
39
+ loaderId?: string;
40
+ loaderData?: unknown;
41
+ }
36
42
  export interface LoaderEntry<T = unknown> {
37
43
  readonly value: T | undefined;
38
44
  /**
@@ -77,6 +83,14 @@ export interface SubscribeOptions {
77
83
  * Refreshes this bucket in place (no params/body) and rejects on failure.
78
84
  */
79
85
  refetch?: () => Promise<void>;
86
+ /**
87
+ * Called by `announcePendingStreams` (inside a transition commit) when a
88
+ * navigation stream for this bucket's loader is still pending. The hook pins
89
+ * `isLoading: true` with a useOptimistic update; React reverts it when that
90
+ * transition commits. Route-context readers only — an ephemeral reader owns
91
+ * its own lifecycle.
92
+ */
93
+ onStreamPending?: () => void;
80
94
  }
81
95
  export declare class LoaderStore {
82
96
  private readonly entries;
@@ -84,6 +98,21 @@ export declare class LoaderStore {
84
98
  private readonly families;
85
99
  /** refresh group name -> set of bucket keys, for refreshGroups(). */
86
100
  private readonly groups;
101
+ /**
102
+ * loader.$$id -> per-loader streams a committed navigation is still
103
+ * receiving. Registered and announced by announcePendingStreams(), which
104
+ * browser/partial-update.ts calls INSIDE every transition commit, so a
105
+ * reader whose content is held on screen by that transition pins
106
+ * `isLoading: true` for the data it is still showing until the transition
107
+ * lands (use-loader.tsx). Family-keyed on purpose: a persisting layout
108
+ * reader of the same createLoader the child is re-running is pinned too
109
+ * (the loader is in flight; not "this segment's copy is being replaced" —
110
+ * issue #862, working as designed). The new tree's own read of the loader
111
+ * suspends at the read site and never observes the flag. A Set, not a
112
+ * flag: overlapping navigations (second click before the first stream
113
+ * lands) keep the family pending until the LAST stream settles.
114
+ */
115
+ private readonly pendingStreams;
87
116
  private getOrCreate;
88
117
  private registerFamily;
89
118
  /**
@@ -178,6 +207,29 @@ export declare class LoaderStore {
178
207
  */
179
208
  clearFamily(loaderId: string): void;
180
209
  private notify;
210
+ /**
211
+ * Register a still-streaming per-loader result for `loaderId`. No-op for a
212
+ * settled Flight chunk (unwrapsSynchronously / "rejected"): the forceAwait
213
+ * and action lanes commit settled chunks, and a { ssr: false } loader is
214
+ * awaited before flush. Released as the stream settles, either way.
215
+ */
216
+ trackPendingStream(loaderId: string, stream: Promise<unknown>): void;
217
+ /** True while any navigation stream for `loaderId` is still pending. */
218
+ isStreamPending(loaderId: string): boolean;
219
+ /**
220
+ * Register the loader segments of a tree being committed whose data is
221
+ * still a pending promise, then fire `onStreamPending` on every subscriber
222
+ * of every family with a pending stream. MUST run inside the startTransition
223
+ * that commits the tree: the hook answers with a useOptimistic update, which
224
+ * React reverts exactly when that transition commits — so the held reader
225
+ * reports isLoading:true for as long as its data stays on screen and not a
226
+ * frame longer. Outside a transition React reverts an optimistic update on
227
+ * the next render, pinning nothing useful. Registering here rather than in
228
+ * the tree build keeps register + announce in one call; settled chunks
229
+ * (cached/reused segments, forceAwait lanes) are skipped by
230
+ * trackPendingStream.
231
+ */
232
+ announcePendingStreams(segments: readonly PendingStreamSource[]): void;
181
233
  /**
182
234
  * Test-only escape hatch. Drops every entry. Production code should never
183
235
  * call this; the store is process-scoped and lives for the tab's lifetime.
@@ -119,6 +119,35 @@ export type ScopedReverseFunction<TLocalRoutes, TGlobalRoutes = TLocalRoutes> =
119
119
  */
120
120
  <TName extends keyof TLocalRoutes & string>(name: `.${TName}`, params: ExtractParams<RoutePatternFor<TLocalRoutes, TName>>, search: ResolveSearchSchema<ExtractSearchSchema<TLocalRoutes, TName>>): string;
121
121
  };
122
+ /**
123
+ * Reverse function that resolves global route names only: no include() scope,
124
+ * no param auto-fill.
125
+ *
126
+ * This is the `ctx.reverse` of middleware (`MiddlewareContext`) and
127
+ * response-route handlers (`ResponseHandlerContext`). On a live request both
128
+ * get `createReverseFunction(routeMap)` with no route name or params (the
129
+ * middleware callers in rsc/handler.ts and rsc/loader-fetch.ts,
130
+ * handleResponseRoute, router/intercept-resolution.ts; mirrored by
131
+ * testing/run-middleware.ts and testing/dispatch.ts), so a dot-local `.name`
132
+ * has no scope to resolve against and throws `Unknown route`. Build-time PPR
133
+ * shell capture (prerender/build-shell-capture.ts) gives global and route
134
+ * middleware the same global-only reverse.
135
+ *
136
+ * - Route map with a string index signature (no generated map, the permissive
137
+ * `Record<string, string>` fallback): any name except a dot-prefixed literal.
138
+ * `Exclude` is required because `keyof` collapses to `string` there, so the
139
+ * global overloads of `ScopedReverseFunction` would accept `.name` too.
140
+ * - Concrete route map: the global overloads of `ScopedReverseFunction`, with
141
+ * name and param validation. The empty local map (`{}`) leaves no dot-prefixed
142
+ * overload that can match.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * reverse("blog.post", { slug: "hello" }) // ok: global route + params
147
+ * reverse(".post", { slug: "hello" }) // compile error: no include() scope
148
+ * ```
149
+ */
150
+ export type GlobalReverseFunction<TGlobalRoutes> = string extends keyof TGlobalRoutes ? <TName extends string>(name: Exclude<TName, `.${string}`>, params?: Record<string, string>, search?: Record<string, unknown>) => string : ScopedReverseFunction<{}, TGlobalRoutes>;
122
151
  /**
123
152
  * Extract local routes type from UrlPatterns
124
153
  * Used with scopedReverse() to get the routes type from patterns
@@ -178,11 +207,14 @@ export type { RouteResponse } from "./urls.js";
178
207
  * Get a locally-typed reverse function from ctx.reverse for composable modules.
179
208
  *
180
209
  * This is a type-only cast - ctx.reverse already resolves names at runtime.
181
- * Provides type safety: `.name` validates against local routes,
182
- * `name` validates against global named-routes.
210
+ * Only the module's LOCAL routes are typed: `.name` and bare `name` both
211
+ * validate against the local map (the global map parameter defaults to it).
212
+ * Always dot-prefix local names — a bare name type-checks against the local
213
+ * map but resolves as a global name at runtime. For global names, call
214
+ * ctx.reverse directly.
183
215
  *
184
216
  * @param reverse - The ctx.reverse function from HandlerContext
185
- * @returns The same reverse function, typed with local + global routes
217
+ * @returns The same reverse function, typed with the module's local routes
186
218
  *
187
219
  * @example
188
220
  * ```typescript
@@ -193,7 +225,7 @@ export type { RouteResponse } from "./urls.js";
193
225
  *
194
226
  * reverse(".index"); // ✓ Local route
195
227
  * reverse(".post", { slug: "x" }); // ✓ Local with params
196
- * reverse("shop.cart"); // ✓ Global route
228
+ * ctx.reverse("shop.cart"); // Global route: use ctx.reverse
197
229
  *
198
230
  * return <BlogIndex />;
199
231
  * }, { name: "index" }),
@@ -26,7 +26,7 @@ declare const revalidate: RouteHelpers<any, any>["revalidate"];
26
26
  * When an error occurs during rendering of this segment or its children,
27
27
  * the fallback will be rendered instead. The fallback can be:
28
28
  * - A static ReactNode (e.g., <ErrorPage />)
29
- * - A handler function that receives error info and reset function
29
+ * - A handler function that receives `{ error }` (server fallbacks get no reset)
30
30
  *
31
31
  * Error boundaries catch errors from:
32
32
  * - Middleware execution
@@ -42,11 +42,11 @@ declare const revalidate: RouteHelpers<any, any>["revalidate"];
42
42
  *
43
43
  * // Or with handler for dynamic error UI:
44
44
  * route("products.detail", ProductDetail, () => [
45
- * errorBoundary(({ error, reset }) => (
45
+ * errorBoundary(({ error }) => (
46
46
  * <div>
47
47
  * <h2>Product failed to load</h2>
48
48
  * <p>{error.message}</p>
49
- * <button onClick={reset}>Retry</button>
49
+ * <a href="/products">Back to products</a>
50
50
  * </div>
51
51
  * )),
52
52
  * ])