@rangojs/router 0.0.0-experimental.10 → 0.0.0-experimental.100
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 +1037 -4
- package/dist/bin/rango.js +1619 -157
- package/dist/vite/index.js +5762 -2301
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +71 -63
- package/skills/breadcrumbs/SKILL.md +252 -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 +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +367 -71
- package/skills/host-router/SKILL.md +218 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +176 -8
- package/skills/layout/SKILL.md +124 -3
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +474 -47
- package/skills/middleware/SKILL.md +207 -37
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +15 -11
- package/skills/parallel/SKILL.md +272 -1
- package/skills/prerender/SKILL.md +467 -65
- package/skills/rango/SKILL.md +89 -21
- package/skills/response-routes/SKILL.md +152 -91
- package/skills/route/SKILL.md +305 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/server-actions/SKILL.md +739 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +333 -86
- package/skills/use-cache/SKILL.md +324 -0
- package/skills/view-transitions/SKILL.md +212 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +136 -68
- 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 +374 -561
- package/src/browser/navigation-client.ts +228 -70
- package/src/browser/navigation-store.ts +97 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +376 -315
- package/src/browser/prefetch/cache.ts +314 -0
- package/src/browser/prefetch/fetch.ts +282 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +191 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +152 -0
- package/src/browser/react/Link.tsx +255 -71
- package/src/browser/react/NavigationProvider.tsx +152 -24
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +55 -0
- package/src/browser/react/index.ts +15 -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 -120
- 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 +78 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +99 -0
- package/src/browser/react/use-router.ts +83 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +85 -99
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +246 -64
- 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 +158 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +84 -23
- package/src/build/generate-route-types.ts +39 -828
- package/src/build/index.ts +4 -5
- package/src/build/route-trie.ts +85 -32
- 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 -307
- package/src/cache/cf/cf-cache-store.ts +573 -21
- 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 +6 -1
- package/src/client.tsx +118 -302
- 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 +77 -7
- package/src/handle.ts +55 -10
- 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 +65 -45
- package/src/index.rsc.ts +138 -21
- package/src/index.ts +206 -51
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +25 -143
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +159 -13
- package/src/prerender.ts +397 -29
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +231 -121
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1134 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +483 -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 +155 -0
- package/src/route-definition.ts +1 -1431
- package/src/route-map-builder.ts +162 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +66 -9
- 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 +418 -86
- package/src/router/intercept-resolution.ts +35 -20
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +359 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +98 -32
- package/src/router/match-api.ts +196 -261
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +441 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +415 -86
- package/src/router/match-middleware/cache-store.ts +91 -29
- package/src/router/match-middleware/intercept-resolution.ts +48 -21
- package/src/router/match-middleware/segment-resolution.ts +73 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +154 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +209 -0
- package/src/router/middleware.ts +373 -371
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +292 -52
- 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 +152 -39
- 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 +756 -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 +1407 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1315
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/substitute-pattern-params.ts +56 -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 +111 -39
- package/src/router/types.ts +17 -9
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +642 -2011
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +864 -1114
- package/src/rsc/helpers.ts +181 -19
- 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 +395 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +360 -0
- package/src/rsc/rsc-rendering.ts +256 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +360 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +52 -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 +187 -38
- package/src/server/context.ts +333 -59
- 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 +603 -109
- package/src/server.ts +35 -155
- package/src/ssr/index.tsx +107 -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 +764 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +209 -0
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +167 -0
- package/src/types.ts +1 -1757
- 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 +108 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -1282
- package/src/use-loader.tsx +161 -81
- package/src/vite/debug.ts +184 -0
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +376 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +486 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -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 -2063
- package/src/vite/plugin-types.ts +103 -0
- package/src/vite/plugins/cjs-to-esm.ts +98 -0
- package/src/vite/plugins/client-ref-dedup.ts +131 -0
- package/src/vite/plugins/client-ref-hashing.ts +117 -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} +107 -64
- 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 +127 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +816 -0
- package/src/vite/plugins/performance-tracks.ts +96 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +336 -0
- package/src/vite/plugins/version-injector.ts +109 -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 +497 -0
- package/src/vite/router-discovery.ts +1423 -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/utils/package-resolution.ts +161 -0
- package/src/vite/utils/prerender-utils.ts +222 -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/router.gen.ts +0 -6
- package/src/urls.gen.ts +0 -8
- 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/expose-prerender-handler-id.ts +0 -429
- package/src/vite/package-resolution.ts +0 -125
- /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,21 @@ 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
|
+
/**
|
|
43
|
+
* All segment ids re-resolved on the server, including null-component
|
|
44
|
+
* ones excluded from `segments`/`diff`. Drives client-side handle-bucket
|
|
45
|
+
* cleanup. Superset of `diff`. See MatchResult.resolvedIds.
|
|
46
|
+
*/
|
|
47
|
+
resolvedIds?: string[];
|
|
48
|
+
/** Merged route params from the matched route */
|
|
49
|
+
params?: Record<string, string>;
|
|
39
50
|
/**
|
|
40
51
|
* State of named slots for this route match
|
|
41
52
|
* Key is slot name (e.g., "@modal"), value is slot state
|
|
@@ -53,6 +64,11 @@ export interface RscMetadata {
|
|
|
53
64
|
* Used to detect version mismatches after HMR/deployment.
|
|
54
65
|
*/
|
|
55
66
|
version?: string;
|
|
67
|
+
/**
|
|
68
|
+
* TTL in milliseconds for the client-side in-memory prefetch cache.
|
|
69
|
+
* Sent on initial render so the browser can configure its cache duration.
|
|
70
|
+
*/
|
|
71
|
+
prefetchCacheTTL?: number;
|
|
56
72
|
/**
|
|
57
73
|
* Theme configuration from router.
|
|
58
74
|
* Included when theme is enabled in router config.
|
|
@@ -63,8 +79,14 @@ export interface RscMetadata {
|
|
|
63
79
|
* Included when theme is enabled in router config.
|
|
64
80
|
*/
|
|
65
81
|
initialTheme?: Theme;
|
|
82
|
+
/** URL prefix for all routes (from createRouter({ basename })). */
|
|
83
|
+
basename?: string;
|
|
66
84
|
/** Whether connection warmup is enabled */
|
|
67
85
|
warmupEnabled?: boolean;
|
|
86
|
+
/** Server-side redirect with optional state (for partial requests) */
|
|
87
|
+
redirect?: { url: string };
|
|
88
|
+
/** Server-set location state to include in history.pushState */
|
|
89
|
+
locationState?: Record<string, unknown>;
|
|
68
90
|
}
|
|
69
91
|
|
|
70
92
|
/**
|
|
@@ -115,7 +137,7 @@ export interface NavigationState {
|
|
|
115
137
|
/** Whether RSC data is currently streaming (initial load or navigation) */
|
|
116
138
|
isStreaming: boolean;
|
|
117
139
|
|
|
118
|
-
/** Current location
|
|
140
|
+
/** Current location */
|
|
119
141
|
location: NavigationLocation;
|
|
120
142
|
|
|
121
143
|
/** URL being navigated to (null when idle) */
|
|
@@ -172,7 +194,7 @@ export type ActionStateListener = (state: TrackedActionState) => void;
|
|
|
172
194
|
|
|
173
195
|
/**
|
|
174
196
|
* Cache interface for storing segments
|
|
175
|
-
* Compatible with
|
|
197
|
+
* Compatible with Map
|
|
176
198
|
*
|
|
177
199
|
* @internal This type is an implementation detail and may change without notice.
|
|
178
200
|
*/
|
|
@@ -204,14 +226,25 @@ export interface SegmentState {
|
|
|
204
226
|
export interface NavigationUpdate {
|
|
205
227
|
root: ReactNode | Promise<ReactNode>;
|
|
206
228
|
metadata: RscMetadata;
|
|
229
|
+
/** Scroll behavior to apply after React commits this update */
|
|
230
|
+
scroll?: {
|
|
231
|
+
/** For back/forward: restore saved position */
|
|
232
|
+
restore?: boolean;
|
|
233
|
+
/** Set to false to disable scrolling entirely */
|
|
234
|
+
enabled?: boolean;
|
|
235
|
+
/** Function to check if streaming is in progress */
|
|
236
|
+
isStreaming?: () => boolean;
|
|
237
|
+
};
|
|
207
238
|
}
|
|
208
239
|
|
|
209
240
|
/**
|
|
210
241
|
* State value for navigate/Link
|
|
211
242
|
* - LocationStateEntry[]: Type-safe state entries (recommended)
|
|
212
|
-
* - unknown:
|
|
243
|
+
* - unknown: Plain state format (object or getter function)
|
|
213
244
|
*/
|
|
214
|
-
export type HistoryState =
|
|
245
|
+
export type HistoryState =
|
|
246
|
+
| import("./react/location-state-shared.js").LocationStateEntry[]
|
|
247
|
+
| unknown;
|
|
215
248
|
|
|
216
249
|
/**
|
|
217
250
|
* Options for navigation operations
|
|
@@ -219,6 +252,25 @@ export type HistoryState = import("./react/location-state-shared.js").LocationSt
|
|
|
219
252
|
export interface NavigateOptions {
|
|
220
253
|
replace?: boolean;
|
|
221
254
|
scroll?: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Whether to revalidate server data on navigation.
|
|
257
|
+
* Set to `false` to skip the RSC server fetch and only update the URL.
|
|
258
|
+
*
|
|
259
|
+
* Only takes effect when the pathname stays the same (search param / hash changes).
|
|
260
|
+
* If the pathname changes, this option is ignored and a full navigation occurs.
|
|
261
|
+
*
|
|
262
|
+
* All location-aware hooks (`useSearchParams`, `useNavigation`, etc.) still update.
|
|
263
|
+
* Server components do not re-render.
|
|
264
|
+
*
|
|
265
|
+
* @default true
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```tsx
|
|
269
|
+
* router.push("/products?color=blue", { revalidate: false });
|
|
270
|
+
* router.replace("/products?page=3", { revalidate: false });
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
revalidate?: boolean;
|
|
222
274
|
/**
|
|
223
275
|
* State to pass to history.pushState/replaceState
|
|
224
276
|
* Accessible via useLocationState() hook.
|
|
@@ -226,19 +278,67 @@ export interface NavigateOptions {
|
|
|
226
278
|
* @example
|
|
227
279
|
* ```tsx
|
|
228
280
|
* // Type-safe state (recommended)
|
|
229
|
-
* const ProductState = createLocationState<{ name: string }>(
|
|
281
|
+
* const ProductState = createLocationState<{ name: string }>();
|
|
230
282
|
* navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
|
|
231
283
|
*
|
|
284
|
+
* // Type-safe just-in-time state (getter called at navigation time)
|
|
285
|
+
* navigate("/product/123", {
|
|
286
|
+
* state: [ProductState(() => ({ name: computeName() }))],
|
|
287
|
+
* });
|
|
288
|
+
*
|
|
232
289
|
* // Multiple states
|
|
233
290
|
* navigate("/checkout", { state: [ProductState(p), CartState(c)] });
|
|
234
291
|
*
|
|
235
|
-
* //
|
|
292
|
+
* // Plain static state
|
|
236
293
|
* navigate("/product", { state: { from: "list" } });
|
|
294
|
+
*
|
|
295
|
+
* // Plain just-in-time state
|
|
296
|
+
* navigate("/product", { state: () => ({ from: window.location.pathname }) });
|
|
237
297
|
* ```
|
|
238
298
|
*/
|
|
239
299
|
state?: HistoryState;
|
|
240
300
|
}
|
|
241
301
|
|
|
302
|
+
/** @internal Extended options used only within the navigation bridge */
|
|
303
|
+
export interface NavigateOptionsInternal extends NavigateOptions {
|
|
304
|
+
/** Skip segment cache (used by redirect-with-state to force re-render) */
|
|
305
|
+
_skipCache?: boolean;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Options for useRouter push/replace methods.
|
|
310
|
+
* Same as NavigateOptions but without `replace` (implicit in push vs replace).
|
|
311
|
+
*/
|
|
312
|
+
export type RouterNavigateOptions = Omit<NavigateOptions, "replace">;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Router instance returned by useRouter hook.
|
|
316
|
+
* Provides stable action methods that never cause re-renders.
|
|
317
|
+
*/
|
|
318
|
+
export interface RouterInstance {
|
|
319
|
+
/** Navigate to a URL, pushing a new entry to the history stack */
|
|
320
|
+
push(url: string, options?: RouterNavigateOptions): Promise<void>;
|
|
321
|
+
/** Navigate to a URL, replacing the current history entry */
|
|
322
|
+
replace(url: string, options?: RouterNavigateOptions): Promise<void>;
|
|
323
|
+
/** Refresh the current route (re-fetch server data, preserve client state) */
|
|
324
|
+
refresh(): Promise<void>;
|
|
325
|
+
/** Prefetch a URL for faster client-side transition */
|
|
326
|
+
prefetch(url: string): void;
|
|
327
|
+
/** Go back in browser history */
|
|
328
|
+
back(): void;
|
|
329
|
+
/** Go forward in browser history */
|
|
330
|
+
forward(): void;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* URLSearchParams without mutation methods.
|
|
335
|
+
* Matches Next.js convention for useSearchParams return type.
|
|
336
|
+
*/
|
|
337
|
+
export type ReadonlyURLSearchParams = Omit<
|
|
338
|
+
URLSearchParams,
|
|
339
|
+
"append" | "delete" | "set" | "sort"
|
|
340
|
+
>;
|
|
341
|
+
|
|
242
342
|
// ============================================================================
|
|
243
343
|
// RSC Browser Dependencies
|
|
244
344
|
// ============================================================================
|
|
@@ -252,15 +352,21 @@ export interface NavigateOptions {
|
|
|
252
352
|
export interface RscBrowserDependencies {
|
|
253
353
|
createFromFetch: <T>(
|
|
254
354
|
response: Promise<Response>,
|
|
255
|
-
options?: {
|
|
355
|
+
options?: {
|
|
356
|
+
temporaryReferences?: any;
|
|
357
|
+
findSourceMapURL?: (
|
|
358
|
+
filename: string,
|
|
359
|
+
environmentName: string,
|
|
360
|
+
) => string | null;
|
|
361
|
+
},
|
|
256
362
|
) => Promise<T>;
|
|
257
363
|
createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
|
|
258
364
|
encodeReply: (
|
|
259
365
|
args: any[],
|
|
260
|
-
options?: { temporaryReferences?: any }
|
|
366
|
+
options?: { temporaryReferences?: any },
|
|
261
367
|
) => Promise<FormData | string>;
|
|
262
368
|
setServerCallback: (
|
|
263
|
-
callback: (id: string, args: any[]) => Promise<any
|
|
369
|
+
callback: (id: string, args: any[]) => Promise<any>,
|
|
264
370
|
) => void;
|
|
265
371
|
createTemporaryReferenceSet: () => any;
|
|
266
372
|
}
|
|
@@ -312,16 +418,27 @@ export interface NavigationStore {
|
|
|
312
418
|
cacheSegmentsForHistory(
|
|
313
419
|
historyKey: string,
|
|
314
420
|
segments: ResolvedSegment[],
|
|
315
|
-
handleData?: HandleData
|
|
421
|
+
handleData?: HandleData,
|
|
316
422
|
): void;
|
|
317
|
-
getCachedSegments(
|
|
318
|
-
|
|
319
|
-
|
|
423
|
+
getCachedSegments(historyKey: string):
|
|
424
|
+
| {
|
|
425
|
+
segments: ResolvedSegment[];
|
|
426
|
+
stale: boolean;
|
|
427
|
+
handleData?: HandleData;
|
|
428
|
+
routerId?: string;
|
|
429
|
+
}
|
|
430
|
+
| undefined;
|
|
320
431
|
hasHistoryCache(historyKey: string): boolean;
|
|
321
432
|
updateCacheHandleData(historyKey: string, handleData: HandleData): void;
|
|
322
433
|
markCacheAsStale(): void;
|
|
323
434
|
markCacheAsStaleAndBroadcast(): void;
|
|
324
435
|
clearHistoryCache(): void;
|
|
436
|
+
/**
|
|
437
|
+
* Clear this tab's nav + prefetch caches without broadcasting or rotating
|
|
438
|
+
* shared state. Intended for app-switch transitions that affect only this
|
|
439
|
+
* tab's session.
|
|
440
|
+
*/
|
|
441
|
+
clearHistoryCacheLocal(): void;
|
|
325
442
|
broadcastCacheInvalidation(): void;
|
|
326
443
|
|
|
327
444
|
// Cross-tab refresh callback (set by navigation bridge)
|
|
@@ -331,6 +448,10 @@ export interface NavigationStore {
|
|
|
331
448
|
getInterceptSourceUrl(): string | null;
|
|
332
449
|
setInterceptSourceUrl(url: string | null): void;
|
|
333
450
|
|
|
451
|
+
// Router identity tracking (for cross-app navigation detection)
|
|
452
|
+
getRouterId?(): string | undefined;
|
|
453
|
+
setRouterId?(id: string): void;
|
|
454
|
+
|
|
334
455
|
// UI update notifications
|
|
335
456
|
onUpdate(callback: UpdateSubscriber): () => void;
|
|
336
457
|
emitUpdate(update: NavigationUpdate): void;
|
|
@@ -340,39 +461,10 @@ export interface NavigationStore {
|
|
|
340
461
|
setActionState(actionId: string, state: Partial<TrackedActionState>): void;
|
|
341
462
|
subscribeToAction(
|
|
342
463
|
actionId: string,
|
|
343
|
-
listener: ActionStateListener
|
|
464
|
+
listener: ActionStateListener,
|
|
344
465
|
): () => void;
|
|
345
466
|
}
|
|
346
467
|
|
|
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
468
|
// ============================================================================
|
|
377
469
|
// Navigation Client Types
|
|
378
470
|
// ============================================================================
|
|
@@ -390,6 +482,8 @@ export interface FetchPartialOptions {
|
|
|
390
482
|
interceptSourceUrl?: string;
|
|
391
483
|
/** RSC version for cache invalidation detection */
|
|
392
484
|
version?: string;
|
|
485
|
+
/** Current router ID — server detects app switch and returns full response */
|
|
486
|
+
routerId?: string;
|
|
393
487
|
/** If true, this is an HMR refetch - server should invalidate manifest cache */
|
|
394
488
|
hmr?: boolean;
|
|
395
489
|
}
|
|
@@ -430,7 +524,6 @@ export interface LinkInterceptorOptions {
|
|
|
430
524
|
*/
|
|
431
525
|
export interface ServerActionBridge {
|
|
432
526
|
register(): void;
|
|
433
|
-
unregister(): void;
|
|
434
527
|
}
|
|
435
528
|
|
|
436
529
|
/**
|
|
@@ -443,7 +536,7 @@ export interface ServerActionBridgeConfig {
|
|
|
443
536
|
onUpdate: UpdateSubscriber;
|
|
444
537
|
renderSegments: (
|
|
445
538
|
segments: ResolvedSegment[],
|
|
446
|
-
options?: RenderSegmentsOptions
|
|
539
|
+
options?: RenderSegmentsOptions,
|
|
447
540
|
) => Promise<ReactNode> | ReactNode;
|
|
448
541
|
}
|
|
449
542
|
|
|
@@ -459,6 +552,15 @@ export interface NavigationBridge {
|
|
|
459
552
|
refresh(): Promise<void>;
|
|
460
553
|
handlePopstate(): Promise<void>;
|
|
461
554
|
registerLinkInterception(): () => void;
|
|
555
|
+
/** Update the RSC version (e.g. after HMR). Clears prefetch cache. */
|
|
556
|
+
updateVersion(newVersion: string): void;
|
|
557
|
+
/**
|
|
558
|
+
* Replace the active app-shell snapshot (rootLayout, basename, version)
|
|
559
|
+
* atomically. Used on cross-app navigations when the response's routerId
|
|
560
|
+
* indicates the user entered a different app. Theme, warmup, and prefetch
|
|
561
|
+
* TTL are document-lifetime and not part of the shell.
|
|
562
|
+
*/
|
|
563
|
+
updateAppShell(next: import("./app-shell.js").AppShell): void;
|
|
462
564
|
}
|
|
463
565
|
|
|
464
566
|
/**
|
|
@@ -470,9 +572,17 @@ export interface NavigationBridgeConfig {
|
|
|
470
572
|
onUpdate: UpdateSubscriber;
|
|
471
573
|
renderSegments: (
|
|
472
574
|
segments: ResolvedSegment[],
|
|
473
|
-
options?: RenderSegmentsOptions
|
|
575
|
+
options?: RenderSegmentsOptions,
|
|
474
576
|
) => Promise<ReactNode> | ReactNode;
|
|
475
577
|
}
|
|
476
578
|
|
|
477
579
|
// Re-export ResolvedSegment for convenience
|
|
478
580
|
export type { ResolvedSegment };
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Token for tracking an active stream.
|
|
584
|
+
* Call end() when the stream completes.
|
|
585
|
+
*/
|
|
586
|
+
export interface StreamingToken {
|
|
587
|
+
end(): void;
|
|
588
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -43,14 +43,14 @@ export interface GeneratedManifest {
|
|
|
43
43
|
routeManifest: Record<string, string>;
|
|
44
44
|
/** Route name → trailing slash mode for trie redirect handling */
|
|
45
45
|
routeTrailingSlash?: Record<string, string>;
|
|
46
|
-
/** Route names using
|
|
46
|
+
/** Route names using Prerender (for dev-mode Node.js delegation) */
|
|
47
47
|
prerenderRoutes?: string[];
|
|
48
|
-
/** Route names with
|
|
48
|
+
/** Route names wrapped with Passthrough() (live handler for runtime fallback) */
|
|
49
49
|
passthroughRoutes?: string[];
|
|
50
50
|
/** Route name → response type for non-RSC routes */
|
|
51
51
|
responseTypeRoutes?: Record<string, string>;
|
|
52
|
-
/**
|
|
53
|
-
|
|
52
|
+
/** Route name -> search schema descriptor for typed URL helpers */
|
|
53
|
+
routeSearchSchemas?: Record<string, Record<string, string>>;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
@@ -62,7 +62,7 @@ function buildPrefixTreeNode(
|
|
|
62
62
|
namePrefix: string | undefined,
|
|
63
63
|
patterns: UrlPatterns<any>,
|
|
64
64
|
routeManifest: Record<string, string>,
|
|
65
|
-
routeAncestry: Record<string, string[]>,
|
|
65
|
+
routeAncestry: Record<string, string[]>, // internal: feeds trie building, not exported
|
|
66
66
|
mountIndex: number,
|
|
67
67
|
visited: Set<unknown> = new Set(),
|
|
68
68
|
routeTrailingSlash?: Record<string, string>,
|
|
@@ -70,10 +70,11 @@ function buildPrefixTreeNode(
|
|
|
70
70
|
prerenderDefs?: Record<string, any>,
|
|
71
71
|
passthroughRoutes?: string[],
|
|
72
72
|
responseTypeRoutes?: Record<string, string>,
|
|
73
|
+
routeSearchSchemas?: Record<string, Record<string, string>>,
|
|
73
74
|
): PrefixTreeNode {
|
|
74
75
|
if (visited.has(patterns)) {
|
|
75
76
|
console.warn(
|
|
76
|
-
`[@rangojs/router] Circular include detected at prefix "${urlPrefix}". Skipping
|
|
77
|
+
`[@rangojs/router] Circular include detected at prefix "${urlPrefix}". Skipping.`,
|
|
77
78
|
);
|
|
78
79
|
return {
|
|
79
80
|
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
@@ -89,6 +90,7 @@ function buildPrefixTreeNode(
|
|
|
89
90
|
const patternsMap = new Map<string, string>();
|
|
90
91
|
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
91
92
|
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
93
|
+
const searchSchemasMap = new Map<string, Record<string, string>>();
|
|
92
94
|
const trackedIncludes: TrackedInclude[] = [];
|
|
93
95
|
|
|
94
96
|
RSCRouterContext.run(
|
|
@@ -97,6 +99,7 @@ function buildPrefixTreeNode(
|
|
|
97
99
|
patterns: patternsMap,
|
|
98
100
|
patternsByPrefix,
|
|
99
101
|
trailingSlash: trailingSlashMap,
|
|
102
|
+
searchSchemas: searchSchemasMap,
|
|
100
103
|
namespace: "build",
|
|
101
104
|
parent: null,
|
|
102
105
|
counters: {},
|
|
@@ -114,7 +117,7 @@ function buildPrefixTreeNode(
|
|
|
114
117
|
}
|
|
115
118
|
return patterns.handler() as AllUseItems[];
|
|
116
119
|
});
|
|
117
|
-
}
|
|
120
|
+
},
|
|
118
121
|
);
|
|
119
122
|
|
|
120
123
|
// Collect route names defined in this include (routes have prefixes applied)
|
|
@@ -130,6 +133,11 @@ function buildPrefixTreeNode(
|
|
|
130
133
|
routeTrailingSlash[name] = mode;
|
|
131
134
|
}
|
|
132
135
|
}
|
|
136
|
+
if (routeSearchSchemas) {
|
|
137
|
+
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
138
|
+
routeSearchSchemas[name] = schema;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
133
141
|
|
|
134
142
|
// Capture ancestry from manifest entries' parent chains
|
|
135
143
|
captureAncestry(manifest, routeAncestry);
|
|
@@ -142,7 +150,7 @@ function buildPrefixTreeNode(
|
|
|
142
150
|
if (prerenderDefs && entry.prerenderDef) {
|
|
143
151
|
prerenderDefs[name] = entry.prerenderDef;
|
|
144
152
|
}
|
|
145
|
-
if (passthroughRoutes && entry.
|
|
153
|
+
if (passthroughRoutes && entry.isPassthrough === true) {
|
|
146
154
|
passthroughRoutes.push(name);
|
|
147
155
|
}
|
|
148
156
|
}
|
|
@@ -177,6 +185,7 @@ function buildPrefixTreeNode(
|
|
|
177
185
|
prerenderDefs,
|
|
178
186
|
passthroughRoutes,
|
|
179
187
|
responseTypeRoutes,
|
|
188
|
+
routeSearchSchemas,
|
|
180
189
|
);
|
|
181
190
|
|
|
182
191
|
const existing = children[include.fullPrefix];
|
|
@@ -188,6 +197,11 @@ function buildPrefixTreeNode(
|
|
|
188
197
|
}
|
|
189
198
|
}
|
|
190
199
|
|
|
200
|
+
// Remove from visited so sibling branches can reuse the same patterns
|
|
201
|
+
// without false circular-include detection. Only ancestors in the current
|
|
202
|
+
// recursion path should trigger the cycle guard.
|
|
203
|
+
visited.delete(patterns);
|
|
204
|
+
|
|
191
205
|
return {
|
|
192
206
|
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
193
207
|
fullPrefix: urlPrefix,
|
|
@@ -218,11 +232,20 @@ function captureAncestry(
|
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
/**
|
|
221
|
-
*
|
|
235
|
+
* Internal manifest result including build-pipeline-only fields.
|
|
236
|
+
* Not part of the public API — use generateManifest() for the public surface.
|
|
237
|
+
*/
|
|
238
|
+
export interface FullManifest extends GeneratedManifest {
|
|
239
|
+
_routeAncestry: Record<string, string[]>;
|
|
240
|
+
_prerenderDefs?: Record<string, any>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Generate manifest from UrlPatterns (public API).
|
|
222
245
|
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
246
|
+
* Returns only the public GeneratedManifest fields. Internal build pipeline
|
|
247
|
+
* consumers that need _routeAncestry or _prerenderDefs should use
|
|
248
|
+
* generateManifestFull() instead.
|
|
226
249
|
*
|
|
227
250
|
* @example
|
|
228
251
|
* ```typescript
|
|
@@ -240,7 +263,27 @@ function captureAncestry(
|
|
|
240
263
|
export function generateManifest<TEnv>(
|
|
241
264
|
urlpatterns: UrlPatterns<TEnv, any>,
|
|
242
265
|
mountIndex: number = 0,
|
|
243
|
-
): GeneratedManifest
|
|
266
|
+
): GeneratedManifest {
|
|
267
|
+
const {
|
|
268
|
+
_routeAncestry: _,
|
|
269
|
+
_prerenderDefs: __,
|
|
270
|
+
...publicManifest
|
|
271
|
+
} = generateManifestFull(urlpatterns, mountIndex);
|
|
272
|
+
return publicManifest;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Generate manifest with internal build-pipeline fields.
|
|
277
|
+
*
|
|
278
|
+
* Used by the Vite plugin (discover-routers via dynamic import through
|
|
279
|
+
* @rangojs/router/build), manifest-init (direct import), and trie
|
|
280
|
+
* building. Not intended for external use.
|
|
281
|
+
*/
|
|
282
|
+
export function generateManifestFull<TEnv>(
|
|
283
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
284
|
+
mountIndex: number = 0,
|
|
285
|
+
options?: { urlPrefix?: string },
|
|
286
|
+
): FullManifest {
|
|
244
287
|
const routeManifest: Record<string, string> = {};
|
|
245
288
|
const routeAncestry: Record<string, string[]> = {};
|
|
246
289
|
const prefixTree: Record<string, PrefixTreeNode> = {};
|
|
@@ -250,6 +293,7 @@ export function generateManifest<TEnv>(
|
|
|
250
293
|
const patternsMap = new Map<string, string>();
|
|
251
294
|
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
252
295
|
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
296
|
+
const searchSchemasMap = new Map<string, Record<string, string>>();
|
|
253
297
|
const trackedIncludes: TrackedInclude[] = [];
|
|
254
298
|
|
|
255
299
|
RSCRouterContext.run(
|
|
@@ -258,11 +302,14 @@ export function generateManifest<TEnv>(
|
|
|
258
302
|
patterns: patternsMap,
|
|
259
303
|
patternsByPrefix,
|
|
260
304
|
trailingSlash: trailingSlashMap,
|
|
305
|
+
searchSchemas: searchSchemasMap,
|
|
261
306
|
namespace: "build",
|
|
262
307
|
parent: null,
|
|
263
308
|
counters: {},
|
|
264
309
|
mountIndex,
|
|
265
310
|
trackedIncludes, // Enable include tracking
|
|
311
|
+
// basename sets the initial URL prefix for all path() registrations
|
|
312
|
+
...(options?.urlPrefix ? { urlPrefix: options.urlPrefix } : {}),
|
|
266
313
|
},
|
|
267
314
|
() => {
|
|
268
315
|
const helpers = createRouteHelpers();
|
|
@@ -270,7 +317,7 @@ export function generateManifest<TEnv>(
|
|
|
270
317
|
helpers.layout(MapRootLayout, () => {
|
|
271
318
|
return urlpatterns.handler() as AllUseItems[];
|
|
272
319
|
});
|
|
273
|
-
}
|
|
320
|
+
},
|
|
274
321
|
);
|
|
275
322
|
|
|
276
323
|
// Collect root-level routes and trailing slash config
|
|
@@ -281,6 +328,10 @@ export function generateManifest<TEnv>(
|
|
|
281
328
|
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
282
329
|
routeTrailingSlash[name] = mode;
|
|
283
330
|
}
|
|
331
|
+
const routeSearchSchemas: Record<string, Record<string, string>> = {};
|
|
332
|
+
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
333
|
+
routeSearchSchemas[name] = schema;
|
|
334
|
+
}
|
|
284
335
|
|
|
285
336
|
// Capture ancestry from manifest entries' parent chains
|
|
286
337
|
captureAncestry(manifest, routeAncestry);
|
|
@@ -296,7 +347,7 @@ export function generateManifest<TEnv>(
|
|
|
296
347
|
if (entry.prerenderDef) {
|
|
297
348
|
prerenderDefs[name] = entry.prerenderDef;
|
|
298
349
|
}
|
|
299
|
-
if (entry.
|
|
350
|
+
if (entry.isPassthrough === true) {
|
|
300
351
|
passthroughRoutes.push(name);
|
|
301
352
|
}
|
|
302
353
|
}
|
|
@@ -323,6 +374,7 @@ export function generateManifest<TEnv>(
|
|
|
323
374
|
prerenderDefs,
|
|
324
375
|
passthroughRoutes,
|
|
325
376
|
responseTypeRoutes,
|
|
377
|
+
routeSearchSchemas,
|
|
326
378
|
);
|
|
327
379
|
|
|
328
380
|
const existing = prefixTree[include.fullPrefix];
|
|
@@ -337,15 +389,25 @@ export function generateManifest<TEnv>(
|
|
|
337
389
|
return {
|
|
338
390
|
prefixTree,
|
|
339
391
|
routeManifest,
|
|
340
|
-
routeTrailingSlash:
|
|
392
|
+
routeTrailingSlash:
|
|
393
|
+
Object.keys(routeTrailingSlash).length > 0
|
|
394
|
+
? routeTrailingSlash
|
|
395
|
+
: undefined,
|
|
341
396
|
prerenderRoutes: prerenderRoutes.length > 0 ? prerenderRoutes : undefined,
|
|
342
|
-
passthroughRoutes:
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
397
|
+
passthroughRoutes:
|
|
398
|
+
passthroughRoutes.length > 0 ? passthroughRoutes : undefined,
|
|
399
|
+
responseTypeRoutes:
|
|
400
|
+
Object.keys(responseTypeRoutes).length > 0
|
|
401
|
+
? responseTypeRoutes
|
|
402
|
+
: undefined,
|
|
403
|
+
routeSearchSchemas:
|
|
404
|
+
Object.keys(routeSearchSchemas).length > 0
|
|
405
|
+
? routeSearchSchemas
|
|
406
|
+
: undefined,
|
|
346
407
|
_routeAncestry: routeAncestry,
|
|
347
408
|
// Internal: prerender handler definitions for build-time getParams() access
|
|
348
|
-
_prerenderDefs:
|
|
409
|
+
_prerenderDefs:
|
|
410
|
+
Object.keys(prerenderDefs).length > 0 ? prerenderDefs : undefined,
|
|
349
411
|
};
|
|
350
412
|
}
|
|
351
413
|
|
|
@@ -359,13 +421,12 @@ export function generateManifest<TEnv>(
|
|
|
359
421
|
* ```
|
|
360
422
|
*/
|
|
361
423
|
export function generateManifestCode<TEnv>(
|
|
362
|
-
urlpatterns: UrlPatterns<TEnv, any
|
|
424
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
363
425
|
): string {
|
|
364
426
|
const manifest = generateManifest(urlpatterns);
|
|
365
427
|
|
|
366
428
|
return `/**
|
|
367
429
|
* Auto-generated route manifest
|
|
368
|
-
* Generated at: ${manifest.generatedAt}
|
|
369
430
|
*
|
|
370
431
|
* DO NOT EDIT - This file is generated by @rangojs/router
|
|
371
432
|
*/
|