@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.81
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 +942 -4
- package/dist/bin/rango.js +1689 -0
- package/dist/vite/index.js +5091 -941
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +61 -52
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -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/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +340 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +151 -8
- package/skills/layout/SKILL.md +122 -3
- package/skills/links/SKILL.md +92 -31
- package/skills/loader/SKILL.md +404 -44
- package/skills/middleware/SKILL.md +205 -37
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +765 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +263 -1
- package/skills/prerender/SKILL.md +685 -0
- package/skills/rango/SKILL.md +87 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +281 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +328 -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/app-version.ts +14 -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 +317 -560
- package/src/browser/navigation-client.ts +206 -68
- package/src/browser/navigation-store.ts +73 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +343 -316
- package/src/browser/prefetch/cache.ts +216 -0
- package/src/browser/prefetch/fetch.ts +206 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +160 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +253 -74
- package/src/browser/react/NavigationProvider.tsx +91 -11
- package/src/browser/react/context.ts +11 -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 +6 -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 +30 -126
- 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 +44 -65
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +76 -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 +214 -58
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +141 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +39 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +291 -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 +418 -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 +618 -0
- package/src/build/route-types/scan-filter.ts +85 -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 +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +135 -301
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +108 -2
- package/src/handle.ts +55 -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 +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +155 -19
- package/src/index.ts +251 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -157
- 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 +186 -0
- package/src/prerender.ts +524 -0
- package/src/reverse.ts +354 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1121 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +478 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +149 -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 +77 -8
- package/src/router/content-negotiation.ts +215 -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 +438 -86
- package/src/router/intercept-resolution.ts +402 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +356 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +163 -35
- package/src/router/match-api.ts +555 -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 +460 -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 +80 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +135 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +220 -0
- package/src/router/middleware.ts +324 -369
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +748 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1379 -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 +78 -3
- package/src/router.ts +740 -4252
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +907 -797
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +393 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +246 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +358 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +46 -11
- package/src/search-params.ts +230 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +134 -36
- package/src/server/context.ts +341 -61
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +607 -81
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +103 -30
- package/src/static-handler.ts +126 -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 +791 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +210 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +207 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +372 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +116 -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 +161 -81
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +348 -0
- package/src/vite/discovery/prerender-collection.ts +439 -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 +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -1133
- package/src/vite/plugin-types.ts +103 -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/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -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 +786 -0
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -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} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +462 -0
- package/src/vite/router-discovery.ts +977 -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 +221 -0
- package/src/vite/utils/shared-utils.ts +170 -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/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;
|
|
@@ -32,10 +32,15 @@ export type HandleData = Record<string, Record<string, unknown[]>>;
|
|
|
32
32
|
export interface RscMetadata {
|
|
33
33
|
pathname: string;
|
|
34
34
|
segments: ResolvedSegment[];
|
|
35
|
+
/** Router instance ID. When this changes between navigations, the client
|
|
36
|
+
* forces a full tree replacement (app switch via host router). */
|
|
37
|
+
routerId?: string;
|
|
35
38
|
isPartial?: boolean;
|
|
36
39
|
isError?: boolean;
|
|
37
40
|
matched?: string[];
|
|
38
41
|
diff?: string[];
|
|
42
|
+
/** Merged route params from the matched route */
|
|
43
|
+
params?: Record<string, string>;
|
|
39
44
|
/**
|
|
40
45
|
* State of named slots for this route match
|
|
41
46
|
* Key is slot name (e.g., "@modal"), value is slot state
|
|
@@ -53,6 +58,11 @@ export interface RscMetadata {
|
|
|
53
58
|
* Used to detect version mismatches after HMR/deployment.
|
|
54
59
|
*/
|
|
55
60
|
version?: string;
|
|
61
|
+
/**
|
|
62
|
+
* TTL in milliseconds for the client-side in-memory prefetch cache.
|
|
63
|
+
* Sent on initial render so the browser can configure its cache duration.
|
|
64
|
+
*/
|
|
65
|
+
prefetchCacheTTL?: number;
|
|
56
66
|
/**
|
|
57
67
|
* Theme configuration from router.
|
|
58
68
|
* Included when theme is enabled in router config.
|
|
@@ -63,8 +73,14 @@ export interface RscMetadata {
|
|
|
63
73
|
* Included when theme is enabled in router config.
|
|
64
74
|
*/
|
|
65
75
|
initialTheme?: Theme;
|
|
76
|
+
/** URL prefix for all routes (from createRouter({ basename })). */
|
|
77
|
+
basename?: string;
|
|
66
78
|
/** Whether connection warmup is enabled */
|
|
67
79
|
warmupEnabled?: boolean;
|
|
80
|
+
/** Server-side redirect with optional state (for partial requests) */
|
|
81
|
+
redirect?: { url: string };
|
|
82
|
+
/** Server-set location state to include in history.pushState */
|
|
83
|
+
locationState?: Record<string, unknown>;
|
|
68
84
|
}
|
|
69
85
|
|
|
70
86
|
/**
|
|
@@ -115,7 +131,7 @@ export interface NavigationState {
|
|
|
115
131
|
/** Whether RSC data is currently streaming (initial load or navigation) */
|
|
116
132
|
isStreaming: boolean;
|
|
117
133
|
|
|
118
|
-
/** Current location
|
|
134
|
+
/** Current location */
|
|
119
135
|
location: NavigationLocation;
|
|
120
136
|
|
|
121
137
|
/** URL being navigated to (null when idle) */
|
|
@@ -172,7 +188,7 @@ export type ActionStateListener = (state: TrackedActionState) => void;
|
|
|
172
188
|
|
|
173
189
|
/**
|
|
174
190
|
* Cache interface for storing segments
|
|
175
|
-
* Compatible with
|
|
191
|
+
* Compatible with Map
|
|
176
192
|
*
|
|
177
193
|
* @internal This type is an implementation detail and may change without notice.
|
|
178
194
|
*/
|
|
@@ -204,14 +220,25 @@ export interface SegmentState {
|
|
|
204
220
|
export interface NavigationUpdate {
|
|
205
221
|
root: ReactNode | Promise<ReactNode>;
|
|
206
222
|
metadata: RscMetadata;
|
|
223
|
+
/** Scroll behavior to apply after React commits this update */
|
|
224
|
+
scroll?: {
|
|
225
|
+
/** For back/forward: restore saved position */
|
|
226
|
+
restore?: boolean;
|
|
227
|
+
/** Set to false to disable scrolling entirely */
|
|
228
|
+
enabled?: boolean;
|
|
229
|
+
/** Function to check if streaming is in progress */
|
|
230
|
+
isStreaming?: () => boolean;
|
|
231
|
+
};
|
|
207
232
|
}
|
|
208
233
|
|
|
209
234
|
/**
|
|
210
235
|
* State value for navigate/Link
|
|
211
236
|
* - LocationStateEntry[]: Type-safe state entries (recommended)
|
|
212
|
-
* - unknown:
|
|
237
|
+
* - unknown: Plain state format (object or getter function)
|
|
213
238
|
*/
|
|
214
|
-
export type HistoryState =
|
|
239
|
+
export type HistoryState =
|
|
240
|
+
| import("./react/location-state-shared.js").LocationStateEntry[]
|
|
241
|
+
| unknown;
|
|
215
242
|
|
|
216
243
|
/**
|
|
217
244
|
* Options for navigation operations
|
|
@@ -219,6 +246,25 @@ export type HistoryState = import("./react/location-state-shared.js").LocationSt
|
|
|
219
246
|
export interface NavigateOptions {
|
|
220
247
|
replace?: boolean;
|
|
221
248
|
scroll?: boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Whether to revalidate server data on navigation.
|
|
251
|
+
* Set to `false` to skip the RSC server fetch and only update the URL.
|
|
252
|
+
*
|
|
253
|
+
* Only takes effect when the pathname stays the same (search param / hash changes).
|
|
254
|
+
* If the pathname changes, this option is ignored and a full navigation occurs.
|
|
255
|
+
*
|
|
256
|
+
* All location-aware hooks (`useSearchParams`, `useNavigation`, etc.) still update.
|
|
257
|
+
* Server components do not re-render.
|
|
258
|
+
*
|
|
259
|
+
* @default true
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```tsx
|
|
263
|
+
* router.push("/products?color=blue", { revalidate: false });
|
|
264
|
+
* router.replace("/products?page=3", { revalidate: false });
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
revalidate?: boolean;
|
|
222
268
|
/**
|
|
223
269
|
* State to pass to history.pushState/replaceState
|
|
224
270
|
* Accessible via useLocationState() hook.
|
|
@@ -226,19 +272,67 @@ export interface NavigateOptions {
|
|
|
226
272
|
* @example
|
|
227
273
|
* ```tsx
|
|
228
274
|
* // Type-safe state (recommended)
|
|
229
|
-
* const ProductState = createLocationState<{ name: string }>(
|
|
275
|
+
* const ProductState = createLocationState<{ name: string }>();
|
|
230
276
|
* navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
|
|
231
277
|
*
|
|
278
|
+
* // Type-safe just-in-time state (getter called at navigation time)
|
|
279
|
+
* navigate("/product/123", {
|
|
280
|
+
* state: [ProductState(() => ({ name: computeName() }))],
|
|
281
|
+
* });
|
|
282
|
+
*
|
|
232
283
|
* // Multiple states
|
|
233
284
|
* navigate("/checkout", { state: [ProductState(p), CartState(c)] });
|
|
234
285
|
*
|
|
235
|
-
* //
|
|
286
|
+
* // Plain static state
|
|
236
287
|
* navigate("/product", { state: { from: "list" } });
|
|
288
|
+
*
|
|
289
|
+
* // Plain just-in-time state
|
|
290
|
+
* navigate("/product", { state: () => ({ from: window.location.pathname }) });
|
|
237
291
|
* ```
|
|
238
292
|
*/
|
|
239
293
|
state?: HistoryState;
|
|
240
294
|
}
|
|
241
295
|
|
|
296
|
+
/** @internal Extended options used only within the navigation bridge */
|
|
297
|
+
export interface NavigateOptionsInternal extends NavigateOptions {
|
|
298
|
+
/** Skip segment cache (used by redirect-with-state to force re-render) */
|
|
299
|
+
_skipCache?: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Options for useRouter push/replace methods.
|
|
304
|
+
* Same as NavigateOptions but without `replace` (implicit in push vs replace).
|
|
305
|
+
*/
|
|
306
|
+
export type RouterNavigateOptions = Omit<NavigateOptions, "replace">;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Router instance returned by useRouter hook.
|
|
310
|
+
* Provides stable action methods that never cause re-renders.
|
|
311
|
+
*/
|
|
312
|
+
export interface RouterInstance {
|
|
313
|
+
/** Navigate to a URL, pushing a new entry to the history stack */
|
|
314
|
+
push(url: string, options?: RouterNavigateOptions): Promise<void>;
|
|
315
|
+
/** Navigate to a URL, replacing the current history entry */
|
|
316
|
+
replace(url: string, options?: RouterNavigateOptions): Promise<void>;
|
|
317
|
+
/** Refresh the current route (re-fetch server data, preserve client state) */
|
|
318
|
+
refresh(): Promise<void>;
|
|
319
|
+
/** Prefetch a URL for faster client-side transition */
|
|
320
|
+
prefetch(url: string): void;
|
|
321
|
+
/** Go back in browser history */
|
|
322
|
+
back(): void;
|
|
323
|
+
/** Go forward in browser history */
|
|
324
|
+
forward(): void;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* URLSearchParams without mutation methods.
|
|
329
|
+
* Matches Next.js convention for useSearchParams return type.
|
|
330
|
+
*/
|
|
331
|
+
export type ReadonlyURLSearchParams = Omit<
|
|
332
|
+
URLSearchParams,
|
|
333
|
+
"append" | "delete" | "set" | "sort"
|
|
334
|
+
>;
|
|
335
|
+
|
|
242
336
|
// ============================================================================
|
|
243
337
|
// RSC Browser Dependencies
|
|
244
338
|
// ============================================================================
|
|
@@ -252,15 +346,21 @@ export interface NavigateOptions {
|
|
|
252
346
|
export interface RscBrowserDependencies {
|
|
253
347
|
createFromFetch: <T>(
|
|
254
348
|
response: Promise<Response>,
|
|
255
|
-
options?: {
|
|
349
|
+
options?: {
|
|
350
|
+
temporaryReferences?: any;
|
|
351
|
+
findSourceMapURL?: (
|
|
352
|
+
filename: string,
|
|
353
|
+
environmentName: string,
|
|
354
|
+
) => string | null;
|
|
355
|
+
},
|
|
256
356
|
) => Promise<T>;
|
|
257
357
|
createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
|
|
258
358
|
encodeReply: (
|
|
259
359
|
args: any[],
|
|
260
|
-
options?: { temporaryReferences?: any }
|
|
360
|
+
options?: { temporaryReferences?: any },
|
|
261
361
|
) => Promise<FormData | string>;
|
|
262
362
|
setServerCallback: (
|
|
263
|
-
callback: (id: string, args: any[]) => Promise<any
|
|
363
|
+
callback: (id: string, args: any[]) => Promise<any>,
|
|
264
364
|
) => void;
|
|
265
365
|
createTemporaryReferenceSet: () => any;
|
|
266
366
|
}
|
|
@@ -312,11 +412,16 @@ export interface NavigationStore {
|
|
|
312
412
|
cacheSegmentsForHistory(
|
|
313
413
|
historyKey: string,
|
|
314
414
|
segments: ResolvedSegment[],
|
|
315
|
-
handleData?: HandleData
|
|
415
|
+
handleData?: HandleData,
|
|
316
416
|
): void;
|
|
317
|
-
getCachedSegments(
|
|
318
|
-
|
|
319
|
-
|
|
417
|
+
getCachedSegments(historyKey: string):
|
|
418
|
+
| {
|
|
419
|
+
segments: ResolvedSegment[];
|
|
420
|
+
stale: boolean;
|
|
421
|
+
handleData?: HandleData;
|
|
422
|
+
routerId?: string;
|
|
423
|
+
}
|
|
424
|
+
| undefined;
|
|
320
425
|
hasHistoryCache(historyKey: string): boolean;
|
|
321
426
|
updateCacheHandleData(historyKey: string, handleData: HandleData): void;
|
|
322
427
|
markCacheAsStale(): void;
|
|
@@ -331,6 +436,10 @@ export interface NavigationStore {
|
|
|
331
436
|
getInterceptSourceUrl(): string | null;
|
|
332
437
|
setInterceptSourceUrl(url: string | null): void;
|
|
333
438
|
|
|
439
|
+
// Router identity tracking (for cross-app navigation detection)
|
|
440
|
+
getRouterId?(): string | undefined;
|
|
441
|
+
setRouterId?(id: string): void;
|
|
442
|
+
|
|
334
443
|
// UI update notifications
|
|
335
444
|
onUpdate(callback: UpdateSubscriber): () => void;
|
|
336
445
|
emitUpdate(update: NavigationUpdate): void;
|
|
@@ -340,39 +449,10 @@ export interface NavigationStore {
|
|
|
340
449
|
setActionState(actionId: string, state: Partial<TrackedActionState>): void;
|
|
341
450
|
subscribeToAction(
|
|
342
451
|
actionId: string,
|
|
343
|
-
listener: ActionStateListener
|
|
452
|
+
listener: ActionStateListener,
|
|
344
453
|
): () => void;
|
|
345
454
|
}
|
|
346
455
|
|
|
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
456
|
// ============================================================================
|
|
377
457
|
// Navigation Client Types
|
|
378
458
|
// ============================================================================
|
|
@@ -390,6 +470,10 @@ export interface FetchPartialOptions {
|
|
|
390
470
|
interceptSourceUrl?: string;
|
|
391
471
|
/** RSC version for cache invalidation detection */
|
|
392
472
|
version?: string;
|
|
473
|
+
/** Current router ID — server detects app switch and returns full response */
|
|
474
|
+
routerId?: string;
|
|
475
|
+
/** If true, this is an HMR refetch - server should invalidate manifest cache */
|
|
476
|
+
hmr?: boolean;
|
|
393
477
|
}
|
|
394
478
|
|
|
395
479
|
/**
|
|
@@ -428,7 +512,6 @@ export interface LinkInterceptorOptions {
|
|
|
428
512
|
*/
|
|
429
513
|
export interface ServerActionBridge {
|
|
430
514
|
register(): void;
|
|
431
|
-
unregister(): void;
|
|
432
515
|
}
|
|
433
516
|
|
|
434
517
|
/**
|
|
@@ -441,7 +524,7 @@ export interface ServerActionBridgeConfig {
|
|
|
441
524
|
onUpdate: UpdateSubscriber;
|
|
442
525
|
renderSegments: (
|
|
443
526
|
segments: ResolvedSegment[],
|
|
444
|
-
options?: RenderSegmentsOptions
|
|
527
|
+
options?: RenderSegmentsOptions,
|
|
445
528
|
) => Promise<ReactNode> | ReactNode;
|
|
446
529
|
}
|
|
447
530
|
|
|
@@ -457,6 +540,8 @@ export interface NavigationBridge {
|
|
|
457
540
|
refresh(): Promise<void>;
|
|
458
541
|
handlePopstate(): Promise<void>;
|
|
459
542
|
registerLinkInterception(): () => void;
|
|
543
|
+
/** Update the RSC version (e.g. after HMR). Clears prefetch cache. */
|
|
544
|
+
updateVersion(newVersion: string): void;
|
|
460
545
|
}
|
|
461
546
|
|
|
462
547
|
/**
|
|
@@ -468,9 +553,17 @@ export interface NavigationBridgeConfig {
|
|
|
468
553
|
onUpdate: UpdateSubscriber;
|
|
469
554
|
renderSegments: (
|
|
470
555
|
segments: ResolvedSegment[],
|
|
471
|
-
options?: RenderSegmentsOptions
|
|
556
|
+
options?: RenderSegmentsOptions,
|
|
472
557
|
) => Promise<ReactNode> | ReactNode;
|
|
473
558
|
}
|
|
474
559
|
|
|
475
560
|
// Re-export ResolvedSegment for convenience
|
|
476
561
|
export type { ResolvedSegment };
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Token for tracking an active stream.
|
|
565
|
+
* Call end() when the stream completes.
|
|
566
|
+
*/
|
|
567
|
+
export interface StreamingToken {
|
|
568
|
+
end(): void;
|
|
569
|
+
}
|
|
@@ -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
|
+
}
|