@rangojs/router 0.0.0-experimental.3 → 0.0.0-experimental.31

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 (300) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +883 -4
  3. package/dist/bin/rango.js +1601 -0
  4. package/dist/vite/index.js +4655 -747
  5. package/package.json +78 -50
  6. package/skills/breadcrumbs/SKILL.md +206 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +54 -25
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +23 -21
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +389 -64
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +133 -10
  16. package/skills/layout/SKILL.md +102 -5
  17. package/skills/links/SKILL.md +239 -0
  18. package/skills/loader/SKILL.md +366 -29
  19. package/skills/middleware/SKILL.md +173 -36
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +80 -3
  22. package/skills/prerender/SKILL.md +643 -0
  23. package/skills/rango/SKILL.md +86 -16
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +227 -15
  26. package/skills/router-setup/SKILL.md +225 -32
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +12 -11
  29. package/skills/typesafety/SKILL.md +415 -87
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +10 -4
  32. package/src/bin/rango.ts +321 -0
  33. package/src/browser/action-coordinator.ts +97 -0
  34. package/src/browser/action-response-classifier.ts +99 -0
  35. package/src/browser/event-controller.ts +87 -64
  36. package/src/browser/history-state.ts +80 -0
  37. package/src/browser/intercept-utils.ts +52 -0
  38. package/src/browser/link-interceptor.ts +20 -4
  39. package/src/browser/logging.ts +55 -0
  40. package/src/browser/merge-segment-loaders.ts +20 -12
  41. package/src/browser/navigation-bridge.ts +201 -553
  42. package/src/browser/navigation-client.ts +124 -71
  43. package/src/browser/navigation-store.ts +33 -50
  44. package/src/browser/navigation-transaction.ts +295 -0
  45. package/src/browser/network-error-handler.ts +61 -0
  46. package/src/browser/partial-update.ts +267 -317
  47. package/src/browser/prefetch/cache.ts +146 -0
  48. package/src/browser/prefetch/fetch.ts +135 -0
  49. package/src/browser/prefetch/observer.ts +65 -0
  50. package/src/browser/prefetch/policy.ts +42 -0
  51. package/src/browser/prefetch/queue.ts +88 -0
  52. package/src/browser/rango-state.ts +112 -0
  53. package/src/browser/react/Link.tsx +173 -73
  54. package/src/browser/react/NavigationProvider.tsx +138 -27
  55. package/src/browser/react/context.ts +6 -0
  56. package/src/browser/react/filter-segment-order.ts +11 -0
  57. package/src/browser/react/index.ts +12 -12
  58. package/src/browser/react/location-state-shared.ts +95 -53
  59. package/src/browser/react/location-state.ts +60 -15
  60. package/src/browser/react/mount-context.ts +37 -0
  61. package/src/browser/react/nonce-context.ts +23 -0
  62. package/src/browser/react/shallow-equal.ts +27 -0
  63. package/src/browser/react/use-action.ts +29 -51
  64. package/src/browser/react/use-client-cache.ts +5 -3
  65. package/src/browser/react/use-handle.ts +49 -65
  66. package/src/browser/react/use-href.tsx +20 -188
  67. package/src/browser/react/use-link-status.ts +6 -5
  68. package/src/browser/react/use-mount.ts +31 -0
  69. package/src/browser/react/use-navigation.ts +27 -78
  70. package/src/browser/react/use-params.ts +65 -0
  71. package/src/browser/react/use-pathname.ts +47 -0
  72. package/src/browser/react/use-router.ts +63 -0
  73. package/src/browser/react/use-search-params.ts +56 -0
  74. package/src/browser/react/use-segments.ts +80 -97
  75. package/src/browser/response-adapter.ts +73 -0
  76. package/src/browser/rsc-router.tsx +111 -26
  77. package/src/browser/scroll-restoration.ts +92 -16
  78. package/src/browser/segment-reconciler.ts +216 -0
  79. package/src/browser/segment-structure-assert.ts +83 -0
  80. package/src/browser/server-action-bridge.ts +504 -584
  81. package/src/browser/shallow.ts +6 -1
  82. package/src/browser/types.ts +92 -57
  83. package/src/browser/validate-redirect-origin.ts +29 -0
  84. package/src/build/generate-manifest.ts +438 -0
  85. package/src/build/generate-route-types.ts +36 -0
  86. package/src/build/index.ts +35 -0
  87. package/src/build/route-trie.ts +265 -0
  88. package/src/build/route-types/ast-helpers.ts +25 -0
  89. package/src/build/route-types/ast-route-extraction.ts +98 -0
  90. package/src/build/route-types/codegen.ts +102 -0
  91. package/src/build/route-types/include-resolution.ts +411 -0
  92. package/src/build/route-types/param-extraction.ts +48 -0
  93. package/src/build/route-types/per-module-writer.ts +128 -0
  94. package/src/build/route-types/router-processing.ts +469 -0
  95. package/src/build/route-types/scan-filter.ts +78 -0
  96. package/src/build/runtime-discovery.ts +231 -0
  97. package/src/cache/background-task.ts +34 -0
  98. package/src/cache/cache-key-utils.ts +44 -0
  99. package/src/cache/cache-policy.ts +125 -0
  100. package/src/cache/cache-runtime.ts +338 -0
  101. package/src/cache/cache-scope.ts +120 -303
  102. package/src/cache/cf/cf-cache-store.ts +119 -7
  103. package/src/cache/cf/index.ts +8 -2
  104. package/src/cache/document-cache.ts +101 -72
  105. package/src/cache/handle-capture.ts +81 -0
  106. package/src/cache/handle-snapshot.ts +41 -0
  107. package/src/cache/index.ts +0 -15
  108. package/src/cache/memory-segment-store.ts +191 -13
  109. package/src/cache/profile-registry.ts +73 -0
  110. package/src/cache/read-through-swr.ts +134 -0
  111. package/src/cache/segment-codec.ts +256 -0
  112. package/src/cache/taint.ts +98 -0
  113. package/src/cache/types.ts +72 -122
  114. package/src/client.rsc.tsx +12 -15
  115. package/src/client.tsx +115 -135
  116. package/src/component-utils.ts +4 -4
  117. package/src/components/DefaultDocument.tsx +5 -1
  118. package/src/context-var.ts +86 -0
  119. package/src/debug.ts +17 -7
  120. package/src/errors.ts +108 -2
  121. package/src/handle.ts +34 -19
  122. package/src/handles/MetaTags.tsx +73 -20
  123. package/src/handles/breadcrumbs.ts +66 -0
  124. package/src/handles/index.ts +1 -0
  125. package/src/handles/meta.ts +30 -13
  126. package/src/host/cookie-handler.ts +165 -0
  127. package/src/host/errors.ts +97 -0
  128. package/src/host/index.ts +53 -0
  129. package/src/host/pattern-matcher.ts +214 -0
  130. package/src/host/router.ts +352 -0
  131. package/src/host/testing.ts +79 -0
  132. package/src/host/types.ts +146 -0
  133. package/src/host/utils.ts +25 -0
  134. package/src/href-client.ts +135 -49
  135. package/src/index.rsc.ts +183 -17
  136. package/src/index.ts +241 -24
  137. package/src/internal-debug.ts +11 -0
  138. package/src/loader.rsc.ts +27 -142
  139. package/src/loader.ts +27 -10
  140. package/src/network-error-thrower.tsx +3 -1
  141. package/src/outlet-provider.tsx +45 -0
  142. package/src/prerender/param-hash.ts +37 -0
  143. package/src/prerender/store.ts +185 -0
  144. package/src/prerender.ts +463 -0
  145. package/src/reverse.ts +330 -0
  146. package/src/root-error-boundary.tsx +41 -29
  147. package/src/route-content-wrapper.tsx +9 -11
  148. package/src/route-definition/dsl-helpers.ts +934 -0
  149. package/src/route-definition/helper-factories.ts +200 -0
  150. package/src/route-definition/helpers-types.ts +430 -0
  151. package/src/route-definition/index.ts +52 -0
  152. package/src/route-definition/redirect.ts +93 -0
  153. package/src/route-definition.ts +1 -1388
  154. package/src/route-map-builder.ts +241 -112
  155. package/src/route-name.ts +53 -0
  156. package/src/route-types.ts +70 -9
  157. package/src/router/content-negotiation.ts +116 -0
  158. package/src/router/debug-manifest.ts +72 -0
  159. package/src/router/error-handling.ts +9 -9
  160. package/src/router/find-match.ts +158 -0
  161. package/src/router/handler-context.ts +371 -81
  162. package/src/router/intercept-resolution.ts +395 -0
  163. package/src/router/lazy-includes.ts +234 -0
  164. package/src/router/loader-resolution.ts +215 -122
  165. package/src/router/logging.ts +248 -0
  166. package/src/router/manifest.ts +155 -32
  167. package/src/router/match-api.ts +620 -0
  168. package/src/router/match-context.ts +5 -3
  169. package/src/router/match-handlers.ts +440 -0
  170. package/src/router/match-middleware/background-revalidation.ts +80 -93
  171. package/src/router/match-middleware/cache-lookup.ts +382 -9
  172. package/src/router/match-middleware/cache-store.ts +51 -22
  173. package/src/router/match-middleware/intercept-resolution.ts +55 -17
  174. package/src/router/match-middleware/segment-resolution.ts +24 -6
  175. package/src/router/match-pipelines.ts +10 -45
  176. package/src/router/match-result.ts +34 -29
  177. package/src/router/metrics.ts +235 -15
  178. package/src/router/middleware-cookies.ts +55 -0
  179. package/src/router/middleware-types.ts +222 -0
  180. package/src/router/middleware.ts +324 -367
  181. package/src/router/pattern-matching.ts +321 -30
  182. package/src/router/prerender-match.ts +400 -0
  183. package/src/router/preview-match.ts +170 -0
  184. package/src/router/revalidation.ts +137 -38
  185. package/src/router/router-context.ts +36 -21
  186. package/src/router/router-interfaces.ts +452 -0
  187. package/src/router/router-options.ts +592 -0
  188. package/src/router/router-registry.ts +24 -0
  189. package/src/router/segment-resolution/fresh.ts +570 -0
  190. package/src/router/segment-resolution/helpers.ts +263 -0
  191. package/src/router/segment-resolution/loader-cache.ts +198 -0
  192. package/src/router/segment-resolution/revalidation.ts +1241 -0
  193. package/src/router/segment-resolution/static-store.ts +67 -0
  194. package/src/router/segment-resolution.ts +21 -0
  195. package/src/router/segment-wrappers.ts +289 -0
  196. package/src/router/telemetry-otel.ts +299 -0
  197. package/src/router/telemetry.ts +300 -0
  198. package/src/router/timeout.ts +148 -0
  199. package/src/router/trie-matching.ts +239 -0
  200. package/src/router/types.ts +77 -3
  201. package/src/router.ts +688 -3656
  202. package/src/rsc/handler-context.ts +45 -0
  203. package/src/rsc/handler.ts +786 -760
  204. package/src/rsc/helpers.ts +140 -6
  205. package/src/rsc/index.ts +5 -25
  206. package/src/rsc/loader-fetch.ts +209 -0
  207. package/src/rsc/manifest-init.ts +86 -0
  208. package/src/rsc/nonce.ts +14 -0
  209. package/src/rsc/origin-guard.ts +141 -0
  210. package/src/rsc/progressive-enhancement.ts +379 -0
  211. package/src/rsc/response-error.ts +37 -0
  212. package/src/rsc/response-route-handler.ts +347 -0
  213. package/src/rsc/rsc-rendering.ts +235 -0
  214. package/src/rsc/runtime-warnings.ts +42 -0
  215. package/src/rsc/server-action.ts +348 -0
  216. package/src/rsc/ssr-setup.ts +128 -0
  217. package/src/rsc/types.ts +40 -14
  218. package/src/search-params.ts +230 -0
  219. package/src/segment-system.tsx +57 -61
  220. package/src/server/context.ts +202 -51
  221. package/src/server/cookie-store.ts +190 -0
  222. package/src/server/fetchable-loader-store.ts +37 -0
  223. package/src/server/handle-store.ts +94 -15
  224. package/src/server/loader-registry.ts +15 -56
  225. package/src/server/request-context.ts +422 -70
  226. package/src/server.ts +36 -120
  227. package/src/ssr/index.tsx +157 -26
  228. package/src/static-handler.ts +114 -0
  229. package/src/theme/ThemeProvider.tsx +21 -15
  230. package/src/theme/ThemeScript.tsx +5 -5
  231. package/src/theme/constants.ts +5 -2
  232. package/src/theme/index.ts +4 -14
  233. package/src/theme/theme-context.ts +4 -30
  234. package/src/theme/theme-script.ts +21 -18
  235. package/src/types/boundaries.ts +158 -0
  236. package/src/types/cache-types.ts +198 -0
  237. package/src/types/error-types.ts +192 -0
  238. package/src/types/global-namespace.ts +100 -0
  239. package/src/types/handler-context.ts +687 -0
  240. package/src/types/index.ts +88 -0
  241. package/src/types/loader-types.ts +183 -0
  242. package/src/types/route-config.ts +170 -0
  243. package/src/types/route-entry.ts +102 -0
  244. package/src/types/segments.ts +148 -0
  245. package/src/types.ts +1 -1577
  246. package/src/urls/include-helper.ts +197 -0
  247. package/src/urls/index.ts +53 -0
  248. package/src/urls/path-helper-types.ts +339 -0
  249. package/src/urls/path-helper.ts +329 -0
  250. package/src/urls/pattern-types.ts +95 -0
  251. package/src/urls/response-types.ts +106 -0
  252. package/src/urls/type-extraction.ts +372 -0
  253. package/src/urls/urls-function.ts +98 -0
  254. package/src/urls.ts +1 -726
  255. package/src/use-loader.tsx +85 -77
  256. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  257. package/src/vite/discovery/discover-routers.ts +344 -0
  258. package/src/vite/discovery/prerender-collection.ts +385 -0
  259. package/src/vite/discovery/route-types-writer.ts +258 -0
  260. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  261. package/src/vite/discovery/state.ts +110 -0
  262. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  263. package/src/vite/index.ts +11 -782
  264. package/src/vite/plugin-types.ts +131 -0
  265. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  266. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  267. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  268. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
  269. package/src/vite/plugins/expose-id-utils.ts +287 -0
  270. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  271. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  272. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  273. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  274. package/src/vite/plugins/expose-ids/types.ts +45 -0
  275. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  276. package/src/vite/plugins/refresh-cmd.ts +65 -0
  277. package/src/vite/plugins/use-cache-transform.ts +323 -0
  278. package/src/vite/plugins/version-injector.ts +83 -0
  279. package/src/vite/plugins/version-plugin.ts +254 -0
  280. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +29 -15
  281. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  282. package/src/vite/rango.ts +510 -0
  283. package/src/vite/router-discovery.ts +785 -0
  284. package/src/vite/utils/ast-handler-extract.ts +517 -0
  285. package/src/vite/utils/banner.ts +36 -0
  286. package/src/vite/utils/bundle-analysis.ts +137 -0
  287. package/src/vite/utils/manifest-utils.ts +70 -0
  288. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  289. package/src/vite/utils/prerender-utils.ts +189 -0
  290. package/src/vite/utils/shared-utils.ts +169 -0
  291. package/CLAUDE.md +0 -3
  292. package/src/browser/lru-cache.ts +0 -69
  293. package/src/browser/request-controller.ts +0 -164
  294. package/src/cache/memory-store.ts +0 -253
  295. package/src/href-context.ts +0 -33
  296. package/src/href.ts +0 -255
  297. package/src/vite/expose-handle-id.ts +0 -209
  298. package/src/vite/expose-loader-id.ts +0 -357
  299. package/src/vite/expose-location-state-id.ts +0 -177
  300. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -26,7 +26,12 @@ export function shallow<T>(a: T, b: T): boolean {
26
26
 
27
27
  // Check each key's value with Object.is
28
28
  for (const key of keysA) {
29
- if (!Object.is((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {
29
+ if (
30
+ !Object.is(
31
+ (a as Record<string, unknown>)[key],
32
+ (b as Record<string, unknown>)[key],
33
+ )
34
+ ) {
30
35
  return false;
31
36
  }
32
37
  }
@@ -8,10 +8,10 @@ import type { RenderSegmentsOptions } from "../segment-system.js";
8
8
  // ============================================================================
9
9
 
10
10
  /**
11
- * RSC payload received from server
11
+ * RSC payload received from server.
12
+ * The tree is reconstructed from metadata.segments by the browser bridges.
12
13
  */
13
14
  export interface RscPayload<TMetadata = RscMetadata> {
14
- root: ReactNode | Promise<ReactNode> | null;
15
15
  metadata?: TMetadata;
16
16
  returnValue?: ActionResult;
17
17
  formState?: unknown;
@@ -36,6 +36,8 @@ export interface RscMetadata {
36
36
  isError?: boolean;
37
37
  matched?: string[];
38
38
  diff?: string[];
39
+ /** Merged route params from the matched route */
40
+ params?: Record<string, string>;
39
41
  /**
40
42
  * State of named slots for this route match
41
43
  * Key is slot name (e.g., "@modal"), value is slot state
@@ -53,6 +55,11 @@ export interface RscMetadata {
53
55
  * Used to detect version mismatches after HMR/deployment.
54
56
  */
55
57
  version?: string;
58
+ /**
59
+ * TTL in milliseconds for the client-side in-memory prefetch cache.
60
+ * Sent on initial render so the browser can configure its cache duration.
61
+ */
62
+ prefetchCacheTTL?: number;
56
63
  /**
57
64
  * Theme configuration from router.
58
65
  * Included when theme is enabled in router config.
@@ -63,16 +70,12 @@ export interface RscMetadata {
63
70
  * Included when theme is enabled in router config.
64
71
  */
65
72
  initialTheme?: Theme;
66
- /**
67
- * Route map for useHref() - maps route names to URL patterns.
68
- * Used for type-safe URL generation on the client.
69
- */
70
- routeMap?: Record<string, string>;
71
- /**
72
- * Current matched route name (for local name resolution in useHref).
73
- * When using include() with name prefix, this contains the full prefixed name.
74
- */
75
- routeName?: string;
73
+ /** Whether connection warmup is enabled */
74
+ warmupEnabled?: boolean;
75
+ /** Server-side redirect with optional state (for partial requests) */
76
+ redirect?: { url: string };
77
+ /** Server-set location state to include in history.pushState */
78
+ locationState?: Record<string, unknown>;
76
79
  }
77
80
 
78
81
  /**
@@ -123,7 +126,7 @@ export interface NavigationState {
123
126
  /** Whether RSC data is currently streaming (initial load or navigation) */
124
127
  isStreaming: boolean;
125
128
 
126
- /** Current location (updated optimistically) */
129
+ /** Current location */
127
130
  location: NavigationLocation;
128
131
 
129
132
  /** URL being navigated to (null when idle) */
@@ -180,7 +183,7 @@ export type ActionStateListener = (state: TrackedActionState) => void;
180
183
 
181
184
  /**
182
185
  * Cache interface for storing segments
183
- * Compatible with both Map and LRUCache
186
+ * Compatible with Map
184
187
  *
185
188
  * @internal This type is an implementation detail and may change without notice.
186
189
  */
@@ -217,9 +220,11 @@ export interface NavigationUpdate {
217
220
  /**
218
221
  * State value for navigate/Link
219
222
  * - LocationStateEntry[]: Type-safe state entries (recommended)
220
- * - unknown: Legacy format for backwards compatibility
223
+ * - unknown: Plain state format (object or getter function)
221
224
  */
222
- export type HistoryState = import("./react/location-state-shared.js").LocationStateEntry[] | unknown;
225
+ export type HistoryState =
226
+ | import("./react/location-state-shared.js").LocationStateEntry[]
227
+ | unknown;
223
228
 
224
229
  /**
225
230
  * Options for navigation operations
@@ -234,19 +239,67 @@ export interface NavigateOptions {
234
239
  * @example
235
240
  * ```tsx
236
241
  * // Type-safe state (recommended)
237
- * const ProductState = createLocationState<{ name: string }>("product");
242
+ * const ProductState = createLocationState<{ name: string }>();
238
243
  * navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
239
244
  *
245
+ * // Type-safe just-in-time state (getter called at navigation time)
246
+ * navigate("/product/123", {
247
+ * state: [ProductState(() => ({ name: computeName() }))],
248
+ * });
249
+ *
240
250
  * // Multiple states
241
251
  * navigate("/checkout", { state: [ProductState(p), CartState(c)] });
242
252
  *
243
- * // Legacy format (backwards compatible)
253
+ * // Plain static state
244
254
  * navigate("/product", { state: { from: "list" } });
255
+ *
256
+ * // Plain just-in-time state
257
+ * navigate("/product", { state: () => ({ from: window.location.pathname }) });
245
258
  * ```
246
259
  */
247
260
  state?: HistoryState;
248
261
  }
249
262
 
263
+ /** @internal Extended options used only within the navigation bridge */
264
+ export interface NavigateOptionsInternal extends NavigateOptions {
265
+ /** Skip segment cache (used by redirect-with-state to force re-render) */
266
+ _skipCache?: boolean;
267
+ }
268
+
269
+ /**
270
+ * Options for useRouter push/replace methods.
271
+ * Same as NavigateOptions but without `replace` (implicit in push vs replace).
272
+ */
273
+ export type RouterNavigateOptions = Omit<NavigateOptions, "replace">;
274
+
275
+ /**
276
+ * Router instance returned by useRouter hook.
277
+ * Provides stable action methods that never cause re-renders.
278
+ */
279
+ export interface RouterInstance {
280
+ /** Navigate to a URL, pushing a new entry to the history stack */
281
+ push(url: string, options?: RouterNavigateOptions): Promise<void>;
282
+ /** Navigate to a URL, replacing the current history entry */
283
+ replace(url: string, options?: RouterNavigateOptions): Promise<void>;
284
+ /** Refresh the current route (re-fetch server data, preserve client state) */
285
+ refresh(): Promise<void>;
286
+ /** Prefetch a URL for faster client-side transition */
287
+ prefetch(url: string): void;
288
+ /** Go back in browser history */
289
+ back(): void;
290
+ /** Go forward in browser history */
291
+ forward(): void;
292
+ }
293
+
294
+ /**
295
+ * URLSearchParams without mutation methods.
296
+ * Matches Next.js convention for useSearchParams return type.
297
+ */
298
+ export type ReadonlyURLSearchParams = Omit<
299
+ URLSearchParams,
300
+ "append" | "delete" | "set" | "sort"
301
+ >;
302
+
250
303
  // ============================================================================
251
304
  // RSC Browser Dependencies
252
305
  // ============================================================================
@@ -260,15 +313,15 @@ export interface NavigateOptions {
260
313
  export interface RscBrowserDependencies {
261
314
  createFromFetch: <T>(
262
315
  response: Promise<Response>,
263
- options?: { temporaryReferences?: any }
316
+ options?: { temporaryReferences?: any },
264
317
  ) => Promise<T>;
265
318
  createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
266
319
  encodeReply: (
267
320
  args: any[],
268
- options?: { temporaryReferences?: any }
321
+ options?: { temporaryReferences?: any },
269
322
  ) => Promise<FormData | string>;
270
323
  setServerCallback: (
271
- callback: (id: string, args: any[]) => Promise<any>
324
+ callback: (id: string, args: any[]) => Promise<any>,
272
325
  ) => void;
273
326
  createTemporaryReferenceSet: () => any;
274
327
  }
@@ -320,11 +373,13 @@ export interface NavigationStore {
320
373
  cacheSegmentsForHistory(
321
374
  historyKey: string,
322
375
  segments: ResolvedSegment[],
323
- handleData?: HandleData
376
+ handleData?: HandleData,
324
377
  ): void;
325
378
  getCachedSegments(
326
- historyKey: string
327
- ): { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData } | undefined;
379
+ historyKey: string,
380
+ ):
381
+ | { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData }
382
+ | undefined;
328
383
  hasHistoryCache(historyKey: string): boolean;
329
384
  updateCacheHandleData(historyKey: string, handleData: HandleData): void;
330
385
  markCacheAsStale(): void;
@@ -348,39 +403,10 @@ export interface NavigationStore {
348
403
  setActionState(actionId: string, state: Partial<TrackedActionState>): void;
349
404
  subscribeToAction(
350
405
  actionId: string,
351
- listener: ActionStateListener
406
+ listener: ActionStateListener,
352
407
  ): () => void;
353
408
  }
354
409
 
355
- // ============================================================================
356
- // Request Controller Types
357
- // ============================================================================
358
-
359
- /**
360
- * Disposable abort controller with automatic cleanup
361
- */
362
- export interface DisposableAbortController extends Disposable {
363
- controller: AbortController;
364
- }
365
-
366
- /**
367
- * Request controller for managing concurrent requests
368
- *
369
- * Separates navigation requests (aborted on new navigation) from
370
- * action requests (complete independently of navigation).
371
- */
372
- export interface RequestController {
373
- create(): AbortController;
374
- createDisposable(): DisposableAbortController;
375
- /** Create a disposable controller for actions (not aborted by navigation) */
376
- createActionDisposable(): DisposableAbortController;
377
- /** Abort all navigation requests (not actions) */
378
- abortAll(): void;
379
- /** Abort all action requests (used for error handling) */
380
- abortAllActions(): void;
381
- remove(controller: AbortController): void;
382
- }
383
-
384
410
  // ============================================================================
385
411
  // Navigation Client Types
386
412
  // ============================================================================
@@ -398,6 +424,8 @@ export interface FetchPartialOptions {
398
424
  interceptSourceUrl?: string;
399
425
  /** RSC version for cache invalidation detection */
400
426
  version?: string;
427
+ /** If true, this is an HMR refetch - server should invalidate manifest cache */
428
+ hmr?: boolean;
401
429
  }
402
430
 
403
431
  /**
@@ -436,7 +464,6 @@ export interface LinkInterceptorOptions {
436
464
  */
437
465
  export interface ServerActionBridge {
438
466
  register(): void;
439
- unregister(): void;
440
467
  }
441
468
 
442
469
  /**
@@ -449,7 +476,7 @@ export interface ServerActionBridgeConfig {
449
476
  onUpdate: UpdateSubscriber;
450
477
  renderSegments: (
451
478
  segments: ResolvedSegment[],
452
- options?: RenderSegmentsOptions
479
+ options?: RenderSegmentsOptions,
453
480
  ) => Promise<ReactNode> | ReactNode;
454
481
  }
455
482
 
@@ -476,9 +503,17 @@ export interface NavigationBridgeConfig {
476
503
  onUpdate: UpdateSubscriber;
477
504
  renderSegments: (
478
505
  segments: ResolvedSegment[],
479
- options?: RenderSegmentsOptions
506
+ options?: RenderSegmentsOptions,
480
507
  ) => Promise<ReactNode> | ReactNode;
481
508
  }
482
509
 
483
510
  // Re-export ResolvedSegment for convenience
484
511
  export type { ResolvedSegment };
512
+
513
+ /**
514
+ * Token for tracking an active stream.
515
+ * Call end() when the stream completes.
516
+ */
517
+ export interface StreamingToken {
518
+ end(): void;
519
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Validate that a client-consumed redirect URL (from headers or Flight payload)
3
+ * targets the same origin as the current page. Prevents open-redirect attacks
4
+ * via crafted responses.
5
+ *
6
+ * @returns The canonical (normalized) URL string on success, or null if blocked.
7
+ */
8
+ export function validateRedirectOrigin(
9
+ url: string,
10
+ currentOrigin: string,
11
+ ): string | null {
12
+ try {
13
+ const target = new URL(url, currentOrigin);
14
+ if (target.origin !== currentOrigin) {
15
+ console.error(
16
+ `[rango] Redirect blocked: origin mismatch (${target.origin})`,
17
+ );
18
+ return null;
19
+ }
20
+ // Return pathname+search+hash for relative inputs, full href for absolute.
21
+ // This normalizes protocol-relative and other ambiguous forms.
22
+ return target.href.startsWith(currentOrigin)
23
+ ? target.href
24
+ : target.pathname + target.search + target.hash;
25
+ } catch {
26
+ console.error(`[rango] Redirect blocked: invalid URL "${url}"`);
27
+ return null;
28
+ }
29
+ }