@rangojs/router 0.0.0-experimental.002d056c

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 (305) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +899 -0
  3. package/dist/bin/rango.js +1606 -0
  4. package/dist/vite/index.js +5153 -0
  5. package/package.json +177 -0
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +253 -0
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +112 -0
  11. package/skills/document-cache/SKILL.md +182 -0
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +704 -0
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +313 -0
  16. package/skills/layout/SKILL.md +310 -0
  17. package/skills/links/SKILL.md +239 -0
  18. package/skills/loader/SKILL.md +596 -0
  19. package/skills/middleware/SKILL.md +339 -0
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +305 -0
  22. package/skills/prerender/SKILL.md +643 -0
  23. package/skills/rango/SKILL.md +118 -0
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +385 -0
  26. package/skills/router-setup/SKILL.md +439 -0
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +79 -0
  29. package/skills/typesafety/SKILL.md +623 -0
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +273 -0
  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 +899 -0
  36. package/src/browser/history-state.ts +80 -0
  37. package/src/browser/index.ts +18 -0
  38. package/src/browser/intercept-utils.ts +52 -0
  39. package/src/browser/link-interceptor.ts +141 -0
  40. package/src/browser/logging.ts +55 -0
  41. package/src/browser/merge-segment-loaders.ts +134 -0
  42. package/src/browser/navigation-bridge.ts +638 -0
  43. package/src/browser/navigation-client.ts +261 -0
  44. package/src/browser/navigation-store.ts +806 -0
  45. package/src/browser/navigation-transaction.ts +297 -0
  46. package/src/browser/network-error-handler.ts +61 -0
  47. package/src/browser/partial-update.ts +582 -0
  48. package/src/browser/prefetch/cache.ts +206 -0
  49. package/src/browser/prefetch/fetch.ts +145 -0
  50. package/src/browser/prefetch/observer.ts +65 -0
  51. package/src/browser/prefetch/policy.ts +48 -0
  52. package/src/browser/prefetch/queue.ts +128 -0
  53. package/src/browser/rango-state.ts +112 -0
  54. package/src/browser/react/Link.tsx +368 -0
  55. package/src/browser/react/NavigationProvider.tsx +413 -0
  56. package/src/browser/react/ScrollRestoration.tsx +94 -0
  57. package/src/browser/react/context.ts +59 -0
  58. package/src/browser/react/filter-segment-order.ts +11 -0
  59. package/src/browser/react/index.ts +52 -0
  60. package/src/browser/react/location-state-shared.ts +162 -0
  61. package/src/browser/react/location-state.ts +107 -0
  62. package/src/browser/react/mount-context.ts +37 -0
  63. package/src/browser/react/nonce-context.ts +23 -0
  64. package/src/browser/react/shallow-equal.ts +27 -0
  65. package/src/browser/react/use-action.ts +218 -0
  66. package/src/browser/react/use-client-cache.ts +58 -0
  67. package/src/browser/react/use-handle.ts +162 -0
  68. package/src/browser/react/use-href.tsx +40 -0
  69. package/src/browser/react/use-link-status.ts +135 -0
  70. package/src/browser/react/use-mount.ts +31 -0
  71. package/src/browser/react/use-navigation.ts +99 -0
  72. package/src/browser/react/use-params.ts +65 -0
  73. package/src/browser/react/use-pathname.ts +47 -0
  74. package/src/browser/react/use-router.ts +63 -0
  75. package/src/browser/react/use-search-params.ts +56 -0
  76. package/src/browser/react/use-segments.ts +171 -0
  77. package/src/browser/response-adapter.ts +73 -0
  78. package/src/browser/rsc-router.tsx +464 -0
  79. package/src/browser/scroll-restoration.ts +397 -0
  80. package/src/browser/segment-reconciler.ts +216 -0
  81. package/src/browser/segment-structure-assert.ts +83 -0
  82. package/src/browser/server-action-bridge.ts +667 -0
  83. package/src/browser/shallow.ts +40 -0
  84. package/src/browser/types.ts +547 -0
  85. package/src/browser/validate-redirect-origin.ts +29 -0
  86. package/src/build/generate-manifest.ts +438 -0
  87. package/src/build/generate-route-types.ts +36 -0
  88. package/src/build/index.ts +35 -0
  89. package/src/build/route-trie.ts +265 -0
  90. package/src/build/route-types/ast-helpers.ts +25 -0
  91. package/src/build/route-types/ast-route-extraction.ts +98 -0
  92. package/src/build/route-types/codegen.ts +102 -0
  93. package/src/build/route-types/include-resolution.ts +411 -0
  94. package/src/build/route-types/param-extraction.ts +48 -0
  95. package/src/build/route-types/per-module-writer.ts +128 -0
  96. package/src/build/route-types/router-processing.ts +479 -0
  97. package/src/build/route-types/scan-filter.ts +78 -0
  98. package/src/build/runtime-discovery.ts +231 -0
  99. package/src/cache/background-task.ts +34 -0
  100. package/src/cache/cache-key-utils.ts +44 -0
  101. package/src/cache/cache-policy.ts +125 -0
  102. package/src/cache/cache-runtime.ts +338 -0
  103. package/src/cache/cache-scope.ts +382 -0
  104. package/src/cache/cf/cf-cache-store.ts +982 -0
  105. package/src/cache/cf/index.ts +29 -0
  106. package/src/cache/document-cache.ts +369 -0
  107. package/src/cache/handle-capture.ts +81 -0
  108. package/src/cache/handle-snapshot.ts +41 -0
  109. package/src/cache/index.ts +44 -0
  110. package/src/cache/memory-segment-store.ts +328 -0
  111. package/src/cache/profile-registry.ts +73 -0
  112. package/src/cache/read-through-swr.ts +134 -0
  113. package/src/cache/segment-codec.ts +256 -0
  114. package/src/cache/taint.ts +98 -0
  115. package/src/cache/types.ts +342 -0
  116. package/src/client.rsc.tsx +85 -0
  117. package/src/client.tsx +601 -0
  118. package/src/component-utils.ts +76 -0
  119. package/src/components/DefaultDocument.tsx +27 -0
  120. package/src/context-var.ts +86 -0
  121. package/src/debug.ts +243 -0
  122. package/src/default-error-boundary.tsx +88 -0
  123. package/src/deps/browser.ts +8 -0
  124. package/src/deps/html-stream-client.ts +2 -0
  125. package/src/deps/html-stream-server.ts +2 -0
  126. package/src/deps/rsc.ts +10 -0
  127. package/src/deps/ssr.ts +2 -0
  128. package/src/errors.ts +365 -0
  129. package/src/handle.ts +135 -0
  130. package/src/handles/MetaTags.tsx +246 -0
  131. package/src/handles/breadcrumbs.ts +66 -0
  132. package/src/handles/index.ts +7 -0
  133. package/src/handles/meta.ts +264 -0
  134. package/src/host/cookie-handler.ts +165 -0
  135. package/src/host/errors.ts +97 -0
  136. package/src/host/index.ts +53 -0
  137. package/src/host/pattern-matcher.ts +214 -0
  138. package/src/host/router.ts +352 -0
  139. package/src/host/testing.ts +79 -0
  140. package/src/host/types.ts +146 -0
  141. package/src/host/utils.ts +25 -0
  142. package/src/href-client.ts +222 -0
  143. package/src/index.rsc.ts +233 -0
  144. package/src/index.ts +277 -0
  145. package/src/internal-debug.ts +11 -0
  146. package/src/loader.rsc.ts +89 -0
  147. package/src/loader.ts +64 -0
  148. package/src/network-error-thrower.tsx +23 -0
  149. package/src/outlet-context.ts +15 -0
  150. package/src/outlet-provider.tsx +45 -0
  151. package/src/prerender/param-hash.ts +37 -0
  152. package/src/prerender/store.ts +185 -0
  153. package/src/prerender.ts +463 -0
  154. package/src/reverse.ts +330 -0
  155. package/src/root-error-boundary.tsx +289 -0
  156. package/src/route-content-wrapper.tsx +196 -0
  157. package/src/route-definition/dsl-helpers.ts +934 -0
  158. package/src/route-definition/helper-factories.ts +200 -0
  159. package/src/route-definition/helpers-types.ts +430 -0
  160. package/src/route-definition/index.ts +52 -0
  161. package/src/route-definition/redirect.ts +93 -0
  162. package/src/route-definition.ts +1 -0
  163. package/src/route-map-builder.ts +281 -0
  164. package/src/route-name.ts +53 -0
  165. package/src/route-types.ts +259 -0
  166. package/src/router/content-negotiation.ts +116 -0
  167. package/src/router/debug-manifest.ts +72 -0
  168. package/src/router/error-handling.ts +287 -0
  169. package/src/router/find-match.ts +160 -0
  170. package/src/router/handler-context.ts +451 -0
  171. package/src/router/intercept-resolution.ts +397 -0
  172. package/src/router/lazy-includes.ts +236 -0
  173. package/src/router/loader-resolution.ts +420 -0
  174. package/src/router/logging.ts +251 -0
  175. package/src/router/manifest.ts +269 -0
  176. package/src/router/match-api.ts +620 -0
  177. package/src/router/match-context.ts +266 -0
  178. package/src/router/match-handlers.ts +440 -0
  179. package/src/router/match-middleware/background-revalidation.ts +223 -0
  180. package/src/router/match-middleware/cache-lookup.ts +634 -0
  181. package/src/router/match-middleware/cache-store.ts +295 -0
  182. package/src/router/match-middleware/index.ts +81 -0
  183. package/src/router/match-middleware/intercept-resolution.ts +306 -0
  184. package/src/router/match-middleware/segment-resolution.ts +193 -0
  185. package/src/router/match-pipelines.ts +179 -0
  186. package/src/router/match-result.ts +219 -0
  187. package/src/router/metrics.ts +282 -0
  188. package/src/router/middleware-cookies.ts +55 -0
  189. package/src/router/middleware-types.ts +222 -0
  190. package/src/router/middleware.ts +749 -0
  191. package/src/router/pattern-matching.ts +563 -0
  192. package/src/router/prerender-match.ts +402 -0
  193. package/src/router/preview-match.ts +170 -0
  194. package/src/router/revalidation.ts +289 -0
  195. package/src/router/router-context.ts +320 -0
  196. package/src/router/router-interfaces.ts +452 -0
  197. package/src/router/router-options.ts +592 -0
  198. package/src/router/router-registry.ts +24 -0
  199. package/src/router/segment-resolution/fresh.ts +570 -0
  200. package/src/router/segment-resolution/helpers.ts +263 -0
  201. package/src/router/segment-resolution/loader-cache.ts +198 -0
  202. package/src/router/segment-resolution/revalidation.ts +1242 -0
  203. package/src/router/segment-resolution/static-store.ts +67 -0
  204. package/src/router/segment-resolution.ts +21 -0
  205. package/src/router/segment-wrappers.ts +291 -0
  206. package/src/router/telemetry-otel.ts +299 -0
  207. package/src/router/telemetry.ts +300 -0
  208. package/src/router/timeout.ts +148 -0
  209. package/src/router/trie-matching.ts +239 -0
  210. package/src/router/types.ts +170 -0
  211. package/src/router.ts +1006 -0
  212. package/src/rsc/handler-context.ts +45 -0
  213. package/src/rsc/handler.ts +1089 -0
  214. package/src/rsc/helpers.ts +198 -0
  215. package/src/rsc/index.ts +36 -0
  216. package/src/rsc/loader-fetch.ts +209 -0
  217. package/src/rsc/manifest-init.ts +86 -0
  218. package/src/rsc/nonce.ts +32 -0
  219. package/src/rsc/origin-guard.ts +141 -0
  220. package/src/rsc/progressive-enhancement.ts +379 -0
  221. package/src/rsc/response-error.ts +37 -0
  222. package/src/rsc/response-route-handler.ts +347 -0
  223. package/src/rsc/rsc-rendering.ts +237 -0
  224. package/src/rsc/runtime-warnings.ts +42 -0
  225. package/src/rsc/server-action.ts +348 -0
  226. package/src/rsc/ssr-setup.ts +128 -0
  227. package/src/rsc/types.ts +263 -0
  228. package/src/search-params.ts +230 -0
  229. package/src/segment-system.tsx +454 -0
  230. package/src/server/context.ts +591 -0
  231. package/src/server/cookie-store.ts +190 -0
  232. package/src/server/fetchable-loader-store.ts +37 -0
  233. package/src/server/handle-store.ts +308 -0
  234. package/src/server/loader-registry.ts +133 -0
  235. package/src/server/request-context.ts +920 -0
  236. package/src/server/root-layout.tsx +10 -0
  237. package/src/server/tsconfig.json +14 -0
  238. package/src/server.ts +51 -0
  239. package/src/ssr/index.tsx +365 -0
  240. package/src/static-handler.ts +114 -0
  241. package/src/theme/ThemeProvider.tsx +297 -0
  242. package/src/theme/ThemeScript.tsx +61 -0
  243. package/src/theme/constants.ts +62 -0
  244. package/src/theme/index.ts +48 -0
  245. package/src/theme/theme-context.ts +44 -0
  246. package/src/theme/theme-script.ts +155 -0
  247. package/src/theme/types.ts +182 -0
  248. package/src/theme/use-theme.ts +44 -0
  249. package/src/types/boundaries.ts +158 -0
  250. package/src/types/cache-types.ts +198 -0
  251. package/src/types/error-types.ts +192 -0
  252. package/src/types/global-namespace.ts +100 -0
  253. package/src/types/handler-context.ts +687 -0
  254. package/src/types/index.ts +88 -0
  255. package/src/types/loader-types.ts +183 -0
  256. package/src/types/route-config.ts +170 -0
  257. package/src/types/route-entry.ts +109 -0
  258. package/src/types/segments.ts +148 -0
  259. package/src/types.ts +1 -0
  260. package/src/urls/include-helper.ts +197 -0
  261. package/src/urls/index.ts +53 -0
  262. package/src/urls/path-helper-types.ts +339 -0
  263. package/src/urls/path-helper.ts +329 -0
  264. package/src/urls/pattern-types.ts +95 -0
  265. package/src/urls/response-types.ts +106 -0
  266. package/src/urls/type-extraction.ts +372 -0
  267. package/src/urls/urls-function.ts +98 -0
  268. package/src/urls.ts +1 -0
  269. package/src/use-loader.tsx +354 -0
  270. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  271. package/src/vite/discovery/discover-routers.ts +344 -0
  272. package/src/vite/discovery/prerender-collection.ts +385 -0
  273. package/src/vite/discovery/route-types-writer.ts +258 -0
  274. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  275. package/src/vite/discovery/state.ts +108 -0
  276. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  277. package/src/vite/index.ts +16 -0
  278. package/src/vite/plugin-types.ts +48 -0
  279. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  280. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  281. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  282. package/src/vite/plugins/expose-action-id.ts +363 -0
  283. package/src/vite/plugins/expose-id-utils.ts +287 -0
  284. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  285. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  286. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  287. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  288. package/src/vite/plugins/expose-ids/types.ts +45 -0
  289. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  290. package/src/vite/plugins/refresh-cmd.ts +65 -0
  291. package/src/vite/plugins/use-cache-transform.ts +323 -0
  292. package/src/vite/plugins/version-injector.ts +83 -0
  293. package/src/vite/plugins/version-plugin.ts +266 -0
  294. package/src/vite/plugins/version.d.ts +12 -0
  295. package/src/vite/plugins/virtual-entries.ts +123 -0
  296. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  297. package/src/vite/rango.ts +445 -0
  298. package/src/vite/router-discovery.ts +777 -0
  299. package/src/vite/utils/ast-handler-extract.ts +517 -0
  300. package/src/vite/utils/banner.ts +36 -0
  301. package/src/vite/utils/bundle-analysis.ts +137 -0
  302. package/src/vite/utils/manifest-utils.ts +70 -0
  303. package/src/vite/utils/package-resolution.ts +121 -0
  304. package/src/vite/utils/prerender-utils.ts +189 -0
  305. package/src/vite/utils/shared-utils.ts +169 -0
@@ -0,0 +1,547 @@
1
+ import type { ReactNode, ComponentType } from "react";
2
+ import type { ResolvedSegment, SlotState } from "../types.js";
3
+ import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
4
+ import type { RenderSegmentsOptions } from "../segment-system.js";
5
+
6
+ // ============================================================================
7
+ // RSC Payload Types
8
+ // ============================================================================
9
+
10
+ /**
11
+ * RSC payload received from server.
12
+ * The tree is reconstructed from metadata.segments by the browser bridges.
13
+ */
14
+ export interface RscPayload<TMetadata = RscMetadata> {
15
+ metadata?: TMetadata;
16
+ returnValue?: ActionResult;
17
+ formState?: unknown;
18
+ }
19
+
20
+ /**
21
+ * Handle data structure: handleName -> segmentId -> entries[]
22
+ *
23
+ * @internal This type is an implementation detail and may change without notice.
24
+ */
25
+ export type HandleData = Record<string, Record<string, unknown[]>>;
26
+
27
+ /**
28
+ * Metadata included in RSC responses
29
+ *
30
+ * @internal This type is an implementation detail and may change without notice.
31
+ */
32
+ export interface RscMetadata {
33
+ pathname: string;
34
+ segments: ResolvedSegment[];
35
+ isPartial?: boolean;
36
+ isError?: boolean;
37
+ matched?: string[];
38
+ diff?: string[];
39
+ /** Merged route params from the matched route */
40
+ params?: Record<string, string>;
41
+ /**
42
+ * State of named slots for this route match
43
+ * Key is slot name (e.g., "@modal"), value is slot state
44
+ * Slots are used for intercepting routes during soft navigation
45
+ */
46
+ slots?: Record<string, SlotState>;
47
+ /** Root layout component for browser-side re-renders */
48
+ rootLayout?: ComponentType<{ children: ReactNode }>;
49
+ /** Handle data accumulated across route segments (async generator that yields on each push) */
50
+ handles?: AsyncGenerator<HandleData, void, unknown>;
51
+ /** Cached handle data (for back/forward navigation from cache) */
52
+ cachedHandleData?: HandleData;
53
+ /**
54
+ * RSC version string from the server.
55
+ * Used to detect version mismatches after HMR/deployment.
56
+ */
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;
63
+ /**
64
+ * Theme configuration from router.
65
+ * Included when theme is enabled in router config.
66
+ */
67
+ themeConfig?: ResolvedThemeConfig | null;
68
+ /**
69
+ * Initial theme from cookie (for SSR hydration).
70
+ * Included when theme is enabled in router config.
71
+ */
72
+ initialTheme?: Theme;
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>;
79
+ }
80
+
81
+ /**
82
+ * Result from server action execution
83
+ *
84
+ * @internal This type is an implementation detail and may change without notice.
85
+ */
86
+ export interface ActionResult {
87
+ ok: boolean;
88
+ data: unknown;
89
+ }
90
+
91
+ // ============================================================================
92
+ // Navigation State Types
93
+ // ============================================================================
94
+
95
+ /**
96
+ * Location object representing current URL
97
+ * Uses URL for full URL parsing (origin, host, hostname, port, protocol, searchParams, etc.)
98
+ */
99
+ export type NavigationLocation = URL;
100
+
101
+ /**
102
+ * Inflight server action being tracked
103
+ *
104
+ * @internal This type is an implementation detail and may change without notice.
105
+ */
106
+ export interface InflightAction {
107
+ /** Unique identifier for this action invocation */
108
+ id: string;
109
+ /** Server action function ID */
110
+ actionId: string;
111
+ /** Action arguments */
112
+ payload: unknown[];
113
+ /** Timestamp when action started */
114
+ startedAt: number;
115
+ }
116
+
117
+ /**
118
+ * Internal navigation state (includes inflight actions for store use)
119
+ *
120
+ * @internal This type is an implementation detail. Use PublicNavigationState instead.
121
+ */
122
+ export interface NavigationState {
123
+ /** Navigation lifecycle state (idle or loading during navigation) */
124
+ state: "idle" | "loading";
125
+
126
+ /** Whether RSC data is currently streaming (initial load or navigation) */
127
+ isStreaming: boolean;
128
+
129
+ /** Current location */
130
+ location: NavigationLocation;
131
+
132
+ /** URL being navigated to (null when idle) */
133
+ pendingUrl: string | null;
134
+
135
+ /** List of inflight server actions (internal use only) */
136
+ inflightActions: InflightAction[];
137
+ }
138
+
139
+ /**
140
+ * Public navigation state exposed via useNavigation hook
141
+ * Excludes internal properties like inflightActions
142
+ */
143
+ export type PublicNavigationState = Omit<NavigationState, "inflightActions">;
144
+
145
+ // ============================================================================
146
+ // Action State Types (for useAction hook)
147
+ // ============================================================================
148
+
149
+ /**
150
+ * Action lifecycle state
151
+ */
152
+ export type ActionLifecycleState = "idle" | "loading" | "streaming";
153
+
154
+ /**
155
+ * State for a tracked server action
156
+ * Used by useAction hook to observe action lifecycle
157
+ *
158
+ * @internal This type is an implementation detail and may change without notice.
159
+ */
160
+ export interface TrackedActionState {
161
+ /** Current lifecycle state of the action */
162
+ state: ActionLifecycleState;
163
+
164
+ /** Server action function ID (e.g., "addToCart") */
165
+ actionId: string | null;
166
+
167
+ /** Action arguments (array for JSON, FormData for form submissions) */
168
+ payload: unknown[] | FormData | null;
169
+
170
+ /** Error if action failed */
171
+ error: unknown | null;
172
+
173
+ /** Result data from the action (preserved after completion) */
174
+ result: unknown | null;
175
+ }
176
+
177
+ /**
178
+ * Listener for action state changes
179
+ *
180
+ * @internal This type is an implementation detail and may change without notice.
181
+ */
182
+ export type ActionStateListener = (state: TrackedActionState) => void;
183
+
184
+ /**
185
+ * Cache interface for storing segments
186
+ * Compatible with Map
187
+ *
188
+ * @internal This type is an implementation detail and may change without notice.
189
+ */
190
+ export interface SegmentCache {
191
+ get(key: string): ResolvedSegment | undefined;
192
+ set(key: string, value: ResolvedSegment): void;
193
+ has(key: string): boolean;
194
+ delete(key: string): boolean;
195
+ keys(): IterableIterator<string>;
196
+ readonly size: number;
197
+ }
198
+
199
+ /**
200
+ * Internal segment state managed by the store
201
+ *
202
+ * @internal This type is an implementation detail and may change without notice.
203
+ */
204
+ export interface SegmentState {
205
+ path: string;
206
+ currentUrl: string;
207
+ currentSegmentIds: string[];
208
+ }
209
+
210
+ /**
211
+ * Navigation update emitted when UI should re-render
212
+ *
213
+ * @internal This type is an implementation detail and may change without notice.
214
+ */
215
+ export interface NavigationUpdate {
216
+ root: ReactNode | Promise<ReactNode>;
217
+ metadata: RscMetadata;
218
+ /** Scroll behavior to apply after React commits this update */
219
+ scroll?: {
220
+ /** For back/forward: restore saved position */
221
+ restore?: boolean;
222
+ /** Set to false to disable scrolling entirely */
223
+ enabled?: boolean;
224
+ /** Function to check if streaming is in progress */
225
+ isStreaming?: () => boolean;
226
+ };
227
+ }
228
+
229
+ /**
230
+ * State value for navigate/Link
231
+ * - LocationStateEntry[]: Type-safe state entries (recommended)
232
+ * - unknown: Plain state format (object or getter function)
233
+ */
234
+ export type HistoryState =
235
+ | import("./react/location-state-shared.js").LocationStateEntry[]
236
+ | unknown;
237
+
238
+ /**
239
+ * Options for navigation operations
240
+ */
241
+ export interface NavigateOptions {
242
+ replace?: boolean;
243
+ scroll?: boolean;
244
+ /**
245
+ * Whether to revalidate server data on navigation.
246
+ * Set to `false` to skip the RSC server fetch and only update the URL.
247
+ *
248
+ * Only takes effect when the pathname stays the same (search param / hash changes).
249
+ * If the pathname changes, this option is ignored and a full navigation occurs.
250
+ *
251
+ * All location-aware hooks (`useSearchParams`, `useNavigation`, etc.) still update.
252
+ * Server components do not re-render.
253
+ *
254
+ * @default true
255
+ *
256
+ * @example
257
+ * ```tsx
258
+ * router.push("/products?color=blue", { revalidate: false });
259
+ * router.replace("/products?page=3", { revalidate: false });
260
+ * ```
261
+ */
262
+ revalidate?: boolean;
263
+ /**
264
+ * State to pass to history.pushState/replaceState
265
+ * Accessible via useLocationState() hook.
266
+ *
267
+ * @example
268
+ * ```tsx
269
+ * // Type-safe state (recommended)
270
+ * const ProductState = createLocationState<{ name: string }>();
271
+ * navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
272
+ *
273
+ * // Type-safe just-in-time state (getter called at navigation time)
274
+ * navigate("/product/123", {
275
+ * state: [ProductState(() => ({ name: computeName() }))],
276
+ * });
277
+ *
278
+ * // Multiple states
279
+ * navigate("/checkout", { state: [ProductState(p), CartState(c)] });
280
+ *
281
+ * // Plain static state
282
+ * navigate("/product", { state: { from: "list" } });
283
+ *
284
+ * // Plain just-in-time state
285
+ * navigate("/product", { state: () => ({ from: window.location.pathname }) });
286
+ * ```
287
+ */
288
+ state?: HistoryState;
289
+ }
290
+
291
+ /** @internal Extended options used only within the navigation bridge */
292
+ export interface NavigateOptionsInternal extends NavigateOptions {
293
+ /** Skip segment cache (used by redirect-with-state to force re-render) */
294
+ _skipCache?: boolean;
295
+ }
296
+
297
+ /**
298
+ * Options for useRouter push/replace methods.
299
+ * Same as NavigateOptions but without `replace` (implicit in push vs replace).
300
+ */
301
+ export type RouterNavigateOptions = Omit<NavigateOptions, "replace">;
302
+
303
+ /**
304
+ * Router instance returned by useRouter hook.
305
+ * Provides stable action methods that never cause re-renders.
306
+ */
307
+ export interface RouterInstance {
308
+ /** Navigate to a URL, pushing a new entry to the history stack */
309
+ push(url: string, options?: RouterNavigateOptions): Promise<void>;
310
+ /** Navigate to a URL, replacing the current history entry */
311
+ replace(url: string, options?: RouterNavigateOptions): Promise<void>;
312
+ /** Refresh the current route (re-fetch server data, preserve client state) */
313
+ refresh(): Promise<void>;
314
+ /** Prefetch a URL for faster client-side transition */
315
+ prefetch(url: string): void;
316
+ /** Go back in browser history */
317
+ back(): void;
318
+ /** Go forward in browser history */
319
+ forward(): void;
320
+ }
321
+
322
+ /**
323
+ * URLSearchParams without mutation methods.
324
+ * Matches Next.js convention for useSearchParams return type.
325
+ */
326
+ export type ReadonlyURLSearchParams = Omit<
327
+ URLSearchParams,
328
+ "append" | "delete" | "set" | "sort"
329
+ >;
330
+
331
+ // ============================================================================
332
+ // RSC Browser Dependencies
333
+ // ============================================================================
334
+
335
+ /**
336
+ * RSC runtime functions from @vitejs/plugin-rsc/browser
337
+ *
338
+ * These are injected as dependencies to avoid direct coupling
339
+ * to the RSC runtime implementation.
340
+ */
341
+ export interface RscBrowserDependencies {
342
+ createFromFetch: <T>(
343
+ response: Promise<Response>,
344
+ options?: { temporaryReferences?: any },
345
+ ) => Promise<T>;
346
+ createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
347
+ encodeReply: (
348
+ args: any[],
349
+ options?: { temporaryReferences?: any },
350
+ ) => Promise<FormData | string>;
351
+ setServerCallback: (
352
+ callback: (id: string, args: any[]) => Promise<any>,
353
+ ) => void;
354
+ createTemporaryReferenceSet: () => any;
355
+ }
356
+
357
+ // ============================================================================
358
+ // Store Types
359
+ // ============================================================================
360
+
361
+ /**
362
+ * Update subscriber callback for UI updates
363
+ */
364
+ export type UpdateSubscriber = (update: NavigationUpdate) => void;
365
+
366
+ /**
367
+ * State change listener for useNavigation hook subscriptions
368
+ */
369
+ export type StateListener = () => void;
370
+
371
+ /**
372
+ * Navigation store interface
373
+ *
374
+ * Manages both:
375
+ * - NavigationState: Public state exposed via useNavigation hook
376
+ * - SegmentState: Internal segment management for partial updates
377
+ */
378
+ export interface NavigationStore {
379
+ // Public state (for useNavigation hook)
380
+ getState(): NavigationState;
381
+ setState(partial: Partial<NavigationState>): void;
382
+ subscribe(listener: StateListener): () => void;
383
+
384
+ // Inflight action management
385
+ addInflightAction(action: InflightAction): void;
386
+ removeInflightAction(id: string): void;
387
+
388
+ // Action state (for controlling update behavior during server actions)
389
+ isActionInProgress(): boolean;
390
+ setActionInProgress(value: boolean): void;
391
+
392
+ // Internal segment state (for bridges)
393
+ getSegmentState(): SegmentState;
394
+ setPath(path: string): void;
395
+ setCurrentUrl(url: string): void;
396
+ setSegmentIds(ids: string[]): void;
397
+
398
+ // History-based segment cache (for back/forward navigation and partial merging)
399
+ getHistoryKey(): string;
400
+ setHistoryKey(key: string): void;
401
+ cacheSegmentsForHistory(
402
+ historyKey: string,
403
+ segments: ResolvedSegment[],
404
+ handleData?: HandleData,
405
+ ): void;
406
+ getCachedSegments(
407
+ historyKey: string,
408
+ ):
409
+ | { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData }
410
+ | undefined;
411
+ hasHistoryCache(historyKey: string): boolean;
412
+ updateCacheHandleData(historyKey: string, handleData: HandleData): void;
413
+ markCacheAsStale(): void;
414
+ markCacheAsStaleAndBroadcast(): void;
415
+ clearHistoryCache(): void;
416
+ broadcastCacheInvalidation(): void;
417
+
418
+ // Cross-tab refresh callback (set by navigation bridge)
419
+ setCrossTabRefreshCallback(callback: () => void): void;
420
+
421
+ // Intercept context tracking (for action revalidation)
422
+ getInterceptSourceUrl(): string | null;
423
+ setInterceptSourceUrl(url: string | null): void;
424
+
425
+ // UI update notifications
426
+ onUpdate(callback: UpdateSubscriber): () => void;
427
+ emitUpdate(update: NavigationUpdate): void;
428
+
429
+ // Action state tracking (for useAction hook)
430
+ getActionState(actionId: string): TrackedActionState;
431
+ setActionState(actionId: string, state: Partial<TrackedActionState>): void;
432
+ subscribeToAction(
433
+ actionId: string,
434
+ listener: ActionStateListener,
435
+ ): () => void;
436
+ }
437
+
438
+ // ============================================================================
439
+ // Navigation Client Types
440
+ // ============================================================================
441
+
442
+ /**
443
+ * Options for partial navigation fetch
444
+ */
445
+ export interface FetchPartialOptions {
446
+ targetUrl: string;
447
+ segmentIds: string[];
448
+ previousUrl: string;
449
+ signal?: AbortSignal;
450
+ /** If true, this is a stale cache revalidation request - server should force revalidators */
451
+ staleRevalidation?: boolean;
452
+ interceptSourceUrl?: string;
453
+ /** RSC version for cache invalidation detection */
454
+ version?: string;
455
+ /** If true, this is an HMR refetch - server should invalidate manifest cache */
456
+ hmr?: boolean;
457
+ }
458
+
459
+ /**
460
+ * Result of a partial fetch including stream completion tracking
461
+ */
462
+ export interface FetchPartialResult {
463
+ payload: RscPayload;
464
+ /** Promise that resolves when the response stream is fully consumed */
465
+ streamComplete: Promise<void>;
466
+ }
467
+
468
+ /**
469
+ * Navigation client for fetching RSC payloads
470
+ */
471
+ export interface NavigationClient {
472
+ fetchPartial(options: FetchPartialOptions): Promise<FetchPartialResult>;
473
+ }
474
+
475
+ // ============================================================================
476
+ // Link Interceptor Types
477
+ // ============================================================================
478
+
479
+ /**
480
+ * Options for link interception
481
+ */
482
+ export interface LinkInterceptorOptions {
483
+ shouldIntercept?: (link: HTMLAnchorElement) => boolean;
484
+ }
485
+
486
+ // ============================================================================
487
+ // Server Action Bridge Types
488
+ // ============================================================================
489
+
490
+ /**
491
+ * Server action bridge for handling server actions
492
+ */
493
+ export interface ServerActionBridge {
494
+ register(): void;
495
+ }
496
+
497
+ /**
498
+ * Configuration for server action bridge
499
+ */
500
+ export interface ServerActionBridgeConfig {
501
+ store: NavigationStore;
502
+ client: NavigationClient;
503
+ deps: RscBrowserDependencies;
504
+ onUpdate: UpdateSubscriber;
505
+ renderSegments: (
506
+ segments: ResolvedSegment[],
507
+ options?: RenderSegmentsOptions,
508
+ ) => Promise<ReactNode> | ReactNode;
509
+ }
510
+
511
+ // ============================================================================
512
+ // Navigation Bridge Types
513
+ // ============================================================================
514
+
515
+ /**
516
+ * Navigation bridge for handling client-side navigation
517
+ */
518
+ export interface NavigationBridge {
519
+ navigate(url: string, options?: NavigateOptions): Promise<void>;
520
+ refresh(): Promise<void>;
521
+ handlePopstate(): Promise<void>;
522
+ registerLinkInterception(): () => void;
523
+ }
524
+
525
+ /**
526
+ * Configuration for navigation bridge
527
+ */
528
+ export interface NavigationBridgeConfig {
529
+ store: NavigationStore;
530
+ client: NavigationClient;
531
+ onUpdate: UpdateSubscriber;
532
+ renderSegments: (
533
+ segments: ResolvedSegment[],
534
+ options?: RenderSegmentsOptions,
535
+ ) => Promise<ReactNode> | ReactNode;
536
+ }
537
+
538
+ // Re-export ResolvedSegment for convenience
539
+ export type { ResolvedSegment };
540
+
541
+ /**
542
+ * Token for tracking an active stream.
543
+ * Call end() when the stream completes.
544
+ */
545
+ export interface StreamingToken {
546
+ end(): void;
547
+ }
@@ -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
+ }