@rangojs/router 0.0.0-experimental.5 → 0.0.0-experimental.50
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.
- package/AGENTS.md +9 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1606 -0
- package/dist/vite/index.js +4567 -769
- package/package.json +77 -58
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +85 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +334 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +89 -30
- package/skills/loader/SKILL.md +388 -38
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +204 -1
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +85 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +226 -14
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +318 -89
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +282 -557
- package/src/browser/navigation-client.ts +157 -71
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +303 -310
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +144 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +193 -73
- package/src/browser/react/NavigationProvider.tsx +160 -13
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +24 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +32 -79
- package/src/browser/react/use-href.tsx +2 -2
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +188 -55
- package/src/browser/scroll-restoration.ts +117 -44
- package/src/browser/segment-reconciler.ts +221 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +504 -599
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +118 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +479 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +167 -309
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +106 -126
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +108 -2
- package/src/handle.ts +15 -29
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +153 -19
- package/src/index.ts +211 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -147
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +959 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -1428
- package/src/route-map-builder.ts +217 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +59 -8
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +374 -81
- package/src/router/intercept-resolution.ts +397 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +215 -122
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +154 -35
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +440 -10
- package/src/router/match-middleware/cache-store.ts +98 -26
- package/src/router/match-middleware/intercept-resolution.ts +57 -17
- package/src/router/match-middleware/segment-resolution.ts +27 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +55 -33
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +327 -369
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +677 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1296 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +77 -3
- package/src/router.ts +665 -4182
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +764 -754
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +38 -11
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +172 -21
- package/src/server/context.ts +266 -58
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +439 -73
- package/src/server.ts +35 -128
- package/src/ssr/index.tsx +101 -31
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +773 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +109 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -802
- package/src/use-loader.tsx +85 -77
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -782
- package/src/vite/plugin-types.ts +48 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +27 -16
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/href.ts +0 -255
- package/src/server/route-manifest-cache.ts +0 -173
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- package/src/warmup/connection-warmup.tsx +0 -94
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/browser/shallow.ts
CHANGED
|
@@ -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 (
|
|
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
|
}
|
package/src/browser/types.ts
CHANGED
|
@@ -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.
|
|
@@ -65,6 +72,10 @@ export interface RscMetadata {
|
|
|
65
72
|
initialTheme?: Theme;
|
|
66
73
|
/** Whether connection warmup is enabled */
|
|
67
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>;
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
/**
|
|
@@ -115,7 +126,7 @@ export interface NavigationState {
|
|
|
115
126
|
/** Whether RSC data is currently streaming (initial load or navigation) */
|
|
116
127
|
isStreaming: boolean;
|
|
117
128
|
|
|
118
|
-
/** Current location
|
|
129
|
+
/** Current location */
|
|
119
130
|
location: NavigationLocation;
|
|
120
131
|
|
|
121
132
|
/** URL being navigated to (null when idle) */
|
|
@@ -172,7 +183,7 @@ export type ActionStateListener = (state: TrackedActionState) => void;
|
|
|
172
183
|
|
|
173
184
|
/**
|
|
174
185
|
* Cache interface for storing segments
|
|
175
|
-
* Compatible with
|
|
186
|
+
* Compatible with Map
|
|
176
187
|
*
|
|
177
188
|
* @internal This type is an implementation detail and may change without notice.
|
|
178
189
|
*/
|
|
@@ -204,14 +215,25 @@ export interface SegmentState {
|
|
|
204
215
|
export interface NavigationUpdate {
|
|
205
216
|
root: ReactNode | Promise<ReactNode>;
|
|
206
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
|
+
};
|
|
207
227
|
}
|
|
208
228
|
|
|
209
229
|
/**
|
|
210
230
|
* State value for navigate/Link
|
|
211
231
|
* - LocationStateEntry[]: Type-safe state entries (recommended)
|
|
212
|
-
* - unknown:
|
|
232
|
+
* - unknown: Plain state format (object or getter function)
|
|
213
233
|
*/
|
|
214
|
-
export type HistoryState =
|
|
234
|
+
export type HistoryState =
|
|
235
|
+
| import("./react/location-state-shared.js").LocationStateEntry[]
|
|
236
|
+
| unknown;
|
|
215
237
|
|
|
216
238
|
/**
|
|
217
239
|
* Options for navigation operations
|
|
@@ -219,6 +241,25 @@ export type HistoryState = import("./react/location-state-shared.js").LocationSt
|
|
|
219
241
|
export interface NavigateOptions {
|
|
220
242
|
replace?: boolean;
|
|
221
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;
|
|
222
263
|
/**
|
|
223
264
|
* State to pass to history.pushState/replaceState
|
|
224
265
|
* Accessible via useLocationState() hook.
|
|
@@ -226,19 +267,67 @@ export interface NavigateOptions {
|
|
|
226
267
|
* @example
|
|
227
268
|
* ```tsx
|
|
228
269
|
* // Type-safe state (recommended)
|
|
229
|
-
* const ProductState = createLocationState<{ name: string }>(
|
|
270
|
+
* const ProductState = createLocationState<{ name: string }>();
|
|
230
271
|
* navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
|
|
231
272
|
*
|
|
273
|
+
* // Type-safe just-in-time state (getter called at navigation time)
|
|
274
|
+
* navigate("/product/123", {
|
|
275
|
+
* state: [ProductState(() => ({ name: computeName() }))],
|
|
276
|
+
* });
|
|
277
|
+
*
|
|
232
278
|
* // Multiple states
|
|
233
279
|
* navigate("/checkout", { state: [ProductState(p), CartState(c)] });
|
|
234
280
|
*
|
|
235
|
-
* //
|
|
281
|
+
* // Plain static state
|
|
236
282
|
* navigate("/product", { state: { from: "list" } });
|
|
283
|
+
*
|
|
284
|
+
* // Plain just-in-time state
|
|
285
|
+
* navigate("/product", { state: () => ({ from: window.location.pathname }) });
|
|
237
286
|
* ```
|
|
238
287
|
*/
|
|
239
288
|
state?: HistoryState;
|
|
240
289
|
}
|
|
241
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
|
+
|
|
242
331
|
// ============================================================================
|
|
243
332
|
// RSC Browser Dependencies
|
|
244
333
|
// ============================================================================
|
|
@@ -252,15 +341,15 @@ export interface NavigateOptions {
|
|
|
252
341
|
export interface RscBrowserDependencies {
|
|
253
342
|
createFromFetch: <T>(
|
|
254
343
|
response: Promise<Response>,
|
|
255
|
-
options?: { temporaryReferences?: any }
|
|
344
|
+
options?: { temporaryReferences?: any },
|
|
256
345
|
) => Promise<T>;
|
|
257
346
|
createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
|
|
258
347
|
encodeReply: (
|
|
259
348
|
args: any[],
|
|
260
|
-
options?: { temporaryReferences?: any }
|
|
349
|
+
options?: { temporaryReferences?: any },
|
|
261
350
|
) => Promise<FormData | string>;
|
|
262
351
|
setServerCallback: (
|
|
263
|
-
callback: (id: string, args: any[]) => Promise<any
|
|
352
|
+
callback: (id: string, args: any[]) => Promise<any>,
|
|
264
353
|
) => void;
|
|
265
354
|
createTemporaryReferenceSet: () => any;
|
|
266
355
|
}
|
|
@@ -312,11 +401,13 @@ export interface NavigationStore {
|
|
|
312
401
|
cacheSegmentsForHistory(
|
|
313
402
|
historyKey: string,
|
|
314
403
|
segments: ResolvedSegment[],
|
|
315
|
-
handleData?: HandleData
|
|
404
|
+
handleData?: HandleData,
|
|
316
405
|
): void;
|
|
317
406
|
getCachedSegments(
|
|
318
|
-
historyKey: string
|
|
319
|
-
):
|
|
407
|
+
historyKey: string,
|
|
408
|
+
):
|
|
409
|
+
| { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData }
|
|
410
|
+
| undefined;
|
|
320
411
|
hasHistoryCache(historyKey: string): boolean;
|
|
321
412
|
updateCacheHandleData(historyKey: string, handleData: HandleData): void;
|
|
322
413
|
markCacheAsStale(): void;
|
|
@@ -340,39 +431,10 @@ export interface NavigationStore {
|
|
|
340
431
|
setActionState(actionId: string, state: Partial<TrackedActionState>): void;
|
|
341
432
|
subscribeToAction(
|
|
342
433
|
actionId: string,
|
|
343
|
-
listener: ActionStateListener
|
|
434
|
+
listener: ActionStateListener,
|
|
344
435
|
): () => void;
|
|
345
436
|
}
|
|
346
437
|
|
|
347
|
-
// ============================================================================
|
|
348
|
-
// Request Controller Types
|
|
349
|
-
// ============================================================================
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Disposable abort controller with automatic cleanup
|
|
353
|
-
*/
|
|
354
|
-
export interface DisposableAbortController extends Disposable {
|
|
355
|
-
controller: AbortController;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Request controller for managing concurrent requests
|
|
360
|
-
*
|
|
361
|
-
* Separates navigation requests (aborted on new navigation) from
|
|
362
|
-
* action requests (complete independently of navigation).
|
|
363
|
-
*/
|
|
364
|
-
export interface RequestController {
|
|
365
|
-
create(): AbortController;
|
|
366
|
-
createDisposable(): DisposableAbortController;
|
|
367
|
-
/** Create a disposable controller for actions (not aborted by navigation) */
|
|
368
|
-
createActionDisposable(): DisposableAbortController;
|
|
369
|
-
/** Abort all navigation requests (not actions) */
|
|
370
|
-
abortAll(): void;
|
|
371
|
-
/** Abort all action requests (used for error handling) */
|
|
372
|
-
abortAllActions(): void;
|
|
373
|
-
remove(controller: AbortController): void;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
438
|
// ============================================================================
|
|
377
439
|
// Navigation Client Types
|
|
378
440
|
// ============================================================================
|
|
@@ -390,6 +452,8 @@ export interface FetchPartialOptions {
|
|
|
390
452
|
interceptSourceUrl?: string;
|
|
391
453
|
/** RSC version for cache invalidation detection */
|
|
392
454
|
version?: string;
|
|
455
|
+
/** If true, this is an HMR refetch - server should invalidate manifest cache */
|
|
456
|
+
hmr?: boolean;
|
|
393
457
|
}
|
|
394
458
|
|
|
395
459
|
/**
|
|
@@ -428,7 +492,6 @@ export interface LinkInterceptorOptions {
|
|
|
428
492
|
*/
|
|
429
493
|
export interface ServerActionBridge {
|
|
430
494
|
register(): void;
|
|
431
|
-
unregister(): void;
|
|
432
495
|
}
|
|
433
496
|
|
|
434
497
|
/**
|
|
@@ -441,7 +504,7 @@ export interface ServerActionBridgeConfig {
|
|
|
441
504
|
onUpdate: UpdateSubscriber;
|
|
442
505
|
renderSegments: (
|
|
443
506
|
segments: ResolvedSegment[],
|
|
444
|
-
options?: RenderSegmentsOptions
|
|
507
|
+
options?: RenderSegmentsOptions,
|
|
445
508
|
) => Promise<ReactNode> | ReactNode;
|
|
446
509
|
}
|
|
447
510
|
|
|
@@ -468,9 +531,17 @@ export interface NavigationBridgeConfig {
|
|
|
468
531
|
onUpdate: UpdateSubscriber;
|
|
469
532
|
renderSegments: (
|
|
470
533
|
segments: ResolvedSegment[],
|
|
471
|
-
options?: RenderSegmentsOptions
|
|
534
|
+
options?: RenderSegmentsOptions,
|
|
472
535
|
) => Promise<ReactNode> | ReactNode;
|
|
473
536
|
}
|
|
474
537
|
|
|
475
538
|
// Re-export ResolvedSegment for convenience
|
|
476
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
|
+
}
|